* [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry
@ 2025-02-14 5:16 NeilBrown
2025-02-14 5:16 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown
` (3 more replies)
0 siblings, 4 replies; 17+ messages in thread
From: NeilBrown @ 2025-02-14 5:16 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker
Cc: linux-nfs, linux-fsdevel, linux-kernel
This is a small set of patches which are needed before we can make the
locking on directory operations more fine grained. I think they are
useful even if we don't go that direction.
Some callers of vfs_mkdir() need to operation on the resulting directory
but cannot be guaranteed that the dentry will be hashed and positive on
success - another dentry might have been used.
This patch changes ->mkdir to return a dentry, changes NFS in particular
to return the correct dentry (I believe it is the only filesystem to
possibly not use the given dentry), and changes vfs_mkdir() to return
that dentry, removing the look that a few callers currently need.
I have not Cc: the developers of all the individual filesystems - only
NFS. I have build-tested all the changes except hostfs. I can email
them explicitly if/when this is otherwise acceptable. If anyone sees
this on fs-devel and wants to provide a pre-emptive ack I will collect
those and avoid further posting for those fs.
Thanks,
NeilBrown
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-14 5:16 [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry NeilBrown @ 2025-02-14 5:16 ` NeilBrown 2025-02-15 8:09 ` kernel test robot 2025-02-17 15:58 ` kernel test robot 2025-02-14 5:16 ` [PATCH 2/3] nfs: change mkdir inode_operation to return alternate dentry if needed NeilBrown ` (2 subsequent siblings) 3 siblings, 2 replies; 17+ messages in thread From: NeilBrown @ 2025-02-14 5:16 UTC (permalink / raw) To: Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: linux-nfs, linux-fsdevel, linux-kernel Some filesystems, such as NFS, do not have complete control of sequencing on the actual filesystem (e.g. on a different server) and may find that the inode created for a mkdir request already exists in the icache and dcache by the time the mkdir request returns. For example, if the filesystem is mounted twice the file could be visible on the other mount before it is on the original mount, and a pair of name_to_handle_at(), open_by_handle_at() could instantiate the directory inode with an IS_ROOT() dentry before the first mkdir returns. This means that the dentry passed to ->mkdir() may not be the one that is associated with the inode after the ->mkdir() completes. Some callers need to interact with the inode after the ->mkdir completes and they currently need to perform a lookup in the (rare) case that the dentry is no longer hashed. This lookup-after-mkdir requires that the directory remains locked to avoid races. Planned future patches to lock the dentry rather than the directory will mean that this lookup cannot be performed atomically with the mkdir. To remove this barrier, this patch changes ->mkdir to return the resulting dentry. With this patch the returned dentry is *always* the one passed in - or an ERR_PTR(). A future patch will change NFS - the only filesystem which handles this - to return that actual dentry used. Signed-off-by: NeilBrown <neilb@suse.de> --- Documentation/filesystems/locking.rst | 2 +- Documentation/filesystems/porting.rst | 11 +++++++++++ Documentation/filesystems/vfs.rst | 7 +++++-- fs/9p/vfs_inode.c | 10 ++++++---- fs/9p/vfs_inode_dotl.c | 11 +++++++---- fs/affs/affs.h | 2 +- fs/affs/namei.c | 8 ++++---- fs/afs/dir.c | 15 +++++++++------ fs/autofs/root.c | 14 +++++++------- fs/bad_inode.c | 6 +++--- fs/bcachefs/fs.c | 12 +++++++++--- fs/btrfs/inode.c | 14 ++++++++++---- fs/ceph/dir.c | 11 +++++++---- fs/coda/dir.c | 14 +++++++------- fs/configfs/dir.c | 9 ++++++--- fs/ecryptfs/inode.c | 9 ++++++--- fs/exfat/namei.c | 11 +++++++---- fs/ext2/namei.c | 12 ++++++++---- fs/ext4/namei.c | 13 ++++++++----- fs/f2fs/namei.c | 14 +++++++------- fs/fat/namei_msdos.c | 8 ++++---- fs/fat/namei_vfat.c | 8 ++++---- fs/fuse/dir.c | 12 +++++++++--- fs/gfs2/inode.c | 14 ++++++++++---- fs/hfs/dir.c | 10 +++++----- fs/hfsplus/dir.c | 13 ++++++++++--- fs/hostfs/hostfs_kern.c | 9 ++++++--- fs/hpfs/namei.c | 10 +++++----- fs/hugetlbfs/inode.c | 9 ++++++--- fs/jffs2/dir.c | 18 +++++++++--------- fs/jfs/namei.c | 11 +++++++---- fs/kernfs/dir.c | 15 +++++++++------ fs/minix/namei.c | 11 +++++++---- fs/namei.c | 12 +++++++++--- fs/nfs/dir.c | 8 ++++---- fs/nfs/internal.h | 4 ++-- fs/nilfs2/namei.c | 11 +++++++---- fs/ntfs3/namei.c | 14 ++++++++++---- fs/ocfs2/dlmfs/dlmfs.c | 14 ++++++++------ fs/ocfs2/namei.c | 13 ++++++++----- fs/omfs/dir.c | 13 ++++++++++--- fs/orangefs/namei.c | 11 +++++++---- fs/overlayfs/dir.c | 12 +++++++++--- fs/ramfs/inode.c | 10 ++++++---- fs/smb/client/cifsfs.h | 4 ++-- fs/smb/client/inode.c | 13 ++++++++----- fs/sysv/namei.c | 9 ++++++--- fs/tracefs/inode.c | 13 ++++++++----- fs/ubifs/dir.c | 10 +++++----- fs/udf/namei.c | 12 ++++++------ fs/ufs/namei.c | 8 ++++---- fs/vboxsf/dir.c | 14 ++++++++++---- fs/xfs/xfs_iops.c | 11 +++++++++-- include/linux/fs.h | 4 ++-- kernel/bpf/inode.c | 8 ++++---- mm/shmem.c | 8 ++++---- security/apparmor/apparmorfs.c | 11 +++++++---- 57 files changed, 375 insertions(+), 225 deletions(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index d20a32b77b60..0ec0bb6eb0fb 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -66,7 +66,7 @@ prototypes:: int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 1639e78e3146..3ef268591b66 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1157,3 +1157,14 @@ in normal case it points into the pathname being looked up. NOTE: if you need something like full path from the root of filesystem, you are still on your own - this assists with simple cases, but it's not magic. + +--- + +** mandatory** + +->mkdir() now returns a 'struct dentry *'. If the created inode is +found to already be in cache and have a dentry (often IS_ROOT), it will +need to be spliced into the given name in place of the given dentry. +That dentry now needs to be returned. If the original dentry is used, +it should be returned otherwise. Any error should be returned with +ERR_PTR(). diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 31eea688609a..0c10723f6513 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -495,7 +495,7 @@ As of kernel 2.6.22, the following members are defined: int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, @@ -562,7 +562,10 @@ otherwise noted. ``mkdir`` called by the mkdir(2) system call. Only required if you want to support creating subdirectories. You will probably need to - call d_instantiate() just as you would in the create() method + call d_instantiate() just as you would in the create() method. + If some dentry other than the one given is spliced in, then it + much be returned. In any case the final dentry of the directory + must be returned, or an ERR_PTR(). ``rmdir`` called by the rmdir(2) system call. Only required if you want diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 3e68521f4e2f..ef1bf2525611 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -669,8 +669,8 @@ v9fs_vfs_create(struct mnt_idmap *idmap, struct inode *dir, * */ -static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int err; u32 perm; @@ -692,8 +692,10 @@ static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (fid) p9_fid_put(fid); - - return err; + if (err) + return ERR_PTR(err); + else + return dentry; } /** diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 143ac03b7425..1f129aa697cc 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -350,9 +350,9 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, * */ -static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, - struct inode *dir, struct dentry *dentry, - umode_t omode) +static struct dentry *v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, + struct inode *dir, struct dentry *dentry, + umode_t omode) { int err; struct v9fs_session_info *v9ses; @@ -417,7 +417,10 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, p9_fid_put(fid); v9fs_put_acl(dacl, pacl); p9_fid_put(dfid); - return err; + if (err) + return ERR_PTR(err); + else + return dentry; } static int diff --git a/fs/affs/affs.h b/fs/affs/affs.h index e8c2c4535cb3..ac4e9a02910b 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -168,7 +168,7 @@ extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsi extern int affs_unlink(struct inode *dir, struct dentry *dentry); extern int affs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool); -extern int affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, +extern struct dentry *affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode); extern int affs_rmdir(struct inode *dir, struct dentry *dentry); extern int affs_link(struct dentry *olddentry, struct inode *dir, diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 8c154490a2d6..d924572f0dbc 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -273,7 +273,7 @@ affs_create(struct mnt_idmap *idmap, struct inode *dir, return 0; } -int +struct dentry * affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { @@ -285,7 +285,7 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, inode = affs_new_inode(dir); if (!inode) - return -ENOSPC; + return ERR_PTR(-ENOSPC); inode->i_mode = S_IFDIR | mode; affs_mode_to_prot(inode); @@ -298,9 +298,9 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, clear_nlink(inode); mark_inode_dirty(inode); iput(inode); - return error; + return ERR_PTR(error); } - return 0; + return dentry; } int diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 02cbf38e1a77..15c3cf09fa7e 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -33,8 +33,8 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nl loff_t fpos, u64 ino, unsigned dtype); static int afs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl); -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode); +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode); static int afs_rmdir(struct inode *dir, struct dentry *dentry); static int afs_unlink(struct inode *dir, struct dentry *dentry); static int afs_link(struct dentry *from, struct inode *dir, @@ -1315,8 +1315,8 @@ static const struct afs_operation_ops afs_mkdir_operation = { /* * create a directory on an AFS filesystem */ -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct afs_operation *op; struct afs_vnode *dvnode = AFS_FS_I(dir); @@ -1328,7 +1328,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { d_drop(dentry); - return PTR_ERR(op); + return ERR_CAST(op); } fscache_use_cookie(afs_vnode_cache(dvnode), true); @@ -1344,7 +1344,10 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, op->ops = &afs_mkdir_operation; ret = afs_do_sync_operation(op); afs_dir_unuse_cookie(dvnode, ret); - return ret; + if (ret) + return ERR_PTR(ret); + else + return dentry; } /* diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 530d18827e35..2b6a53f7aa82 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -15,8 +15,8 @@ static int autofs_dir_symlink(struct mnt_idmap *, struct inode *, struct dentry *, const char *); static int autofs_dir_unlink(struct inode *, struct dentry *); static int autofs_dir_rmdir(struct inode *, struct dentry *); -static int autofs_dir_mkdir(struct mnt_idmap *, struct inode *, - struct dentry *, umode_t); +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *, struct inode *, + struct dentry *, umode_t); static long autofs_root_ioctl(struct file *, unsigned int, unsigned long); #ifdef CONFIG_COMPAT static long autofs_root_compat_ioctl(struct file *, @@ -720,9 +720,9 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry) return 0; } -static int autofs_dir_mkdir(struct mnt_idmap *idmap, - struct inode *dir, struct dentry *dentry, - umode_t mode) +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *idmap, + struct inode *dir, struct dentry *dentry, + umode_t mode) { struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); struct autofs_info *ino = autofs_dentry_ino(dentry); @@ -739,7 +739,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, inode = autofs_get_inode(dir->i_sb, S_IFDIR | mode); if (!inode) - return -ENOMEM; + return ERR_PTR(-ENOMEM); d_add(dentry, inode); if (sbi->version < 5) @@ -751,7 +751,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, inc_nlink(dir); inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); - return 0; + return dentry; } /* Get/set timeout ioctl() operation */ diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 316d88da2ce1..0ef9bcb744dd 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -58,10 +58,10 @@ static int bad_inode_symlink(struct mnt_idmap *idmap, return -EIO; } -static int bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return -EIO; + return ERR_PTR(-EIO); } static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 90ade8f648d9..1c7ea982a499 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -858,10 +858,16 @@ static int bch2_symlink(struct mnt_idmap *idmap, return bch2_err_class(ret); } -static int bch2_mkdir(struct mnt_idmap *idmap, - struct inode *vdir, struct dentry *dentry, umode_t mode) +static struct dentry *bch2_mkdir(struct mnt_idmap *idmap, + struct inode *vdir, struct dentry *dentry, umode_t mode) { - return bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0); + int err = bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0); + + if (err) + return ERR_PTR(err); + else + return dentry; + } static int bch2_rename2(struct mnt_idmap *idmap, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a9322601ab5c..ceaac826355a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6739,18 +6739,24 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, return err; } -static int btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; + int err; inode = new_inode(dir->i_sb); if (!inode) - return -ENOMEM; + return ERR_PTR(-ENOMEM); inode_init_owner(idmap, inode, dir, S_IFDIR | mode); inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; - return btrfs_create_common(dir, dentry, inode); + err = btrfs_create_common(dir, dentry, inode); + if (err) + return ERR_PTR(err); + else + return dentry; + } static noinline int uncompress_inline(struct btrfs_path *path, diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 62e99e65250d..efca19a381de 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1092,8 +1092,8 @@ static int ceph_symlink(struct mnt_idmap *idmap, struct inode *dir, return err; } -static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb); struct ceph_client *cl = mdsc->fsc->client; @@ -1104,7 +1104,7 @@ static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, err = ceph_wait_on_conflict_unlink(dentry); if (err) - return err; + return ERR_PTR(err); if (ceph_snap(dir) == CEPH_SNAPDIR) { /* mkdir .snap/foo is a MKSNAP */ @@ -1173,7 +1173,10 @@ static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, else d_drop(dentry); ceph_release_acl_sec_ctx(&as_ctx); - return err; + if (err) + return ERR_PTR(err); + else + return dentry; } static int ceph_link(struct dentry *old_dentry, struct inode *dir, diff --git a/fs/coda/dir.c b/fs/coda/dir.c index a3e2dfeedfbf..1f95f42e789c 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -166,8 +166,8 @@ static int coda_create(struct mnt_idmap *idmap, struct inode *dir, return error; } -static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *de, umode_t mode) +static struct dentry *coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *de, umode_t mode) { struct inode *inode; struct coda_vattr attrs; @@ -177,14 +177,14 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct CodaFid newfid; if (is_root_inode(dir) && coda_iscontrol(name, len)) - return -EPERM; + return ERR_PTR(-EPERM); attrs.va_mode = mode; - error = venus_mkdir(dir->i_sb, coda_i2f(dir), + error = venus_mkdir(dir->i_sb, coda_i2f(dir), name, len, &newfid, &attrs); if (error) goto err_out; - + inode = coda_iget(dir->i_sb, &newfid, &attrs); if (IS_ERR(inode)) { error = PTR_ERR(inode); @@ -195,10 +195,10 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, coda_dir_inc_nlink(dir); coda_dir_update_mtime(dir); d_instantiate(de, inode); - return 0; + return de; err_out: d_drop(de); - return error; + return ERR_PTR(error); } /* try to make de an entry in dir_inodde linked to source_de */ diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 7d10278db30d..bae8304d9246 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1280,8 +1280,8 @@ int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys, } EXPORT_SYMBOL(configfs_depend_item_unlocked); -static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int ret = 0; int module_got = 0; @@ -1461,7 +1461,10 @@ static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, put_fragment(frag); out: - return ret; + if (ret) + return ERR_PTR(ret); + else + return dentry; } static int configfs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a9819ddb1ab8..7445c32c1e95 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -503,8 +503,8 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap, return rc; } -static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int rc; struct dentry *lower_dentry; @@ -526,7 +526,10 @@ static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, inode_unlock(lower_dir); if (d_really_is_negative(dentry)) d_drop(dentry); - return rc; + if (rc) + return ERR_PTR(rc); + else + return dentry; } static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index 691dd77b6ab5..ec880735846f 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -835,8 +835,8 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) return err; } -static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -846,7 +846,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, loff_t size = i_size_read(dir); if (unlikely(exfat_forced_shutdown(sb))) - return -EIO; + return ERR_PTR(-EIO); mutex_lock(&EXFAT_SB(sb)->s_lock); exfat_set_volume_dirty(sb); @@ -877,7 +877,10 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, unlock: mutex_unlock(&EXFAT_SB(sb)->s_lock); - return err; + if (err) + return ERR_PTR(err); + else + return dentry; } static int exfat_check_dir_empty(struct super_block *sb, diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 8346ab9534c1..4c7295746f2b 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -225,15 +225,16 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, return err; } -static int ext2_mkdir(struct mnt_idmap * idmap, - struct inode * dir, struct dentry * dentry, umode_t mode) +static struct dentry *ext2_mkdir(struct mnt_idmap * idmap, + struct inode * dir, struct dentry * dentry, + umode_t mode) { struct inode * inode; int err; err = dquot_initialize(dir); if (err) - return err; + return ERR_PTR(err); inode_inc_link_count(dir); @@ -258,7 +259,10 @@ static int ext2_mkdir(struct mnt_idmap * idmap, d_instantiate_new(dentry, inode); out: - return err; + if (err) + return ERR_PTR(err); + else + return dentry; out_fail: inode_dec_link_count(inode); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 536d56d15072..6da7935cfd4a 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3004,19 +3004,19 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, return err; } -static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { handle_t *handle; struct inode *inode; int err, err2 = 0, credits, retries = 0; if (EXT4_DIR_LINK_MAX(dir)) - return -EMLINK; + return ERR_PTR(-EMLINK); err = dquot_initialize(dir); if (err) - return err; + return ERR_PTR(err); credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); @@ -3066,7 +3066,10 @@ static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, out_retry: if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; - return err; + if (err) + return ERR_PTR(err); + else + return dentry; } /* diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a278c7da8177..5c0409c5385b 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -684,23 +684,23 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir, return err; } -static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err; if (unlikely(f2fs_cp_error(sbi))) - return -EIO; + return ERR_PTR(-EIO); err = f2fs_dquot_initialize(dir); if (err) - return err; + return ERR_PTR(err); inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; @@ -722,12 +722,12 @@ static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, f2fs_sync_fs(sbi->sb, 1); f2fs_balance_fs(sbi, true); - return 0; + return dentry; out_fail: clear_inode_flag(inode, FI_INC_LINK); f2fs_handle_failed_inode(inode); - return err; + return ERR_PTR(err); } static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index f06f6ba643cc..2ae5b5a69d68 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -339,8 +339,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) } /***** Make a directory */ -static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; @@ -389,13 +389,13 @@ static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, mutex_unlock(&MSDOS_SB(sb)->s_lock); fat_flush_inodes(sb, dir, inode); - return 0; + return dentry; out_free: fat_free_clusters(dir, cluster); out: mutex_unlock(&MSDOS_SB(sb)->s_lock); - return err; + return ERR_PTR(err); } /***** Unlink a file */ diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 926c26e90ef8..8a32cb9ced12 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -841,8 +841,8 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) return err; } -static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -877,13 +877,13 @@ static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); mutex_unlock(&MSDOS_SB(sb)->s_lock); - return 0; + return dentry; out_free: fat_free_clusters(dir, cluster); out: mutex_unlock(&MSDOS_SB(sb)->s_lock); - return err; + return ERR_PTR(err); } static int vfat_get_dotdot_de(struct inode *inode, struct buffer_head **bh, diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 198862b086ff..cf6ac3e37c82 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -898,11 +898,12 @@ static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir, return err; } -static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *entry, umode_t mode) +static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *entry, umode_t mode) { struct fuse_mkdir_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); + int err; FUSE_ARGS(args); if (!fm->fc->dont_mask) @@ -917,7 +918,12 @@ static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, args.in_args[0].value = &inarg; args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; - return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); + err = create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); + if (err) + return ERR_PTR(err); + else + return entry; + } static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6fbbaaad1cd0..e48a9eece720 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1248,14 +1248,20 @@ static int gfs2_symlink(struct mnt_idmap *idmap, struct inode *dir, * @dentry: The dentry of the new directory * @mode: The mode of the new directory * - * Returns: errno + * Returns: the dentry, or ERR_PTR(errno) */ -static int gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { unsigned dsize = gfs2_max_stuffed_size(GFS2_I(dir)); - return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0); + int err; + + err = gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0); + if (err) + return ERR_PTR(err); + else + return dentry; } /** diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index b75c26045df4..3d835e7cbfe0 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -219,26 +219,26 @@ static int hfs_create(struct mnt_idmap *idmap, struct inode *dir, * in a directory, given the inode for the parent directory and the * name (and its length) of the new directory. */ -static int hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; int res; inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); if (!inode) - return -ENOMEM; + return ERR_PTR(-ENOMEM); res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); if (res) { clear_nlink(inode); hfs_delete_inode(inode); iput(inode); - return res; + return ERR_PTR(res); } d_instantiate(dentry, inode); mark_inode_dirty(inode); - return 0; + return dentry; } /* diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f5c4b3e31a1c..96836afbb4f5 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -523,10 +523,17 @@ static int hfsplus_create(struct mnt_idmap *idmap, struct inode *dir, return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode, 0); } -static int hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); + int err; + + err = hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); + if (err) + return ERR_PTR(err); + else + return dentry; + } static int hfsplus_rename(struct mnt_idmap *idmap, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index e0741e468956..6caccd4f673f 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -679,8 +679,8 @@ static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino, return err; } -static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, - struct dentry *dentry, umode_t mode) +static struct dentry *hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, + struct dentry *dentry, umode_t mode) { char *file; int err; @@ -689,7 +689,10 @@ static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, return -ENOMEM; err = do_mkdir(file, mode); __putname(file); - return err; + if (err) + return ERR_PTR(err); + else + return dentry; } static int hostfs_rmdir(struct inode *ino, struct dentry *dentry) diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index d0edf9ed33b6..9234e405df64 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -19,8 +19,8 @@ static void hpfs_update_directory_times(struct inode *dir) hpfs_write_inode_nolock(dir); } -static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; @@ -35,7 +35,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, int r; struct hpfs_dirent dee; int err; - if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; + if ((err = hpfs_chk_name(name, &len))) return ERR_PTR(err==-ENOENT ? -EINVAL : err); hpfs_lock(dir->i_sb); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); @@ -112,7 +112,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); - return 0; + return dentry; bail3: iput(result); bail2: @@ -123,7 +123,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); - return err; + return ERR_PTR(err); } static int hpfs_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0fc179a59830..b6066bcb0f64 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -991,14 +991,17 @@ static int hugetlbfs_mknod(struct mnt_idmap *idmap, struct inode *dir, return 0; } -static int hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int retval = hugetlbfs_mknod(idmap, dir, dentry, mode | S_IFDIR, 0); if (!retval) inc_nlink(dir); - return retval; + if (retval) + return ERR_PTR(retval); + else + return dentry; } static int hugetlbfs_create(struct mnt_idmap *idmap, diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 2b2938970da3..0d3cf10e7237 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -32,8 +32,8 @@ static int jffs2_link (struct dentry *,struct inode *,struct dentry *); static int jffs2_unlink (struct inode *,struct dentry *); static int jffs2_symlink (struct mnt_idmap *, struct inode *, struct dentry *, const char *); -static int jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, - umode_t); +static struct dentry *jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, + umode_t); static int jffs2_rmdir (struct inode *,struct dentry *); static int jffs2_mknod (struct mnt_idmap *, struct inode *,struct dentry *, umode_t,dev_t); @@ -446,8 +446,8 @@ static int jffs2_symlink (struct mnt_idmap *idmap, struct inode *dir_i, } -static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, - struct dentry *dentry, umode_t mode) +static struct dentry *jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, + struct dentry *dentry, umode_t mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -464,7 +464,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, ri = jffs2_alloc_raw_inode(); if (!ri) - return -ENOMEM; + return ERR_PTR(-ENOMEM); c = JFFS2_SB_INFO(dir_i->i_sb); @@ -477,7 +477,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, if (ret) { jffs2_free_raw_inode(ri); - return ret; + return ERR_PTR(ret); } inode = jffs2_new_inode(dir_i, mode, ri); @@ -485,7 +485,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); - return PTR_ERR(inode); + return ERR_CAST(inode); } inode->i_op = &jffs2_dir_inode_operations; @@ -584,11 +584,11 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, jffs2_complete_reservation(c); d_instantiate_new(dentry, inode); - return 0; + return dentry; fail: iget_failed(inode); - return ret; + return ERR_PTR(ret); } static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index fc8ede43afde..922a23c6179f 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -187,13 +187,13 @@ static int jfs_create(struct mnt_idmap *idmap, struct inode *dip, * dentry - dentry of child directory * mode - create mode (rwxrwxrwx). * - * RETURN: Errors from subroutines + * RETURN: The dentry or ERR_PTR() of errors from subroutines * * note: * EACCES: user needs search+write permission on the parent directory */ -static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, - struct dentry *dentry, umode_t mode) +static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, + struct dentry *dentry, umode_t mode) { int rc = 0; tid_t tid; /* transaction id */ @@ -308,7 +308,10 @@ static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, out1: jfs_info("jfs_mkdir: rc:%d", rc); - return rc; + if (rc) + return ERR_PTR(rc); + else + return dentry; } /* diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 5f0f8b95f44c..1b112c84ff03 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1230,24 +1230,27 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, return d_splice_alias(inode, dentry); } -static int kernfs_iop_mkdir(struct mnt_idmap *idmap, - struct inode *dir, struct dentry *dentry, - umode_t mode) +static struct dentry *kernfs_iop_mkdir(struct mnt_idmap *idmap, + struct inode *dir, struct dentry *dentry, + umode_t mode) { struct kernfs_node *parent = dir->i_private; struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops; int ret; if (!scops || !scops->mkdir) - return -EPERM; + return ERR_PTR(-EPERM); if (!kernfs_get_active(parent)) - return -ENODEV; + return ERR_PTR(-ENODEV); ret = scops->mkdir(parent, dentry->d_name.name, mode); kernfs_put_active(parent); - return ret; + if (ret) + return ERR_PTR(ret); + else + return dentry; } static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 5d9c1406fe27..0fc29a3ed049 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -104,15 +104,15 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, return add_nondir(dentry, inode); } -static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode * inode; int err; inode = minix_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); inode_inc_link_count(dir); minix_set_inode(inode, 0); @@ -128,7 +128,10 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); out: - return err; + if (err) + return ERR_PTR(err); + else + return dentry; out_fail: inode_dec_link_count(inode); diff --git a/fs/namei.c b/fs/namei.c index 6659e3be52ce..6094d93ed7d3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4291,6 +4291,7 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, { int error; unsigned max_links = dir->i_sb->s_max_links; + struct dentry *de; error = may_create(idmap, dir, dentry); if (error) @@ -4307,9 +4308,14 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (max_links && dir->i_nlink >= max_links) return -EMLINK; - error = dir->i_op->mkdir(idmap, dir, dentry, mode); - if (!error) - fsnotify_mkdir(dir, dentry); + de = dir->i_op->mkdir(idmap, dir, dentry, mode); + error = PTR_ERR_OR_ZERO(de); + if (!error) { + fsnotify_mkdir(dir, de); + if (de != dentry) + /* Cannot return de yet */ + dput(de); + } return error; } EXPORT_SYMBOL(vfs_mkdir); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 56cf16a72334..1bf728367426 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2422,8 +2422,8 @@ EXPORT_SYMBOL_GPL(nfs_mknod); /* * See comments for nfs_proc_create regarding failed operations. */ -int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct iattr attr; int error; @@ -2439,10 +2439,10 @@ int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, trace_nfs_mkdir_exit(dir, dentry, error); if (error != 0) goto out_err; - return 0; + return dentry; out_err: d_drop(dentry); - return error; + return ERR_PTR(error); } EXPORT_SYMBOL_GPL(nfs_mkdir); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index fae2c7ae4acc..1ac1d3eec517 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -400,8 +400,8 @@ struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); void nfs_d_prune_case_insensitive_aliases(struct inode *inode); int nfs_create(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, bool); -int nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, - umode_t); +struct dentry *nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, + umode_t); int nfs_rmdir(struct inode *, struct dentry *); int nfs_unlink(struct inode *, struct dentry *); int nfs_symlink(struct mnt_idmap *, struct inode *, struct dentry *, diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 953fbd5f0851..c86df905948b 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -218,8 +218,8 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, return err; } -static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct nilfs_transaction_info ti; @@ -227,7 +227,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, err = nilfs_transaction_begin(dir->i_sb, &ti, 1); if (err) - return err; + return ERR_PTR(err); inc_nlink(dir); @@ -258,7 +258,10 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, else nilfs_transaction_abort(dir->i_sb); - return err; + if (err) + return ERR_PTR(err); + else + return dentry; out_fail: drop_nlink(inode); diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index abf7e81584a9..dcf33098e278 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -201,11 +201,17 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, /* * ntfs_mkdir- inode_operations::mkdir */ -static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, - NULL, 0, NULL); + int err; + + err = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, + NULL, 0, NULL); + if (err) + return ERR_PTR(err); + else + return dentry; } /* diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 2a7f36643895..370480c258a3 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -402,10 +402,10 @@ static struct inode *dlmfs_get_inode(struct inode *parent, * File creation. Allocate an inode, and we're done.. */ /* SMP-safe */ -static int dlmfs_mkdir(struct mnt_idmap * idmap, - struct inode * dir, - struct dentry * dentry, - umode_t mode) +static struct dentry *dlmfs_mkdir(struct mnt_idmap * idmap, + struct inode * dir, + struct dentry * dentry, + umode_t mode) { int status; struct inode *inode = NULL; @@ -446,9 +446,11 @@ static int dlmfs_mkdir(struct mnt_idmap * idmap, status = 0; bail: - if (status < 0) + if (status < 0) { iput(inode); - return status; + return ERR_PTR(status); + } + return dentry; } static int dlmfs_create(struct mnt_idmap *idmap, diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 0ec63a1a94b8..819da0cc780d 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -644,10 +644,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, suballoc_loc, suballoc_bit); } -static int ocfs2_mkdir(struct mnt_idmap *idmap, - struct inode *dir, - struct dentry *dentry, - umode_t mode) +static struct dentry *ocfs2_mkdir(struct mnt_idmap *idmap, + struct inode *dir, + struct dentry *dentry, + umode_t mode) { int ret; @@ -657,7 +657,10 @@ static int ocfs2_mkdir(struct mnt_idmap *idmap, if (ret) mlog_errno(ret); - return ret; + if (ret) + return ERR_PTR(ret); + else + return dentry; } static int ocfs2_create(struct mnt_idmap *idmap, diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index 6bda275826d6..0e1c53bb948d 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c @@ -279,10 +279,17 @@ static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) return err; } -static int omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return omfs_add_node(dir, dentry, mode | S_IFDIR); + int err; + + err = omfs_add_node(dir, dentry, mode | S_IFDIR); + if (err) + return ERR_PTR(err); + else + return dentry; + } static int omfs_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 200558ec72f0..7be2c17a749b 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -300,8 +300,8 @@ static int orangefs_symlink(struct mnt_idmap *idmap, return ret; } -static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct orangefs_inode_s *parent = ORANGEFS_I(dir); struct orangefs_kernel_op_s *new_op; @@ -312,7 +312,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR); if (!new_op) - return -ENOMEM; + return ERR_PTR(-ENOMEM); new_op->upcall.req.mkdir.parent_refn = parent->refn; @@ -366,7 +366,10 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, __orangefs_setattr(dir, &iattr); out: op_release(new_op); - return ret; + if (ret) + return ERR_PTR(ret); + else + return dentry; } static int orangefs_rename(struct mnt_idmap *idmap, diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index c9993ff66fc2..74a0541a8619 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -687,10 +687,16 @@ static int ovl_create(struct mnt_idmap *idmap, struct inode *dir, return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); } -static int ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); + int err; + + err = ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); + if (err) + return ERR_PTR(err); + else + return dentry; } static int ovl_mknod(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 8006faaaf0ec..d285152ca0af 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -119,13 +119,15 @@ ramfs_mknod(struct mnt_idmap *idmap, struct inode *dir, return error; } -static int ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int retval = ramfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); - if (!retval) + if (!retval) { inc_nlink(dir); - return retval; + return dentry; + } else + return ERR_PTR(retval); } static int ramfs_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 831fee962c4d..8dea0cf3a8de 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -59,8 +59,8 @@ extern int cifs_unlink(struct inode *dir, struct dentry *dentry); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); extern int cifs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, dev_t); -extern int cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, - umode_t); +extern struct dentry *cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, + umode_t); extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rename2(struct mnt_idmap *, struct inode *, struct dentry *, struct inode *, struct dentry *, diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 9cc31cf6ebd0..5c7d7563fd7a 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -2194,8 +2194,8 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, - struct dentry *direntry, umode_t mode) +struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, + struct dentry *direntry, umode_t mode) { int rc = 0; unsigned int xid; @@ -2211,10 +2211,10 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, cifs_sb = CIFS_SB(inode->i_sb); if (unlikely(cifs_forced_shutdown(cifs_sb))) - return -EIO; + return ERR_PTR(-EIO); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) - return PTR_ERR(tlink); + return ERR_CAST(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); @@ -2270,7 +2270,10 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); - return rc; + if (rc) + return ERR_PTR(rc); + else + return direntry; } int cifs_rmdir(struct inode *inode, struct dentry *direntry) diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index fb8bd8437872..8132f6835e7b 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -110,8 +110,8 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, return add_nondir(dentry, inode); } -static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode * inode; int err; @@ -137,7 +137,10 @@ static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); out: - return err; + if (err) + return ERR_PTR(err); + else + return dentry; out_fail: inode_dec_link_count(inode); diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 53214499e384..5e946db59611 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -109,9 +109,9 @@ static char *get_dname(struct dentry *dentry) return name; } -static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, - struct inode *inode, struct dentry *dentry, - umode_t mode) +static struct dentry *tracefs_syscall_mkdir(struct mnt_idmap *idmap, + struct inode *inode, struct dentry *dentry, + umode_t mode) { struct tracefs_inode *ti; char *name; @@ -119,7 +119,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, name = get_dname(dentry); if (!name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); /* * This is a new directory that does not take the default of @@ -141,7 +141,10 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, kfree(name); - return ret; + if (ret) + return ERR_PTR(ret); + else + return dentry; } static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index fda82f3e16e8..b960cb0dec1a 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1002,8 +1002,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) return err; } -static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); @@ -1023,7 +1023,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, err = ubifs_budget_space(c, &req); if (err) - return err; + return ERR_PTR(err); err = ubifs_prepare_create(dir, dentry, &nm); if (err) @@ -1060,7 +1060,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, ubifs_release_budget(c, &req); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); - return 0; + return dentry; out_cancel: dir->i_size -= sz_change; @@ -1074,7 +1074,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); - return err; + return ERR_PTR(err); } static int ubifs_mknod(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 2cb49b6b0716..4916a6bba5fe 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -419,8 +419,8 @@ static int udf_mknod(struct mnt_idmap *idmap, struct inode *dir, return udf_add_nondir(dentry, inode); } -static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct udf_fileident_iter iter; @@ -430,7 +430,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, inode = udf_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); iinfo = UDF_I(inode); inode->i_op = &udf_dir_inode_operations; @@ -439,7 +439,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (err) { clear_nlink(inode); discard_new_inode(inode); - return err; + return ERR_PTR(err); } set_nlink(inode, 2); iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -456,7 +456,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (err) { clear_nlink(inode); discard_new_inode(inode); - return err; + return ERR_PTR(err); } iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location); @@ -471,7 +471,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, mark_inode_dirty(dir); d_instantiate_new(dentry, inode); - return 0; + return dentry; } static int empty_dir(struct inode *dir) diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 38a024c8cccd..f64a40e00528 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -166,8 +166,8 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, return error; } -static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, - struct dentry * dentry, umode_t mode) +static struct dentry *ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, + struct dentry * dentry, umode_t mode) { struct inode * inode; int err; @@ -194,7 +194,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, goto out_fail; d_instantiate_new(dentry, inode); - return 0; + return dentry; out_fail: inode_dec_link_count(inode); @@ -202,7 +202,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, discard_new_inode(inode); out_dir: inode_dec_link_count(dir); - return err; + return ERR_PTR(err); } static int ufs_unlink(struct inode *dir, struct dentry *dentry) diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c index a859ac9b74ba..57bc2557182c 100644 --- a/fs/vboxsf/dir.c +++ b/fs/vboxsf/dir.c @@ -303,11 +303,17 @@ static int vboxsf_dir_mkfile(struct mnt_idmap *idmap, return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL); } -static int vboxsf_dir_mkdir(struct mnt_idmap *idmap, - struct inode *parent, struct dentry *dentry, - umode_t mode) +static struct dentry *vboxsf_dir_mkdir(struct mnt_idmap *idmap, + struct inode *parent, struct dentry *dentry, + umode_t mode) { - return vboxsf_dir_create(parent, dentry, mode, true, true, NULL); + int err; + + err = vboxsf_dir_create(parent, dentry, mode, true, true, NULL); + if (err) + return ERR_PTR(err); + else + return dentry; } static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry, diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 40289fe6f5b2..b93283f0a7af 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -298,14 +298,21 @@ xfs_vn_create( return xfs_generic_create(idmap, dir, dentry, mode, 0, NULL); } -STATIC int +STATIC struct dentry * xfs_vn_mkdir( struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { - return xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL); + int err; + + err = xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL); + if (err) + return ERR_PTR(err); + else + return dentry; + } STATIC struct dentry * diff --git a/include/linux/fs.h b/include/linux/fs.h index be3ad155ec9f..67eb77f75b40 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2199,8 +2199,8 @@ struct inode_operations { int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *, const char *); - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *, - umode_t); + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *, + struct dentry *, umode_t); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *, umode_t,dev_t); diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 9aaf5124648b..7decda734c68 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -150,14 +150,14 @@ static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode, inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); } -static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; inode = bpf_get_inode(dir->i_sb, dir, mode | S_IFDIR); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); inode->i_op = &bpf_dir_iops; inode->i_fop = &simple_dir_operations; @@ -166,7 +166,7 @@ static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, inc_nlink(dir); bpf_dentry_finalize(dentry, inode, dir); - return 0; + return dentry; } struct map_iter { diff --git a/mm/shmem.c b/mm/shmem.c index 4ea6109a8043..18f0450690aa 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3889,16 +3889,16 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir, return error; } -static int shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int error; error = shmem_mknod(idmap, dir, dentry, mode | S_IFDIR, 0); if (error) - return error; + return ERR_PTR(error); inc_nlink(dir); - return 0; + return dentry; } static int shmem_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index c07d150685d7..13b8829079a1 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1795,8 +1795,8 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) return error; } -static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct aa_ns *ns, *parent; /* TODO: improve permission check */ @@ -1808,7 +1808,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, AA_MAY_LOAD_POLICY); end_current_label_crit_section(label); if (error) - return error; + return ERR_PTR(error); parent = aa_get_ns(dir->i_private); AA_BUG(d_inode(ns_subns_dir(parent)) != dir); @@ -1843,7 +1843,10 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, mutex_unlock(&parent->lock); aa_put_ns(parent); - return error; + if (error) + return ERR_PTR(error); + else + return dentry; } static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) -- 2.47.1 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-14 5:16 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown @ 2025-02-15 8:09 ` kernel test robot 2025-02-17 15:58 ` kernel test robot 1 sibling, 0 replies; 17+ messages in thread From: kernel test robot @ 2025-02-15 8:09 UTC (permalink / raw) To: NeilBrown, Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: llvm, oe-kbuild-all, linux-nfs, linux-fsdevel, linux-kernel Hi NeilBrown, kernel test robot noticed the following build errors: [auto build test ERROR on brauner-vfs/vfs.all] [also build test ERROR on trondmy-nfs/linux-next driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus cifs/for-next xfs-linux/for-next linus/master v6.14-rc2 next-20250214] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/NeilBrown/nfs-change-mkdir-inode_operation-to-return-alternate-dentry-if-needed/20250214-141741 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250214052204.3105610-2-neilb%40suse.de patch subject: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * config: um-randconfig-001-20250215 (https://download.01.org/0day-ci/archive/20250215/202502151519.0MA7hz8D-lkp@intel.com/config) compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project 910be4ff90d7d07bd4518ea03b85c0974672bf9c) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250215/202502151519.0MA7hz8D-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202502151519.0MA7hz8D-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from fs/hostfs/hostfs_kern.c:13: In file included from include/linux/pagemap.h:11: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:549:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 549 | val = __raw_readb(PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:567:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 567 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu' 37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) | ^ In file included from fs/hostfs/hostfs_kern.c:13: In file included from include/linux/pagemap.h:11: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:585:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 585 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu' 35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) | ^ In file included from fs/hostfs/hostfs_kern.c:13: In file included from include/linux/pagemap.h:11: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:601:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 601 | __raw_writeb(value, PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:616:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 616 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:631:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 631 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:724:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 724 | readsb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:737:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 737 | readsw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:750:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 750 | readsl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:764:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 764 | writesb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:778:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 778 | writesw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:792:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 792 | writesl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ >> fs/hostfs/hostfs_kern.c:689:10: error: incompatible integer to pointer conversion returning 'int' from a function with result type 'struct dentry *' [-Wint-conversion] 689 | return -ENOMEM; | ^~~~~~~ 12 warnings and 1 error generated. vim +689 fs/hostfs/hostfs_kern.c ^1da177e4c3f41 Linus Torvalds 2005-04-16 681 456289e0bd14ce NeilBrown 2025-02-14 682 static struct dentry *hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, 549c7297717c32 Christian Brauner 2021-01-21 683 struct dentry *dentry, umode_t mode) ^1da177e4c3f41 Linus Torvalds 2005-04-16 684 { ^1da177e4c3f41 Linus Torvalds 2005-04-16 685 char *file; ^1da177e4c3f41 Linus Torvalds 2005-04-16 686 int err; ^1da177e4c3f41 Linus Torvalds 2005-04-16 687 c5322220eb91b9 Al Viro 2010-06-06 688 if ((file = dentry_name(dentry)) == NULL) f1adc05e773830 Jeff Dike 2007-05-08 @689 return -ENOMEM; ^1da177e4c3f41 Linus Torvalds 2005-04-16 690 err = do_mkdir(file, mode); e9193059b1b373 Al Viro 2010-06-06 691 __putname(file); 456289e0bd14ce NeilBrown 2025-02-14 692 if (err) 456289e0bd14ce NeilBrown 2025-02-14 693 return ERR_PTR(err); 456289e0bd14ce NeilBrown 2025-02-14 694 else 456289e0bd14ce NeilBrown 2025-02-14 695 return dentry; ^1da177e4c3f41 Linus Torvalds 2005-04-16 696 } ^1da177e4c3f41 Linus Torvalds 2005-04-16 697 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-14 5:16 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 2025-02-15 8:09 ` kernel test robot @ 2025-02-17 15:58 ` kernel test robot 1 sibling, 0 replies; 17+ messages in thread From: kernel test robot @ 2025-02-17 15:58 UTC (permalink / raw) To: NeilBrown, Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: oe-kbuild-all, linux-nfs, linux-fsdevel, linux-kernel Hi NeilBrown, kernel test robot noticed the following build warnings: [auto build test WARNING on brauner-vfs/vfs.all] [also build test WARNING on trondmy-nfs/linux-next driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus cifs/for-next xfs-linux/for-next linus/master v6.14-rc3 next-20250217] [cannot apply to ericvh-v9fs/for-next tyhicks-ecryptfs/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/NeilBrown/nfs-change-mkdir-inode_operation-to-return-alternate-dentry-if-needed/20250214-141741 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250214052204.3105610-2-neilb%40suse.de patch subject: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * config: um-randconfig-r122-20250217 (https://download.01.org/0day-ci/archive/20250217/202502172326.hdZnGqWS-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250217/202502172326.hdZnGqWS-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202502172326.hdZnGqWS-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) >> fs/hostfs/hostfs_kern.c:689:24: sparse: sparse: incorrect type in return expression (different base types) @@ expected struct dentry * @@ got int @@ fs/hostfs/hostfs_kern.c:689:24: sparse: expected struct dentry * fs/hostfs/hostfs_kern.c:689:24: sparse: got int vim +689 fs/hostfs/hostfs_kern.c ^1da177e4c3f41 Linus Torvalds 2005-04-16 681 456289e0bd14ce NeilBrown 2025-02-14 682 static struct dentry *hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, 549c7297717c32 Christian Brauner 2021-01-21 683 struct dentry *dentry, umode_t mode) ^1da177e4c3f41 Linus Torvalds 2005-04-16 684 { ^1da177e4c3f41 Linus Torvalds 2005-04-16 685 char *file; ^1da177e4c3f41 Linus Torvalds 2005-04-16 686 int err; ^1da177e4c3f41 Linus Torvalds 2005-04-16 687 c5322220eb91b9 Al Viro 2010-06-06 688 if ((file = dentry_name(dentry)) == NULL) f1adc05e773830 Jeff Dike 2007-05-08 @689 return -ENOMEM; ^1da177e4c3f41 Linus Torvalds 2005-04-16 690 err = do_mkdir(file, mode); e9193059b1b373 Al Viro 2010-06-06 691 __putname(file); 456289e0bd14ce NeilBrown 2025-02-14 692 if (err) 456289e0bd14ce NeilBrown 2025-02-14 693 return ERR_PTR(err); 456289e0bd14ce NeilBrown 2025-02-14 694 else 456289e0bd14ce NeilBrown 2025-02-14 695 return dentry; ^1da177e4c3f41 Linus Torvalds 2005-04-16 696 } ^1da177e4c3f41 Linus Torvalds 2005-04-16 697 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/3] nfs: change mkdir inode_operation to return alternate dentry if needed. 2025-02-14 5:16 [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry NeilBrown 2025-02-14 5:16 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown @ 2025-02-14 5:16 ` NeilBrown 2025-02-14 5:16 ` [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry NeilBrown 2025-02-14 6:00 ` [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry Al Viro 3 siblings, 0 replies; 17+ messages in thread From: NeilBrown @ 2025-02-14 5:16 UTC (permalink / raw) To: Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: linux-nfs, linux-fsdevel, linux-kernel mkdir now allows a different dentry to be returned which is sometimes relevant for nfs. This patch changes the nfs_rpc_ops mkdir op to return a dentry, and passes that back to the caller. The mkdir nfs_rpc_op may return NULL if the original dentry should be used. This is different from the mkdir inode_operation. Signed-off-by: NeilBrown <neilb@suse.de> --- fs/nfs/dir.c | 18 ++++++++--------- fs/nfs/nfs3proc.c | 7 ++++--- fs/nfs/nfs4proc.c | 43 +++++++++++++++++++++++++++++------------ fs/nfs/proc.c | 12 ++++++++---- include/linux/nfs_xdr.h | 2 +- 5 files changed, 53 insertions(+), 29 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 1bf728367426..84ee33bbd91f 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2426,7 +2426,7 @@ struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { struct iattr attr; - int error; + struct dentry *ret; dfprintk(VFS, "NFS: mkdir(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); @@ -2435,14 +2435,14 @@ struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, attr.ia_mode = mode | S_IFDIR; trace_nfs_mkdir_enter(dir, dentry); - error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); - trace_nfs_mkdir_exit(dir, dentry, error); - if (error != 0) - goto out_err; - return dentry; -out_err: - d_drop(dentry); - return ERR_PTR(error); + ret = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); + trace_nfs_mkdir_exit(dir, dentry, PTR_ERR_OR_ZERO(ret)); + if (IS_ERR(ret)) + d_drop(dentry); + if (ret) + return ret; + else + return dentry; } EXPORT_SYMBOL_GPL(nfs_mkdir); diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 0c3bc98cd999..f8e239121669 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -578,7 +578,7 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio, return status; } -static int +static struct dentry * nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { struct posix_acl *default_acl, *acl; @@ -613,14 +613,15 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); - dput(d_alias); out_release_acls: posix_acl_release(acl); posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mkdir: %d\n", status); - return status; + if (status) + return ERR_PTR(status); + return dentry; } static int diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index df9669d4ded7..164c9f3f36c8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5135,9 +5135,6 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_ &data->arg.seq_args, &data->res.seq_res, 1); if (status == 0) { spin_lock(&dir->i_lock); - /* Creating a directory bumps nlink in the parent */ - if (data->arg.ftype == NF4DIR) - nfs4_inc_nlink_locked(dir); nfs4_update_changeattr_locked(dir, &data->res.dir_cinfo, data->res.fattr->time_start, NFS_INO_INVALID_DATA); @@ -5147,6 +5144,25 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_ return status; } +static struct dentry *nfs4_do_mkdir(struct inode *dir, struct dentry *dentry, + struct nfs4_createdata *data) +{ + int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg, + &data->arg.seq_args, &data->res.seq_res, 1); + + if (status) + return ERR_PTR(status); + + spin_lock(&dir->i_lock); + /* Creating a directory bumps nlink in the parent */ + nfs4_inc_nlink_locked(dir); + nfs4_update_changeattr_locked(dir, &data->res.dir_cinfo, + data->res.fattr->time_start, + NFS_INO_INVALID_DATA); + spin_unlock(&dir->i_lock); + return nfs_add_or_obtain(dentry, data->res.fh, data->res.fattr); +} + static void nfs4_free_createdata(struct nfs4_createdata *data) { nfs4_label_free(data->fattr.label); @@ -5203,32 +5219,34 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, return err; } -static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, - struct iattr *sattr, struct nfs4_label *label) +static struct dentry *_nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, + struct iattr *sattr, + struct nfs4_label *label) { struct nfs4_createdata *data; - int status = -ENOMEM; + struct dentry *ret = ERR_PTR(-ENOMEM); data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR); if (data == NULL) goto out; data->arg.label = label; - status = nfs4_do_create(dir, dentry, data); + ret = nfs4_do_mkdir(dir, dentry, data); nfs4_free_createdata(data); out: - return status; + return ret; } -static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, - struct iattr *sattr) +static struct dentry *nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, + struct iattr *sattr) { struct nfs_server *server = NFS_SERVER(dir); struct nfs4_exception exception = { .interruptible = true, }; struct nfs4_label l, *label; + struct dentry *alias; int err; label = nfs4_label_init_security(dir, dentry, sattr, &l); @@ -5236,14 +5254,15 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK)) sattr->ia_mode &= ~current_umask(); do { - err = _nfs4_proc_mkdir(dir, dentry, sattr, label); + alias = _nfs4_proc_mkdir(dir, dentry, sattr, label); + err = PTR_ERR_OR_ZERO(alias); trace_nfs4_mkdir(dir, &dentry->d_name, err); err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception); } while (exception.retry); nfs4_label_release_security(label); - return err; + return alias; } static int _nfs4_proc_readdir(struct nfs_readdir_arg *nr_arg, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 77920a2e3cef..63e71310b9f6 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -446,13 +446,14 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio, return status; } -static int +static struct dentry * nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { struct nfs_createdata *data; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], }; + struct dentry *alias = NULL; int status = -ENOMEM; dprintk("NFS call mkdir %pd\n", dentry); @@ -464,12 +465,15 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); - if (status == 0) - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); + if (status == 0) { + alias = nfs_add_or_obtain(dentry, data->res.fh, data->res.fattr); + status = PTR_ERR_OR_ZERO(alias); + } else + alias = ERR_PTR(status); nfs_free_createdata(data); out: dprintk("NFS reply mkdir: %d\n", status); - return status; + return alias; } static int diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 9155a6ffc370..d66c61cbbd1d 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1802,7 +1802,7 @@ struct nfs_rpc_ops { int (*link) (struct inode *, struct inode *, const struct qstr *); int (*symlink) (struct inode *, struct dentry *, struct folio *, unsigned int, struct iattr *); - int (*mkdir) (struct inode *, struct dentry *, struct iattr *); + struct dentry *(*mkdir) (struct inode *, struct dentry *, struct iattr *); int (*rmdir) (struct inode *, const struct qstr *); int (*readdir) (struct nfs_readdir_arg *, struct nfs_readdir_res *); int (*mknod) (struct inode *, struct dentry *, struct iattr *, -- 2.47.1 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry. 2025-02-14 5:16 [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry NeilBrown 2025-02-14 5:16 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 2025-02-14 5:16 ` [PATCH 2/3] nfs: change mkdir inode_operation to return alternate dentry if needed NeilBrown @ 2025-02-14 5:16 ` NeilBrown 2025-02-15 4:10 ` kernel test robot 2025-02-15 6:36 ` kernel test robot 2025-02-14 6:00 ` [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry Al Viro 3 siblings, 2 replies; 17+ messages in thread From: NeilBrown @ 2025-02-14 5:16 UTC (permalink / raw) To: Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: linux-nfs, linux-fsdevel, linux-kernel vfs_mkdir() does not guarantee to leave the child dentry hashed or make it positive on success. It may leave it unhashed and negative and then the caller needs to perform a lookup to find the target dentry, if it needs it. This patch changes vfs_mkdir() to return the dentry provided by the filesystems which IS guaranteed to be hashed. This avoids the need for lookup code. If a different dentry is returned, the first one is put. If necessary the fact that it is new can be determined by comparing pointers. A new dentry will certainly have a new pointer (as the old is put after the new is obtained). Signed-off-by: NeilBrown <neilb@suse.de> --- drivers/base/devtmpfs.c | 7 +++---- fs/cachefiles/namei.c | 11 ++++------ fs/ecryptfs/inode.c | 8 ++++--- fs/init.c | 6 ++++-- fs/namei.c | 45 ++++++++++++++++++++++++++-------------- fs/nfsd/nfs4recover.c | 6 ++++-- fs/nfsd/vfs.c | 25 ++++++---------------- fs/overlayfs/dir.c | 37 ++++----------------------------- fs/overlayfs/overlayfs.h | 15 +++++++------- fs/overlayfs/super.c | 5 +++-- fs/smb/server/vfs.c | 25 +++++----------------- fs/xfs/scrub/orphanage.c | 7 ++++--- include/linux/fs.h | 4 ++-- 13 files changed, 80 insertions(+), 121 deletions(-) diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index c9e34842139f..8ec756b5dec4 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -160,18 +160,17 @@ static int dev_mkdir(const char *name, umode_t mode) { struct dentry *dentry; struct path path; - int err; dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY); if (IS_ERR(dentry)) return PTR_ERR(dentry); - err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode); - if (!err) + dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode); + if (!IS_ERR(dentry)) /* mark as kernel-created inode */ d_inode(dentry)->i_private = &thread; done_path_create(&path, dentry); - return err; + return PTR_ERR_OR_ZERO(dentry); } static int create_path(const char *nodepath) diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 7cf59713f0f7..8188fe7a5084 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -95,7 +95,6 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, /* search the current directory for the element name */ inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); -retry: ret = cachefiles_inject_read_error(); if (ret == 0) subdir = lookup_one_len(dirname, dir, strlen(dirname)); @@ -129,8 +128,10 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, if (ret < 0) goto mkdir_error; ret = cachefiles_inject_write_error(); - if (ret == 0) - ret = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700); + if (ret == 0) { + subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700); + ret = PTR_ERR_OR_ZERO(subdir); + } if (ret < 0) { trace_cachefiles_vfs_error(NULL, d_inode(dir), ret, cachefiles_trace_mkdir_error); @@ -138,10 +139,6 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, } trace_cachefiles_mkdir(dir, subdir); - if (unlikely(d_unhashed(subdir))) { - cachefiles_put_directory(subdir); - goto retry; - } ASSERT(d_backing_inode(subdir)); _debug("mkdir -> %pd{ino=%lu}", diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 7445c32c1e95..b01fd0bb4fe8 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -511,9 +511,11 @@ static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct inode *lower_dir; rc = lock_parent(dentry, &lower_dentry, &lower_dir); - if (!rc) - rc = vfs_mkdir(&nop_mnt_idmap, lower_dir, - lower_dentry, mode); + if (!rc) { + lower_dentry = vfs_mkdir(&nop_mnt_idmap, lower_dir, + lower_dentry, mode); + rc = PTR_ERR_OR_ZERO(lower_dentry); + } if (rc || d_really_is_negative(lower_dentry)) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); diff --git a/fs/init.c b/fs/init.c index e9387b6c4f30..07ac858e70c4 100644 --- a/fs/init.c +++ b/fs/init.c @@ -230,9 +230,11 @@ int __init init_mkdir(const char *pathname, umode_t mode) return PTR_ERR(dentry); mode = mode_strip_umask(d_inode(path.dentry), mode); error = security_path_mkdir(&path, dentry, mode); - if (!error) - error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, + if (!error) { + dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry, mode); + error = PTR_ERR_OR_ZERO(dentry); + } done_path_create(&path, dentry); return error; } diff --git a/fs/namei.c b/fs/namei.c index 6094d93ed7d3..c38ed9aefe3c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4126,7 +4126,8 @@ EXPORT_SYMBOL(kern_path_create); void done_path_create(struct path *path, struct dentry *dentry) { - dput(dentry); + if (!IS_ERR(dentry)) + dput(dentry); inode_unlock(path->dentry->d_inode); mnt_drop_write(path->mnt); path_put(path); @@ -4272,7 +4273,7 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d } /** - * vfs_mkdir - create directory + * vfs_mkdir - create directory returning correct dentry * @idmap: idmap of the mount the inode was found from * @dir: inode of the parent directory * @dentry: dentry of the child directory @@ -4285,9 +4286,15 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d * care to map the inode according to @idmap before checking permissions. * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. + * + * In the event that the filesystem does not use the *@dentry but + * unhashes it and spices a different one returning it, the original + * dentry is dput() and the alternate is returned. + * + * In case of an error the denrty is dput() and an ERR_PTR() is returned. */ -int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int error; unsigned max_links = dir->i_sb->s_max_links; @@ -4295,28 +4302,33 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, error = may_create(idmap, dir, dentry); if (error) - return error; + goto err; + error = -EPERM; if (!dir->i_op->mkdir) - return -EPERM; + goto err; mode = vfs_prepare_mode(idmap, dir, mode, S_IRWXUGO | S_ISVTX, 0); error = security_inode_mkdir(dir, dentry, mode); if (error) - return error; + goto err; + error = -EMLINK; if (max_links && dir->i_nlink >= max_links) - return -EMLINK; + goto err; de = dir->i_op->mkdir(idmap, dir, dentry, mode); error = PTR_ERR_OR_ZERO(de); - if (!error) { - fsnotify_mkdir(dir, de); - if (de != dentry) - /* Cannot return de yet */ - dput(de); - } - return error; + if (error) + goto err; + fsnotify_mkdir(dir, de); + if (de != dentry) + dput(dentry); + return de; + +err: + dput(dentry); + return ERR_PTR(error); } EXPORT_SYMBOL(vfs_mkdir); @@ -4336,8 +4348,9 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode) error = security_path_mkdir(&path, dentry, mode_strip_umask(path.dentry->d_inode, mode)); if (!error) { - error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, + dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry, mode); + error = PTR_ERR_OR_ZERO(dentry); } done_path_create(&path, dentry); if (retry_estale(error, lookup_flags)) { diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 28f4d5311c40..6773bef039dd 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -233,9 +233,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) * as well be forgiving and just succeed silently. */ goto out_put; - status = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU); + dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU); + status = PTR_ERR_OR_ZERO(dentry); out_put: - dput(dentry); + if (!status) + dput(dentry); out_unlock: inode_unlock(d_inode(dir)); if (status == 0) { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 29cb7b812d71..939267614b27 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1488,26 +1488,12 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, nfsd_check_ignore_resizing(iap); break; case S_IFDIR: - host_err = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode); - if (!host_err && unlikely(d_unhashed(dchild))) { - struct dentry *d; - d = lookup_one_len(dchild->d_name.name, - dchild->d_parent, - dchild->d_name.len); - if (IS_ERR(d)) { - host_err = PTR_ERR(d); - break; - } - if (unlikely(d_is_negative(d))) { - dput(d); - err = nfserr_serverfault; - goto out; - } + dchild = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode); + host_err = PTR_ERR_OR_ZERO(dchild); + if (!host_err && unlikely(dchild != resfhp->fh_dentry)) { dput(resfhp->fh_dentry); - resfhp->fh_dentry = dget(d); + resfhp->fh_dentry = dget(dchild); err = fh_update(resfhp); - dput(dchild); - dchild = d; if (err) goto out; } @@ -1530,7 +1516,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfsd_create_setattr(rqstp, fhp, resfhp, attrs); out: - dput(dchild); + if (!IS_ERR(dchild)) + dput(dchild); return err; out_nfserr: diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 74a0541a8619..f03ebf43883b 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -138,37 +138,6 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir, goto out; } -int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir, - struct dentry **newdentry, umode_t mode) -{ - int err; - struct dentry *d, *dentry = *newdentry; - - err = ovl_do_mkdir(ofs, dir, dentry, mode); - if (err) - return err; - - if (likely(!d_unhashed(dentry))) - return 0; - - /* - * vfs_mkdir() may succeed and leave the dentry passed - * to it unhashed and negative. If that happens, try to - * lookup a new hashed and positive dentry. - */ - d = ovl_lookup_upper(ofs, dentry->d_name.name, dentry->d_parent, - dentry->d_name.len); - if (IS_ERR(d)) { - pr_warn("failed lookup after mkdir (%pd2, err=%i).\n", - dentry, err); - return PTR_ERR(d); - } - dput(dentry); - *newdentry = d; - - return 0; -} - struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, struct dentry *newdentry, struct ovl_cattr *attr) { @@ -191,7 +160,8 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, case S_IFDIR: /* mkdir is special... */ - err = ovl_mkdir_real(ofs, dir, &newdentry, attr->mode); + newdentry = ovl_do_mkdir(ofs, dir, newdentry, attr->mode); + err = PTR_ERR_OR_ZERO(newdentry); break; case S_IFCHR: @@ -219,7 +189,8 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, } out: if (err) { - dput(newdentry); + if (!IS_ERR(newdentry)) + dput(newdentry); return ERR_PTR(err); } return newdentry; diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 0021e2025020..6f2f8f4cfbbc 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -241,13 +241,14 @@ static inline int ovl_do_create(struct ovl_fs *ofs, return err; } -static inline int ovl_do_mkdir(struct ovl_fs *ofs, - struct inode *dir, struct dentry *dentry, - umode_t mode) +static inline struct dentry *ovl_do_mkdir(struct ovl_fs *ofs, + struct inode *dir, + struct dentry *dentry, + umode_t mode) { - int err = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode); - pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, err); - return err; + dentry = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode); + pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, PTR_ERR_OR_ZERO(dentry)); + return dentry; } static inline int ovl_do_mknod(struct ovl_fs *ofs, @@ -838,8 +839,6 @@ struct ovl_cattr { #define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) }) -int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir, - struct dentry **newdentry, umode_t mode); struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, struct dentry *newdentry, struct ovl_cattr *attr); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 86ae6f6da36b..3802678b960c 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -327,9 +327,10 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, goto retry; } - err = ovl_mkdir_real(ofs, dir, &work, attr.ia_mode); + work = ovl_do_mkdir(ofs, dir, work, attr.ia_mode); + err = PTR_ERR_OR_ZERO(work); if (err) - goto out_dput; + goto out_err; /* Weird filesystem returning with hashed negative (kernfs)? */ err = -EINVAL; diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index fe29acef5872..4589a151b80d 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -206,7 +206,7 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) { struct mnt_idmap *idmap; struct path path; - struct dentry *dentry; + struct dentry *dentry, *d; int err; dentry = ksmbd_vfs_kern_path_create(work, name, @@ -222,27 +222,12 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) idmap = mnt_idmap(path.mnt); mode |= S_IFDIR; - err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); - if (!err && d_unhashed(dentry)) { - struct dentry *d; - - d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent, - dentry->d_name.len); - if (IS_ERR(d)) { - err = PTR_ERR(d); - goto out_err; - } - if (unlikely(d_is_negative(d))) { - dput(d); - err = -ENOENT; - goto out_err; - } - + d = dentry; + entry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); + err = PTR_ERR_OR_ZERO(dentry); + if (!err && dentry != d) ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); - dput(d); - } -out_err: done_path_create(&path, dentry); if (err) pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); diff --git a/fs/xfs/scrub/orphanage.c b/fs/xfs/scrub/orphanage.c index c287c755f2c5..9b8d27624717 100644 --- a/fs/xfs/scrub/orphanage.c +++ b/fs/xfs/scrub/orphanage.c @@ -167,10 +167,11 @@ xrep_orphanage_create( * directory to control access to a file we put in here. */ if (d_really_is_negative(orphanage_dentry)) { - error = vfs_mkdir(&nop_mnt_idmap, root_inode, orphanage_dentry, - 0750); + orphanage_dentry = vfs_mkdir(&nop_mnt_idmap, root_inode, + orphanage_dentry, 0750); + error = PTR_ERR_OR_ZERO(orphanage_dentry); if (error) - goto out_dput_orphanage; + goto out_unlock_root; } /* Not a directory? Bail out. */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 67eb77f75b40..29d0df85b7fb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1969,8 +1969,8 @@ bool inode_owner_or_capable(struct mnt_idmap *idmap, */ int vfs_create(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, bool); -int vfs_mkdir(struct mnt_idmap *, struct inode *, - struct dentry *, umode_t); +struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *, + struct dentry *, umode_t); int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, dev_t); int vfs_symlink(struct mnt_idmap *, struct inode *, -- 2.47.1 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry. 2025-02-14 5:16 ` [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry NeilBrown @ 2025-02-15 4:10 ` kernel test robot 2025-02-15 6:36 ` kernel test robot 1 sibling, 0 replies; 17+ messages in thread From: kernel test robot @ 2025-02-15 4:10 UTC (permalink / raw) To: NeilBrown, Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: oe-kbuild-all, linux-nfs, linux-fsdevel, linux-kernel Hi NeilBrown, kernel test robot noticed the following build errors: [auto build test ERROR on brauner-vfs/vfs.all] [also build test ERROR on trondmy-nfs/linux-next driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus cifs/for-next xfs-linux/for-next linus/master v6.14-rc2 next-20250214] [cannot apply to ericvh-v9fs/for-next tyhicks-ecryptfs/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/NeilBrown/nfs-change-mkdir-inode_operation-to-return-alternate-dentry-if-needed/20250214-141741 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250214052204.3105610-4-neilb%40suse.de patch subject: [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry. config: x86_64-buildonly-randconfig-001-20250215 (https://download.01.org/0day-ci/archive/20250215/202502151124.LyMTodTU-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250215/202502151124.LyMTodTU-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202502151124.LyMTodTU-lkp@intel.com/ All errors (new ones prefixed by >>): fs/smb/server/vfs.c: In function 'ksmbd_vfs_mkdir': >> fs/smb/server/vfs.c:226:9: error: 'entry' undeclared (first use in this function); did you mean 'dentry'? 226 | entry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); | ^~~~~ | dentry fs/smb/server/vfs.c:226:9: note: each undeclared identifier is reported only once for each function it appears in vim +226 fs/smb/server/vfs.c 196 197 /** 198 * ksmbd_vfs_mkdir() - vfs helper for smb create directory 199 * @work: work 200 * @name: directory name that is relative to share 201 * @mode: directory create mode 202 * 203 * Return: 0 on success, otherwise error 204 */ 205 int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) 206 { 207 struct mnt_idmap *idmap; 208 struct path path; 209 struct dentry *dentry, *d; 210 int err; 211 212 dentry = ksmbd_vfs_kern_path_create(work, name, 213 LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, 214 &path); 215 if (IS_ERR(dentry)) { 216 err = PTR_ERR(dentry); 217 if (err != -EEXIST) 218 ksmbd_debug(VFS, "path create failed for %s, err %d\n", 219 name, err); 220 return err; 221 } 222 223 idmap = mnt_idmap(path.mnt); 224 mode |= S_IFDIR; 225 d = dentry; > 226 entry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); 227 err = PTR_ERR_OR_ZERO(dentry); 228 if (!err && dentry != d) 229 ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); 230 231 done_path_create(&path, dentry); 232 if (err) 233 pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); 234 return err; 235 } 236 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry. 2025-02-14 5:16 ` [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry NeilBrown 2025-02-15 4:10 ` kernel test robot @ 2025-02-15 6:36 ` kernel test robot 1 sibling, 0 replies; 17+ messages in thread From: kernel test robot @ 2025-02-15 6:36 UTC (permalink / raw) To: NeilBrown, Al Viro, Christian Brauner, Trond Myklebust, Anna Schumaker Cc: llvm, oe-kbuild-all, linux-nfs, linux-fsdevel, linux-kernel Hi NeilBrown, kernel test robot noticed the following build errors: [auto build test ERROR on brauner-vfs/vfs.all] [also build test ERROR on trondmy-nfs/linux-next driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus cifs/for-next xfs-linux/for-next linus/master v6.14-rc2 next-20250214] [cannot apply to ericvh-v9fs/for-next tyhicks-ecryptfs/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/NeilBrown/nfs-change-mkdir-inode_operation-to-return-alternate-dentry-if-needed/20250214-141741 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250214052204.3105610-4-neilb%40suse.de patch subject: [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry. config: riscv-randconfig-001-20250215 (https://download.01.org/0day-ci/archive/20250215/202502151435.jfkY8wb2-lkp@intel.com/config) compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250215/202502151435.jfkY8wb2-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202502151435.jfkY8wb2-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from ./arch/riscv/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/riscv/include/asm/io.h:136: include/asm-generic/io.h:812:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 812 | insw(addr, buffer, count); | ^~~~~~~~~~~~~~~~~~~~~~~~~ arch/riscv/include/asm/io.h:105:53: note: expanded from macro 'insw' 105 | #define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count) | ~~~~~~~~~~ ^ In file included from fs/smb/server/vfs.c:11: In file included from include/linux/backing-dev.h:16: In file included from include/linux/writeback.h:13: In file included from include/linux/blk_types.h:10: In file included from include/linux/bvec.h:10: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from ./arch/riscv/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/riscv/include/asm/io.h:136: include/asm-generic/io.h:820:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 820 | insl(addr, buffer, count); | ^~~~~~~~~~~~~~~~~~~~~~~~~ arch/riscv/include/asm/io.h:106:53: note: expanded from macro 'insl' 106 | #define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count) | ~~~~~~~~~~ ^ In file included from fs/smb/server/vfs.c:11: In file included from include/linux/backing-dev.h:16: In file included from include/linux/writeback.h:13: In file included from include/linux/blk_types.h:10: In file included from include/linux/bvec.h:10: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from ./arch/riscv/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/riscv/include/asm/io.h:136: include/asm-generic/io.h:829:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 829 | outsb(addr, buffer, count); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ arch/riscv/include/asm/io.h:118:55: note: expanded from macro 'outsb' 118 | #define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count) | ~~~~~~~~~~ ^ In file included from fs/smb/server/vfs.c:11: In file included from include/linux/backing-dev.h:16: In file included from include/linux/writeback.h:13: In file included from include/linux/blk_types.h:10: In file included from include/linux/bvec.h:10: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from ./arch/riscv/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/riscv/include/asm/io.h:136: include/asm-generic/io.h:838:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 838 | outsw(addr, buffer, count); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ arch/riscv/include/asm/io.h:119:55: note: expanded from macro 'outsw' 119 | #define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count) | ~~~~~~~~~~ ^ In file included from fs/smb/server/vfs.c:11: In file included from include/linux/backing-dev.h:16: In file included from include/linux/writeback.h:13: In file included from include/linux/blk_types.h:10: In file included from include/linux/bvec.h:10: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from ./arch/riscv/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/riscv/include/asm/io.h:136: include/asm-generic/io.h:847:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 847 | outsl(addr, buffer, count); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ arch/riscv/include/asm/io.h:120:55: note: expanded from macro 'outsl' 120 | #define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count) | ~~~~~~~~~~ ^ In file included from fs/smb/server/vfs.c:11: In file included from include/linux/backing-dev.h:16: In file included from include/linux/writeback.h:13: In file included from include/linux/blk_types.h:10: In file included from include/linux/bvec.h:10: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from ./arch/riscv/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:14: In file included from arch/riscv/include/asm/io.h:136: include/asm-generic/io.h:1175:55: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 1175 | return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port; | ~~~~~~~~~~ ^ >> fs/smb/server/vfs.c:226:2: error: use of undeclared identifier 'entry'; did you mean 'dentry'? 226 | entry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); | ^~~~~ | dentry fs/smb/server/vfs.c:209:17: note: 'dentry' declared here 209 | struct dentry *dentry, *d; | ^ 7 warnings and 1 error generated. vim +226 fs/smb/server/vfs.c 196 197 /** 198 * ksmbd_vfs_mkdir() - vfs helper for smb create directory 199 * @work: work 200 * @name: directory name that is relative to share 201 * @mode: directory create mode 202 * 203 * Return: 0 on success, otherwise error 204 */ 205 int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) 206 { 207 struct mnt_idmap *idmap; 208 struct path path; 209 struct dentry *dentry, *d; 210 int err; 211 212 dentry = ksmbd_vfs_kern_path_create(work, name, 213 LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, 214 &path); 215 if (IS_ERR(dentry)) { 216 err = PTR_ERR(dentry); 217 if (err != -EEXIST) 218 ksmbd_debug(VFS, "path create failed for %s, err %d\n", 219 name, err); 220 return err; 221 } 222 223 idmap = mnt_idmap(path.mnt); 224 mode |= S_IFDIR; 225 d = dentry; > 226 entry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); 227 err = PTR_ERR_OR_ZERO(dentry); 228 if (!err && dentry != d) 229 ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); 230 231 done_path_create(&path, dentry); 232 if (err) 233 pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); 234 return err; 235 } 236 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry 2025-02-14 5:16 [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry NeilBrown ` (2 preceding siblings ...) 2025-02-14 5:16 ` [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry NeilBrown @ 2025-02-14 6:00 ` Al Viro 2025-02-14 6:13 ` Al Viro 2025-02-17 3:53 ` NeilBrown 3 siblings, 2 replies; 17+ messages in thread From: Al Viro @ 2025-02-14 6:00 UTC (permalink / raw) To: NeilBrown Cc: Christian Brauner, Trond Myklebust, Anna Schumaker, linux-nfs, linux-fsdevel, linux-kernel On Fri, Feb 14, 2025 at 04:16:40PM +1100, NeilBrown wrote: > This is a small set of patches which are needed before we can make the > locking on directory operations more fine grained. I think they are > useful even if we don't go that direction. > > Some callers of vfs_mkdir() need to operation on the resulting directory > but cannot be guaranteed that the dentry will be hashed and positive on > success - another dentry might have been used. > > This patch changes ->mkdir to return a dentry, changes NFS in particular > to return the correct dentry (I believe it is the only filesystem to > possibly not use the given dentry), and changes vfs_mkdir() to return > that dentry, removing the look that a few callers currently need. > > I have not Cc: the developers of all the individual filesystems - only > NFS. I have build-tested all the changes except hostfs. I can email > them explicitly if/when this is otherwise acceptable. If anyone sees > this on fs-devel and wants to provide a pre-emptive ack I will collect > those and avoid further posting for those fs. 1) please, don't sprinkle the PTR_ERR_OR_ZERO() shite all over the place. Almost always the same thing can be done without it and it ends up being cleaner. Seriously. 2) I suspect that having method instances return NULL for "just use the argument" would would be harder to fuck up; basically, the same as for ->lookup() instances. I'll try to tweak it and see what falls out... 3) I'm pretty sure that NFS is *not* the only filesystem that returns unhashed negative in some success cases; will need to go over the instances to verify that, though. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry 2025-02-14 6:00 ` [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry Al Viro @ 2025-02-14 6:13 ` Al Viro 2025-02-14 6:33 ` Al Viro 2025-02-17 3:53 ` NeilBrown 1 sibling, 1 reply; 17+ messages in thread From: Al Viro @ 2025-02-14 6:13 UTC (permalink / raw) To: NeilBrown Cc: Christian Brauner, Trond Myklebust, Anna Schumaker, linux-nfs, linux-fsdevel, linux-kernel On Fri, Feb 14, 2025 at 06:00:39AM +0000, Al Viro wrote: > 3) I'm pretty sure that NFS is *not* the only filesystem that returns > unhashed negative in some success cases; will need to go over the instances > to verify that, though. Definitely so: in cifs_mkdir() we have if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, cifs_sb); d_drop(direntry); /* for time being always refresh inode info */ goto mkdir_out; } There might be other cases. hostfs is definitely like that, I'm pretty sure that kernfs is as well... ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry 2025-02-14 6:13 ` Al Viro @ 2025-02-14 6:33 ` Al Viro 0 siblings, 0 replies; 17+ messages in thread From: Al Viro @ 2025-02-14 6:33 UTC (permalink / raw) To: NeilBrown Cc: Christian Brauner, Trond Myklebust, Anna Schumaker, linux-nfs, linux-fsdevel, linux-kernel On Fri, Feb 14, 2025 at 06:13:55AM +0000, Al Viro wrote: > On Fri, Feb 14, 2025 at 06:00:39AM +0000, Al Viro wrote: > > > 3) I'm pretty sure that NFS is *not* the only filesystem that returns > > unhashed negative in some success cases; will need to go over the instances > > to verify that, though. > > Definitely so: in cifs_mkdir() we have > if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { > rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, > cifs_sb); > d_drop(direntry); /* for time being always refresh inode info */ > goto mkdir_out; > } > There might be other cases. hostfs is definitely like that, I'm pretty > sure that kernfs is as well... kernfs is actually playing fast and loose with the calling conventions there; it does not bother with unhashing and relies upon its ->d_revalidate() noticing and unhashing the sucker. Another variant that would work (and follow the calling conventions) is to have ->lookup() that leaves negatives unhashed and ->mkdir() not bothering to hash or instantiate. It really needs a review instance by instance. And yes, it does look like ->lookup()-like calling conventions end up better, especially if we make an instance return d_splice_alias() result... ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry 2025-02-14 6:00 ` [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry Al Viro 2025-02-14 6:13 ` Al Viro @ 2025-02-17 3:53 ` NeilBrown 1 sibling, 0 replies; 17+ messages in thread From: NeilBrown @ 2025-02-17 3:53 UTC (permalink / raw) To: Al Viro Cc: Christian Brauner, Trond Myklebust, Anna Schumaker, linux-nfs, linux-fsdevel, linux-kernel On Fri, 14 Feb 2025, Al Viro wrote: > On Fri, Feb 14, 2025 at 04:16:40PM +1100, NeilBrown wrote: > > This is a small set of patches which are needed before we can make the > > locking on directory operations more fine grained. I think they are > > useful even if we don't go that direction. > > > > Some callers of vfs_mkdir() need to operation on the resulting directory > > but cannot be guaranteed that the dentry will be hashed and positive on > > success - another dentry might have been used. > > > > This patch changes ->mkdir to return a dentry, changes NFS in particular > > to return the correct dentry (I believe it is the only filesystem to > > possibly not use the given dentry), and changes vfs_mkdir() to return > > that dentry, removing the look that a few callers currently need. > > > > I have not Cc: the developers of all the individual filesystems - only > > NFS. I have build-tested all the changes except hostfs. I can email > > them explicitly if/when this is otherwise acceptable. If anyone sees > > this on fs-devel and wants to provide a pre-emptive ack I will collect > > those and avoid further posting for those fs. > > 1) please, don't sprinkle the PTR_ERR_OR_ZERO() shite all over the place. > Almost always the same thing can be done without it and it ends up > being cleaner. Seriously. I've removed several PTR_ERR_OR_ZERO() calls. Some times that could be seen as a slight improvement, other times possibly a slight negative (depending on how one feels about PTR_ERR_OR_ZERO of course). I have left three as I cannot see how to remove them without making the code significant more clumsy. If you find the remaining few to still be objectionable I would be happy to see what alternate you would propose. Your other feedback has been quite helpful - thanks. NeilBrown > > 2) I suspect that having method instances return NULL for "just use the > argument" would would be harder to fuck up; basically, the same as for > ->lookup() instances. I'll try to tweak it and see what falls out... > > 3) I'm pretty sure that NFS is *not* the only filesystem that returns > unhashed negative in some success cases; will need to go over the instances > to verify that, though. > ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 0/3 RFC v2] change ->mkdir() and vfs_mkdir() to return a dentry @ 2025-02-17 5:30 NeilBrown 2025-02-17 5:30 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 0 siblings, 1 reply; 17+ messages in thread From: NeilBrown @ 2025-02-17 5:30 UTC (permalink / raw) To: Christian Brauner, Alexander Viro, Jan Kara; +Cc: linux-fsdevel, linux-kernel Here is a second attempt at this change. Guided by Al I have handled other file systems which don't return a hashed positive dentry on success. It is not always possible to provide a reliable answer. One example is that cifs might find, after successfully creating a directory, that the name now leads to a non-directory (due to a race with another client). So callers of vfs_mkdir() need to cope with successful mkdir but no usable dentry. There is nothing they can do to recover and must continue gracefully. This failre mode is detected by the returned dentry being unhashed. ORIGINAL DESCRIPTION - updated to reflect changes. This is a small set of patches which are needed before we can make the locking on directory operations more fine grained. I think they are useful even if we don't go that direction. Some callers of vfs_mkdir() need to operate on the resulting directory but cannot be guaranteed that the dentry will be hashed and positive on success - another dentry might have been used. This patch changes ->mkdir to return a dentry, changes several filesystems to return the correct dentry, and changes vfs_mkdir() to return that dentry, only performing a lookup as a last resort. I have not Cc: the developers of all the individual filesystems NFS. I or kernel-test-robot have build-tested all the changes. If anyone sees this on fs-devel and wants to provide a pre-emptive ack I will collect those and avoid further posting for those fs. Thanks, NeilBrown [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * [PATCH 2/3] nfs: change mkdir inode_operation to return alternate [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry. ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-17 5:30 [PATCH 0/3 RFC v2] change " NeilBrown @ 2025-02-17 5:30 ` NeilBrown 2025-02-18 12:20 ` Jan Kara ` (2 more replies) 0 siblings, 3 replies; 17+ messages in thread From: NeilBrown @ 2025-02-17 5:30 UTC (permalink / raw) To: Christian Brauner, Alexander Viro, Jan Kara; +Cc: linux-fsdevel, linux-kernel Some filesystems, such as NFS, cifs, ceph, and fuse, do not have complete control of sequencing on the actual filesystem (e.g. on a different server) and may find that the inode created for a mkdir request already exists in the icache and dcache by the time the mkdir request returns. For example, if the filesystem is mounted twice the file could be visible on the other mount before it is on the original mount, and a pair of name_to_handle_at(), open_by_handle_at() could instantiate the directory inode with an IS_ROOT() dentry before the first mkdir returns. This means that the dentry passed to ->mkdir() may not be the one that is associated with the inode after the ->mkdir() completes. Some callers need to interact with the inode after the ->mkdir completes and they currently need to perform a lookup in the (rare) case that the dentry is no longer hashed. This lookup-after-mkdir requires that the directory remains locked to avoid races. Planned future patches to lock the dentry rather than the directory will mean that this lookup cannot be performed atomically with the mkdir. To remove this barrier, this patch changes ->mkdir to return the resulting dentry if it is different from the one passed in. Possible returns are: NULL - the directory was created and no other dentry was used ERR_PTR() - an error occurred non-NULL - this other dentry was spliced in Not all filesystems reliable result in a positive hashed dentry: - NFS does produce the proper dentry, but does not yet return it. The code change is larger than I wanted to include in this patch - cifs will, when posix extensions are enabled, unhash the dentry on success so a subsequent lookup will create it if needed. - cifs without posix extensions will unhash the dentry if an internal lookup finds a non-directory where it expected the dir. - kernfs and tracefs leave the dentry negative and the ->revalidate operation ensures that lookup will be called to correctly populate the dentry - hostfs leaves the dentry negative and uses .d_delete = always_delete_dentry so the negative dentry is quickly discarded and a lookup will add a new entry. Signed-off-by: NeilBrown <neilb@suse.de> --- Documentation/filesystems/locking.rst | 2 +- Documentation/filesystems/porting.rst | 11 +++++ Documentation/filesystems/vfs.rst | 7 +++- fs/9p/vfs_inode.c | 7 ++-- fs/9p/vfs_inode_dotl.c | 8 ++-- fs/affs/affs.h | 2 +- fs/affs/namei.c | 8 ++-- fs/afs/dir.c | 12 +++--- fs/autofs/root.c | 14 +++---- fs/bad_inode.c | 6 +-- fs/bcachefs/fs.c | 6 +-- fs/btrfs/inode.c | 8 ++-- fs/ceph/dir.c | 15 +++++-- fs/coda/dir.c | 14 +++---- fs/configfs/dir.c | 6 +-- fs/ecryptfs/inode.c | 6 +-- fs/exfat/namei.c | 8 ++-- fs/ext2/namei.c | 9 +++-- fs/ext4/namei.c | 10 ++--- fs/f2fs/namei.c | 14 +++---- fs/fat/namei_msdos.c | 8 ++-- fs/fat/namei_vfat.c | 8 ++-- fs/fuse/dir.c | 58 +++++++++++++++++---------- fs/gfs2/inode.c | 9 +++-- fs/hfs/dir.c | 10 ++--- fs/hfsplus/dir.c | 6 +-- fs/hostfs/hostfs_kern.c | 8 ++-- fs/hpfs/namei.c | 10 ++--- fs/hugetlbfs/inode.c | 6 +-- fs/jffs2/dir.c | 18 ++++----- fs/jfs/namei.c | 8 ++-- fs/kernfs/dir.c | 12 +++--- fs/minix/namei.c | 8 ++-- fs/namei.c | 14 +++++-- fs/nfs/dir.c | 9 +++-- fs/nfs/internal.h | 4 +- fs/nilfs2/namei.c | 8 ++-- fs/ntfs3/namei.c | 8 ++-- fs/ocfs2/dlmfs/dlmfs.c | 14 ++++--- fs/ocfs2/namei.c | 10 ++--- fs/omfs/dir.c | 6 +-- fs/orangefs/namei.c | 8 ++-- fs/overlayfs/dir.c | 9 +++-- fs/ramfs/inode.c | 6 +-- fs/smb/client/cifsfs.h | 4 +- fs/smb/client/inode.c | 10 ++--- fs/sysv/namei.c | 8 ++-- fs/tracefs/inode.c | 10 ++--- fs/ubifs/dir.c | 10 ++--- fs/udf/namei.c | 12 +++--- fs/ufs/namei.c | 8 ++-- fs/vboxsf/dir.c | 8 ++-- fs/xfs/xfs_iops.c | 4 +- include/linux/fs.h | 4 +- kernel/bpf/inode.c | 8 ++-- mm/shmem.c | 8 ++-- security/apparmor/apparmorfs.c | 8 ++-- 57 files changed, 294 insertions(+), 246 deletions(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index d20a32b77b60..0ec0bb6eb0fb 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -66,7 +66,7 @@ prototypes:: int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 159adb02be52..68938b7ca1ab 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1175,3 +1175,14 @@ lookup_one_qstr_excl() is changed to return errors in some cases: LOOKUP_EXCL now means "target must not exist". It can be combined with LOOK_CREATE or LOOKUP_RENAME_TARGET. + +--- + +** mandatory** + +->mkdir() now returns a 'struct dentry *'. If the created inode is +found to already be in cache and have a dentry (often IS_ROOT), it will +need to be spliced into the given name in place of the given dentry. +That dentry now needs to be returned. If the original dentry is used, +NULL should be returned. Any error should be returned with +ERR_PTR(). diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 31eea688609a..bd3751dfddcf 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -495,7 +495,7 @@ As of kernel 2.6.22, the following members are defined: int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, @@ -562,7 +562,10 @@ otherwise noted. ``mkdir`` called by the mkdir(2) system call. Only required if you want to support creating subdirectories. You will probably need to - call d_instantiate() just as you would in the create() method + call d_instantiate() just as you would in the create() method. + If some dentry other than the one given is spliced in, then it + much be returned, otherwise NULL is returned is the original dentry + is successfully used, else an ERR_PTR() is returned. ``rmdir`` called by the rmdir(2) system call. Only required if you want diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 3e68521f4e2f..399d455d50d6 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -669,8 +669,8 @@ v9fs_vfs_create(struct mnt_idmap *idmap, struct inode *dir, * */ -static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int err; u32 perm; @@ -692,8 +692,7 @@ static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (fid) p9_fid_put(fid); - - return err; + return ERR_PTR(err); } /** diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 143ac03b7425..cc2007be2173 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -350,9 +350,9 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, * */ -static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, - struct inode *dir, struct dentry *dentry, - umode_t omode) +static struct dentry *v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, + struct inode *dir, struct dentry *dentry, + umode_t omode) { int err; struct v9fs_session_info *v9ses; @@ -417,7 +417,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, p9_fid_put(fid); v9fs_put_acl(dacl, pacl); p9_fid_put(dfid); - return err; + return ERR_PTR(err); } static int diff --git a/fs/affs/affs.h b/fs/affs/affs.h index e8c2c4535cb3..ac4e9a02910b 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -168,7 +168,7 @@ extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsi extern int affs_unlink(struct inode *dir, struct dentry *dentry); extern int affs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool); -extern int affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, +extern struct dentry *affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode); extern int affs_rmdir(struct inode *dir, struct dentry *dentry); extern int affs_link(struct dentry *olddentry, struct inode *dir, diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 8c154490a2d6..f883be50db12 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -273,7 +273,7 @@ affs_create(struct mnt_idmap *idmap, struct inode *dir, return 0; } -int +struct dentry * affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { @@ -285,7 +285,7 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, inode = affs_new_inode(dir); if (!inode) - return -ENOSPC; + return ERR_PTR(-ENOSPC); inode->i_mode = S_IFDIR | mode; affs_mode_to_prot(inode); @@ -298,9 +298,9 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, clear_nlink(inode); mark_inode_dirty(inode); iput(inode); - return error; + return ERR_PTR(error); } - return 0; + return NULL; } int diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 02cbf38e1a77..5bddcc20786e 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -33,8 +33,8 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nl loff_t fpos, u64 ino, unsigned dtype); static int afs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl); -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode); +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode); static int afs_rmdir(struct inode *dir, struct dentry *dentry); static int afs_unlink(struct inode *dir, struct dentry *dentry); static int afs_link(struct dentry *from, struct inode *dir, @@ -1315,8 +1315,8 @@ static const struct afs_operation_ops afs_mkdir_operation = { /* * create a directory on an AFS filesystem */ -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct afs_operation *op; struct afs_vnode *dvnode = AFS_FS_I(dir); @@ -1328,7 +1328,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, op = afs_alloc_operation(NULL, dvnode->volume); if (IS_ERR(op)) { d_drop(dentry); - return PTR_ERR(op); + return ERR_CAST(op); } fscache_use_cookie(afs_vnode_cache(dvnode), true); @@ -1344,7 +1344,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, op->ops = &afs_mkdir_operation; ret = afs_do_sync_operation(op); afs_dir_unuse_cookie(dvnode, ret); - return ret; + return ERR_PTR(ret); } /* diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 530d18827e35..174c7205fee4 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -15,8 +15,8 @@ static int autofs_dir_symlink(struct mnt_idmap *, struct inode *, struct dentry *, const char *); static int autofs_dir_unlink(struct inode *, struct dentry *); static int autofs_dir_rmdir(struct inode *, struct dentry *); -static int autofs_dir_mkdir(struct mnt_idmap *, struct inode *, - struct dentry *, umode_t); +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *, struct inode *, + struct dentry *, umode_t); static long autofs_root_ioctl(struct file *, unsigned int, unsigned long); #ifdef CONFIG_COMPAT static long autofs_root_compat_ioctl(struct file *, @@ -720,9 +720,9 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry) return 0; } -static int autofs_dir_mkdir(struct mnt_idmap *idmap, - struct inode *dir, struct dentry *dentry, - umode_t mode) +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *idmap, + struct inode *dir, struct dentry *dentry, + umode_t mode) { struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); struct autofs_info *ino = autofs_dentry_ino(dentry); @@ -739,7 +739,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, inode = autofs_get_inode(dir->i_sb, S_IFDIR | mode); if (!inode) - return -ENOMEM; + return ERR_PTR(-ENOMEM); d_add(dentry, inode); if (sbi->version < 5) @@ -751,7 +751,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, inc_nlink(dir); inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); - return 0; + return NULL; } /* Get/set timeout ioctl() operation */ diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 316d88da2ce1..0ef9bcb744dd 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -58,10 +58,10 @@ static int bad_inode_symlink(struct mnt_idmap *idmap, return -EIO; } -static int bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return -EIO; + return ERR_PTR(-EIO); } static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 90ade8f648d9..1c94a680fcce 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -858,10 +858,10 @@ static int bch2_symlink(struct mnt_idmap *idmap, return bch2_err_class(ret); } -static int bch2_mkdir(struct mnt_idmap *idmap, - struct inode *vdir, struct dentry *dentry, umode_t mode) +static struct dentry *bch2_mkdir(struct mnt_idmap *idmap, + struct inode *vdir, struct dentry *dentry, umode_t mode) { - return bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0); + return ERR_PTR(bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0)); } static int bch2_rename2(struct mnt_idmap *idmap, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a9322601ab5c..851d3e8a06a7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6739,18 +6739,18 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, return err; } -static int btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; inode = new_inode(dir->i_sb); if (!inode) - return -ENOMEM; + return ERR_PTR(-ENOMEM); inode_init_owner(idmap, inode, dir, S_IFDIR | mode); inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; - return btrfs_create_common(dir, dentry, inode); + return ERR_PTR(btrfs_create_common(dir, dentry, inode)); } static noinline int uncompress_inline(struct btrfs_path *path, diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 62e99e65250d..c1a1c168bb27 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1092,19 +1092,20 @@ static int ceph_symlink(struct mnt_idmap *idmap, struct inode *dir, return err; } -static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb); struct ceph_client *cl = mdsc->fsc->client; struct ceph_mds_request *req; struct ceph_acl_sec_ctx as_ctx = {}; + struct dentry *ret = NULL; int err; int op; err = ceph_wait_on_conflict_unlink(dentry); if (err) - return err; + return ERR_PTR(err); if (ceph_snap(dir) == CEPH_SNAPDIR) { /* mkdir .snap/foo is a MKSNAP */ @@ -1166,14 +1167,20 @@ static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); out_req: + if (!err && req->r_dentry != dentry) + /* Some other dentry was spliced in */ + ret = dget(req->r_dentry); ceph_mdsc_put_request(req); out: if (!err) + /* Should this use 'ret' ?? */ ceph_init_inode_acls(d_inode(dentry), &as_ctx); else d_drop(dentry); ceph_release_acl_sec_ctx(&as_ctx); - return err; + if (err) + return ERR_PTR(err); + return ret; } static int ceph_link(struct dentry *old_dentry, struct inode *dir, diff --git a/fs/coda/dir.c b/fs/coda/dir.c index a3e2dfeedfbf..ab69d8f0cec2 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -166,8 +166,8 @@ static int coda_create(struct mnt_idmap *idmap, struct inode *dir, return error; } -static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *de, umode_t mode) +static struct dentry *coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *de, umode_t mode) { struct inode *inode; struct coda_vattr attrs; @@ -177,14 +177,14 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct CodaFid newfid; if (is_root_inode(dir) && coda_iscontrol(name, len)) - return -EPERM; + return ERR_PTR(-EPERM); attrs.va_mode = mode; - error = venus_mkdir(dir->i_sb, coda_i2f(dir), + error = venus_mkdir(dir->i_sb, coda_i2f(dir), name, len, &newfid, &attrs); if (error) goto err_out; - + inode = coda_iget(dir->i_sb, &newfid, &attrs); if (IS_ERR(inode)) { error = PTR_ERR(inode); @@ -195,10 +195,10 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, coda_dir_inc_nlink(dir); coda_dir_update_mtime(dir); d_instantiate(de, inode); - return 0; + return NULL; err_out: d_drop(de); - return error; + return ERR_PTR(error); } /* try to make de an entry in dir_inodde linked to source_de */ diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 7d10278db30d..5568cb74b322 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1280,8 +1280,8 @@ int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys, } EXPORT_SYMBOL(configfs_depend_item_unlocked); -static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int ret = 0; int module_got = 0; @@ -1461,7 +1461,7 @@ static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, put_fragment(frag); out: - return ret; + return ERR_PTR(ret); } static int configfs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a9819ddb1ab8..6315dd194228 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -503,8 +503,8 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap, return rc; } -static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int rc; struct dentry *lower_dentry; @@ -526,7 +526,7 @@ static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, inode_unlock(lower_dir); if (d_really_is_negative(dentry)) d_drop(dentry); - return rc; + return ERR_PTR(rc); } static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index 691dd77b6ab5..1660c9bbcfa9 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -835,8 +835,8 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) return err; } -static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -846,7 +846,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, loff_t size = i_size_read(dir); if (unlikely(exfat_forced_shutdown(sb))) - return -EIO; + return ERR_PTR(-EIO); mutex_lock(&EXFAT_SB(sb)->s_lock); exfat_set_volume_dirty(sb); @@ -877,7 +877,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, unlock: mutex_unlock(&EXFAT_SB(sb)->s_lock); - return err; + return ERR_PTR(err); } static int exfat_check_dir_empty(struct super_block *sb, diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 8346ab9534c1..bde617a66cec 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -225,15 +225,16 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, return err; } -static int ext2_mkdir(struct mnt_idmap * idmap, - struct inode * dir, struct dentry * dentry, umode_t mode) +static struct dentry *ext2_mkdir(struct mnt_idmap * idmap, + struct inode * dir, struct dentry * dentry, + umode_t mode) { struct inode * inode; int err; err = dquot_initialize(dir); if (err) - return err; + return ERR_PTR(err); inode_inc_link_count(dir); @@ -258,7 +259,7 @@ static int ext2_mkdir(struct mnt_idmap * idmap, d_instantiate_new(dentry, inode); out: - return err; + return ERR_PTR(err); out_fail: inode_dec_link_count(inode); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 536d56d15072..716cc6096870 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3004,19 +3004,19 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, return err; } -static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { handle_t *handle; struct inode *inode; int err, err2 = 0, credits, retries = 0; if (EXT4_DIR_LINK_MAX(dir)) - return -EMLINK; + return ERR_PTR(-EMLINK); err = dquot_initialize(dir); if (err) - return err; + return ERR_PTR(err); credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); @@ -3066,7 +3066,7 @@ static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, out_retry: if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; - return err; + return ERR_PTR(err); } /* diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a278c7da8177..24dca4dc85a9 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -684,23 +684,23 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir, return err; } -static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err; if (unlikely(f2fs_cp_error(sbi))) - return -EIO; + return ERR_PTR(-EIO); err = f2fs_dquot_initialize(dir); if (err) - return err; + return ERR_PTR(err); inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; @@ -722,12 +722,12 @@ static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, f2fs_sync_fs(sbi->sb, 1); f2fs_balance_fs(sbi, true); - return 0; + return NULL; out_fail: clear_inode_flag(inode, FI_INC_LINK); f2fs_handle_failed_inode(inode); - return err; + return ERR_PTR(err); } static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index f06f6ba643cc..23e9b9371ec3 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -339,8 +339,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) } /***** Make a directory */ -static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; @@ -389,13 +389,13 @@ static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, mutex_unlock(&MSDOS_SB(sb)->s_lock); fat_flush_inodes(sb, dir, inode); - return 0; + return NULL; out_free: fat_free_clusters(dir, cluster); out: mutex_unlock(&MSDOS_SB(sb)->s_lock); - return err; + return ERR_PTR(err); } /***** Unlink a file */ diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 926c26e90ef8..dd910edd2404 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -841,8 +841,8 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) return err; } -static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -877,13 +877,13 @@ static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); mutex_unlock(&MSDOS_SB(sb)->s_lock); - return 0; + return NULL; out_free: fat_free_clusters(dir, cluster); out: mutex_unlock(&MSDOS_SB(sb)->s_lock); - return err; + return ERR_PTR(err); } static int vfat_get_dotdot_de(struct inode *inode, struct buffer_head **bh, diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 198862b086ff..2537eefcd023 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -781,9 +781,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, /* * Code shared between mknod, mkdir, symlink and link */ -static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, - struct fuse_args *args, struct inode *dir, - struct dentry *entry, umode_t mode) +static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, + struct fuse_args *args, struct inode *dir, + struct dentry *entry, umode_t mode) { struct fuse_entry_out outarg; struct inode *inode; @@ -792,11 +792,11 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, struct fuse_forget_link *forget; if (fuse_is_bad(dir)) - return -EIO; + return ERR_PTR(-EIO); forget = fuse_alloc_forget(); if (!forget) - return -ENOMEM; + return ERR_PTR(-ENOMEM); memset(&outarg, 0, sizeof(outarg)); args->nodeid = get_node_id(dir); @@ -826,29 +826,27 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); if (!inode) { fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } kfree(forget); d_drop(entry); d = d_splice_alias(inode, entry); if (IS_ERR(d)) - return PTR_ERR(d); + return d; - if (d) { + if (d) fuse_change_entry_timeout(d, &outarg); - dput(d); - } else { + else fuse_change_entry_timeout(entry, &outarg); - } fuse_dir_changed(dir); - return 0; + return d; out_put_forget_req: if (err == -EEXIST) fuse_invalidate_entry(entry); kfree(forget); - return err; + return ERR_PTR(err); } static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, @@ -856,6 +854,7 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, { struct fuse_mknod_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); + struct dentry *de; FUSE_ARGS(args); if (!fm->fc->dont_mask) @@ -871,7 +870,12 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, args.in_args[0].value = &inarg; args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; - return create_new_entry(idmap, fm, &args, dir, entry, mode); + de = create_new_entry(idmap, fm, &args, dir, entry, mode); + if (IS_ERR(de)) + return PTR_ERR(de); + if (de) + dput(de); + return 0; } static int fuse_create(struct mnt_idmap *idmap, struct inode *dir, @@ -898,8 +902,8 @@ static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir, return err; } -static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *entry, umode_t mode) +static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *entry, umode_t mode) { struct fuse_mkdir_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); @@ -918,6 +922,7 @@ static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); + } static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, @@ -925,6 +930,7 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, { struct fuse_mount *fm = get_fuse_mount(dir); unsigned len = strlen(link) + 1; + struct dentry *de; FUSE_ARGS(args); args.opcode = FUSE_SYMLINK; @@ -934,7 +940,12 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, args.in_args[1].value = entry->d_name.name; args.in_args[2].size = len; args.in_args[2].value = link; - return create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); + de = create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); + if (IS_ERR(de)) + return PTR_ERR(de); + if (de) + dput(de); + return 0; } void fuse_flush_time_update(struct inode *inode) @@ -1117,7 +1128,7 @@ static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir, static int fuse_link(struct dentry *entry, struct inode *newdir, struct dentry *newent) { - int err; + struct dentry *de; struct fuse_link_in inarg; struct inode *inode = d_inode(entry); struct fuse_mount *fm = get_fuse_mount(inode); @@ -1131,13 +1142,16 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, args.in_args[0].value = &inarg; args.in_args[1].size = newent->d_name.len + 1; args.in_args[1].value = newent->d_name.name; - err = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); - if (!err) + de = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); + if (!IS_ERR(de)) { + if (de) + dput(de); + de = NULL; fuse_update_ctime_in_cache(inode); - else if (err == -EINTR) + } else if (PTR_ERR(de) == -EINTR) fuse_invalidate_attr(inode); - return err; + return PTR_ERR(de); } static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode, diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6fbbaaad1cd0..198a8cbaf5e5 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1248,14 +1248,15 @@ static int gfs2_symlink(struct mnt_idmap *idmap, struct inode *dir, * @dentry: The dentry of the new directory * @mode: The mode of the new directory * - * Returns: errno + * Returns: the dentry, or ERR_PTR(errno) */ -static int gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { unsigned dsize = gfs2_max_stuffed_size(GFS2_I(dir)); - return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0); + + return ERR_PTR(gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0)); } /** diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index b75c26045df4..86a6b317b474 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -219,26 +219,26 @@ static int hfs_create(struct mnt_idmap *idmap, struct inode *dir, * in a directory, given the inode for the parent directory and the * name (and its length) of the new directory. */ -static int hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; int res; inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); if (!inode) - return -ENOMEM; + return ERR_PTR(-ENOMEM); res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); if (res) { clear_nlink(inode); hfs_delete_inode(inode); iput(inode); - return res; + return ERR_PTR(res); } d_instantiate(dentry, inode); mark_inode_dirty(inode); - return 0; + return NULL; } /* diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f5c4b3e31a1c..876bbb80fb4d 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -523,10 +523,10 @@ static int hfsplus_create(struct mnt_idmap *idmap, struct inode *dir, return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode, 0); } -static int hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); + return ERR_PTR(hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0)); } static int hfsplus_rename(struct mnt_idmap *idmap, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index e0741e468956..ccbb48fe830d 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -679,17 +679,17 @@ static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino, return err; } -static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, - struct dentry *dentry, umode_t mode) +static struct dentry *hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, + struct dentry *dentry, umode_t mode) { char *file; int err; if ((file = dentry_name(dentry)) == NULL) - return -ENOMEM; + return ERR_PTR(-ENOMEM); err = do_mkdir(file, mode); __putname(file); - return err; + return ERR_PTR(err); } static int hostfs_rmdir(struct inode *ino, struct dentry *dentry) diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index d0edf9ed33b6..e3cdc421dfba 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -19,8 +19,8 @@ static void hpfs_update_directory_times(struct inode *dir) hpfs_write_inode_nolock(dir); } -static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; @@ -35,7 +35,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, int r; struct hpfs_dirent dee; int err; - if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; + if ((err = hpfs_chk_name(name, &len))) return ERR_PTR(err==-ENOENT ? -EINVAL : err); hpfs_lock(dir->i_sb); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); @@ -112,7 +112,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); - return 0; + return NULL; bail3: iput(result); bail2: @@ -123,7 +123,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); - return err; + return ERR_PTR(err); } static int hpfs_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0fc179a59830..d98caedbb723 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -991,14 +991,14 @@ static int hugetlbfs_mknod(struct mnt_idmap *idmap, struct inode *dir, return 0; } -static int hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int retval = hugetlbfs_mknod(idmap, dir, dentry, mode | S_IFDIR, 0); if (!retval) inc_nlink(dir); - return retval; + return ERR_PTR(retval); } static int hugetlbfs_create(struct mnt_idmap *idmap, diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 2b2938970da3..dd91f725ded6 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -32,8 +32,8 @@ static int jffs2_link (struct dentry *,struct inode *,struct dentry *); static int jffs2_unlink (struct inode *,struct dentry *); static int jffs2_symlink (struct mnt_idmap *, struct inode *, struct dentry *, const char *); -static int jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, - umode_t); +static struct dentry *jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, + umode_t); static int jffs2_rmdir (struct inode *,struct dentry *); static int jffs2_mknod (struct mnt_idmap *, struct inode *,struct dentry *, umode_t,dev_t); @@ -446,8 +446,8 @@ static int jffs2_symlink (struct mnt_idmap *idmap, struct inode *dir_i, } -static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, - struct dentry *dentry, umode_t mode) +static struct dentry *jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, + struct dentry *dentry, umode_t mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -464,7 +464,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, ri = jffs2_alloc_raw_inode(); if (!ri) - return -ENOMEM; + return ERR_PTR(-ENOMEM); c = JFFS2_SB_INFO(dir_i->i_sb); @@ -477,7 +477,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, if (ret) { jffs2_free_raw_inode(ri); - return ret; + return ERR_PTR(ret); } inode = jffs2_new_inode(dir_i, mode, ri); @@ -485,7 +485,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); - return PTR_ERR(inode); + return ERR_CAST(inode); } inode->i_op = &jffs2_dir_inode_operations; @@ -584,11 +584,11 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, jffs2_complete_reservation(c); d_instantiate_new(dentry, inode); - return 0; + return NULL; fail: iget_failed(inode); - return ret; + return ERR_PTR(ret); } static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index fc8ede43afde..65a218eba8fa 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -187,13 +187,13 @@ static int jfs_create(struct mnt_idmap *idmap, struct inode *dip, * dentry - dentry of child directory * mode - create mode (rwxrwxrwx). * - * RETURN: Errors from subroutines + * RETURN: ERR_PTR() of errors from subroutines. * * note: * EACCES: user needs search+write permission on the parent directory */ -static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, - struct dentry *dentry, umode_t mode) +static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, + struct dentry *dentry, umode_t mode) { int rc = 0; tid_t tid; /* transaction id */ @@ -308,7 +308,7 @@ static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, out1: jfs_info("jfs_mkdir: rc:%d", rc); - return rc; + return ERR_PTR(rc); } /* diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 5f0f8b95f44c..d296aad70800 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1230,24 +1230,24 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, return d_splice_alias(inode, dentry); } -static int kernfs_iop_mkdir(struct mnt_idmap *idmap, - struct inode *dir, struct dentry *dentry, - umode_t mode) +static struct dentry *kernfs_iop_mkdir(struct mnt_idmap *idmap, + struct inode *dir, struct dentry *dentry, + umode_t mode) { struct kernfs_node *parent = dir->i_private; struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops; int ret; if (!scops || !scops->mkdir) - return -EPERM; + return ERR_PTR(-EPERM); if (!kernfs_get_active(parent)) - return -ENODEV; + return ERR_PTR(-ENODEV); ret = scops->mkdir(parent, dentry->d_name.name, mode); kernfs_put_active(parent); - return ret; + return ERR_PTR(ret); } static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 5d9c1406fe27..8938536d8d3c 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -104,15 +104,15 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, return add_nondir(dentry, inode); } -static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode * inode; int err; inode = minix_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); inode_inc_link_count(dir); minix_set_inode(inode, 0); @@ -128,7 +128,7 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); out: - return err; + return ERR_PTR(err); out_fail: inode_dec_link_count(inode); diff --git a/fs/namei.c b/fs/namei.c index 865a009fdebc..19d5ea340a18 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4297,6 +4297,7 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, { int error; unsigned max_links = dir->i_sb->s_max_links; + struct dentry *de; error = may_create(idmap, dir, dentry); if (error) @@ -4313,10 +4314,17 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (max_links && dir->i_nlink >= max_links) return -EMLINK; - error = dir->i_op->mkdir(idmap, dir, dentry, mode); - if (!error) + de = dir->i_op->mkdir(idmap, dir, dentry, mode); + if (IS_ERR(de)) + return PTR_ERR(de); + if (de) { + fsnotify_mkdir(dir, de); + /* Cannot return de yet */ + dput(de); + } else fsnotify_mkdir(dir, dentry); - return error; + + return 0; } EXPORT_SYMBOL(vfs_mkdir); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 56cf16a72334..5700f73d48bc 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2422,8 +2422,8 @@ EXPORT_SYMBOL_GPL(nfs_mknod); /* * See comments for nfs_proc_create regarding failed operations. */ -int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct iattr attr; int error; @@ -2439,10 +2439,11 @@ int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, trace_nfs_mkdir_exit(dir, dentry, error); if (error != 0) goto out_err; - return 0; + /* FIXME - ->mkdir might have used an alternate dentry */ + return NULL; out_err: d_drop(dentry); - return error; + return ERR_PTR(error); } EXPORT_SYMBOL_GPL(nfs_mkdir); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index fae2c7ae4acc..1ac1d3eec517 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -400,8 +400,8 @@ struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); void nfs_d_prune_case_insensitive_aliases(struct inode *inode); int nfs_create(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, bool); -int nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, - umode_t); +struct dentry *nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, + umode_t); int nfs_rmdir(struct inode *, struct dentry *); int nfs_unlink(struct inode *, struct dentry *); int nfs_symlink(struct mnt_idmap *, struct inode *, struct dentry *, diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 953fbd5f0851..40f4b1a28705 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -218,8 +218,8 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, return err; } -static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct nilfs_transaction_info ti; @@ -227,7 +227,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, err = nilfs_transaction_begin(dir->i_sb, &ti, 1); if (err) - return err; + return ERR_PTR(err); inc_nlink(dir); @@ -258,7 +258,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, else nilfs_transaction_abort(dir->i_sb); - return err; + return ERR_PTR(err); out_fail: drop_nlink(inode); diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index abf7e81584a9..652735a0b0c4 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -201,11 +201,11 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, /* * ntfs_mkdir- inode_operations::mkdir */ -static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, - NULL, 0, NULL); + return ERR_PTR(ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, + NULL, 0, NULL)); } /* diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 2a7f36643895..f632fbfe59e8 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -402,10 +402,10 @@ static struct inode *dlmfs_get_inode(struct inode *parent, * File creation. Allocate an inode, and we're done.. */ /* SMP-safe */ -static int dlmfs_mkdir(struct mnt_idmap * idmap, - struct inode * dir, - struct dentry * dentry, - umode_t mode) +static struct dentry *dlmfs_mkdir(struct mnt_idmap * idmap, + struct inode * dir, + struct dentry * dentry, + umode_t mode) { int status; struct inode *inode = NULL; @@ -446,9 +446,11 @@ static int dlmfs_mkdir(struct mnt_idmap * idmap, status = 0; bail: - if (status < 0) + if (status < 0) { iput(inode); - return status; + return ERR_PTR(status); + } + return NULL; } static int dlmfs_create(struct mnt_idmap *idmap, diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 0ec63a1a94b8..99278c8f0e24 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -644,10 +644,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, suballoc_loc, suballoc_bit); } -static int ocfs2_mkdir(struct mnt_idmap *idmap, - struct inode *dir, - struct dentry *dentry, - umode_t mode) +static struct dentry *ocfs2_mkdir(struct mnt_idmap *idmap, + struct inode *dir, + struct dentry *dentry, + umode_t mode) { int ret; @@ -657,7 +657,7 @@ static int ocfs2_mkdir(struct mnt_idmap *idmap, if (ret) mlog_errno(ret); - return ret; + return ERR_PTR(ret); } static int ocfs2_create(struct mnt_idmap *idmap, diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index 6bda275826d6..2ed541fccf33 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c @@ -279,10 +279,10 @@ static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) return err; } -static int omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return omfs_add_node(dir, dentry, mode | S_IFDIR); + return ERR_PTR(omfs_add_node(dir, dentry, mode | S_IFDIR)); } static int omfs_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 200558ec72f0..82395fe2b956 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -300,8 +300,8 @@ static int orangefs_symlink(struct mnt_idmap *idmap, return ret; } -static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct orangefs_inode_s *parent = ORANGEFS_I(dir); struct orangefs_kernel_op_s *new_op; @@ -312,7 +312,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR); if (!new_op) - return -ENOMEM; + return ERR_PTR(-ENOMEM); new_op->upcall.req.mkdir.parent_refn = parent->refn; @@ -366,7 +366,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, __orangefs_setattr(dir, &iattr); out: op_release(new_op); - return ret; + return ERR_PTR(ret); } static int orangefs_rename(struct mnt_idmap *idmap, diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index c9993ff66fc2..21c3aaf7b274 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -282,7 +282,8 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, * XXX: if we ever use ovl_obtain_alias() to decode directory * file handles, need to use ovl_get_inode_locked() and * d_instantiate_new() here to prevent from creating two - * hashed directory inode aliases. + * hashed directory inode aliases. We then need to return + * the obtained alias to ovl_mkdir(). */ inode = ovl_get_inode(dentry->d_sb, &oip); if (IS_ERR(inode)) @@ -687,10 +688,10 @@ static int ovl_create(struct mnt_idmap *idmap, struct inode *dir, return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); } -static int ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { - return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); + return ERR_PTR(ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL)); } static int ovl_mknod(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 8006faaaf0ec..775fa905fda0 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -119,13 +119,13 @@ ramfs_mknod(struct mnt_idmap *idmap, struct inode *dir, return error; } -static int ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int retval = ramfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); if (!retval) inc_nlink(dir); - return retval; + return ERR_PTR(retval); } static int ramfs_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 831fee962c4d..8dea0cf3a8de 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -59,8 +59,8 @@ extern int cifs_unlink(struct inode *dir, struct dentry *dentry); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); extern int cifs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, dev_t); -extern int cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, - umode_t); +extern struct dentry *cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, + umode_t); extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rename2(struct mnt_idmap *, struct inode *, struct dentry *, struct inode *, struct dentry *, diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 9cc31cf6ebd0..685a176f7f7e 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -2194,8 +2194,8 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ -int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, - struct dentry *direntry, umode_t mode) +struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, + struct dentry *direntry, umode_t mode) { int rc = 0; unsigned int xid; @@ -2211,10 +2211,10 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, cifs_sb = CIFS_SB(inode->i_sb); if (unlikely(cifs_forced_shutdown(cifs_sb))) - return -EIO; + return ERR_PTR(-EIO); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) - return PTR_ERR(tlink); + return ERR_CAST(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); @@ -2270,7 +2270,7 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, free_dentry_path(page); free_xid(xid); cifs_put_tlink(tlink); - return rc; + return ERR_PTR(rc); } int cifs_rmdir(struct inode *inode, struct dentry *direntry) diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index fb8bd8437872..ba037727c1e6 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -110,8 +110,8 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, return add_nondir(dentry, inode); } -static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode * inode; int err; @@ -135,9 +135,9 @@ static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (err) goto out_fail; - d_instantiate(dentry, inode); + d_instantiate(dentry, inode); out: - return err; + return ERR_PTR(err); out_fail: inode_dec_link_count(inode); diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 53214499e384..cb1af30b49f5 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -109,9 +109,9 @@ static char *get_dname(struct dentry *dentry) return name; } -static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, - struct inode *inode, struct dentry *dentry, - umode_t mode) +static struct dentry *tracefs_syscall_mkdir(struct mnt_idmap *idmap, + struct inode *inode, struct dentry *dentry, + umode_t mode) { struct tracefs_inode *ti; char *name; @@ -119,7 +119,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, name = get_dname(dentry); if (!name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); /* * This is a new directory that does not take the default of @@ -141,7 +141,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, kfree(name); - return ret; + return ERR_PTR(ret); } static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index fda82f3e16e8..3c3d3ad4fa6c 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1002,8 +1002,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) return err; } -static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); @@ -1023,7 +1023,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, err = ubifs_budget_space(c, &req); if (err) - return err; + return ERR_PTR(err); err = ubifs_prepare_create(dir, dentry, &nm); if (err) @@ -1060,7 +1060,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, ubifs_release_budget(c, &req); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); - return 0; + return NULL; out_cancel: dir->i_size -= sz_change; @@ -1074,7 +1074,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); - return err; + return ERR_PTR(err); } static int ubifs_mknod(struct mnt_idmap *idmap, struct inode *dir, diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 2cb49b6b0716..5f2e9a892bff 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -419,8 +419,8 @@ static int udf_mknod(struct mnt_idmap *idmap, struct inode *dir, return udf_add_nondir(dentry, inode); } -static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; struct udf_fileident_iter iter; @@ -430,7 +430,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, inode = udf_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); iinfo = UDF_I(inode); inode->i_op = &udf_dir_inode_operations; @@ -439,7 +439,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (err) { clear_nlink(inode); discard_new_inode(inode); - return err; + return ERR_PTR(err); } set_nlink(inode, 2); iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -456,7 +456,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, if (err) { clear_nlink(inode); discard_new_inode(inode); - return err; + return ERR_PTR(err); } iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location); @@ -471,7 +471,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, mark_inode_dirty(dir); d_instantiate_new(dentry, inode); - return 0; + return NULL; } static int empty_dir(struct inode *dir) diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 38a024c8cccd..5b3c85c93242 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -166,8 +166,8 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, return error; } -static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, - struct dentry * dentry, umode_t mode) +static struct dentry *ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, + struct dentry * dentry, umode_t mode) { struct inode * inode; int err; @@ -194,7 +194,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, goto out_fail; d_instantiate_new(dentry, inode); - return 0; + return NULL; out_fail: inode_dec_link_count(inode); @@ -202,7 +202,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, discard_new_inode(inode); out_dir: inode_dec_link_count(dir); - return err; + return ERR_PTR(err); } static int ufs_unlink(struct inode *dir, struct dentry *dentry) diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c index a859ac9b74ba..770e29ec3557 100644 --- a/fs/vboxsf/dir.c +++ b/fs/vboxsf/dir.c @@ -303,11 +303,11 @@ static int vboxsf_dir_mkfile(struct mnt_idmap *idmap, return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL); } -static int vboxsf_dir_mkdir(struct mnt_idmap *idmap, - struct inode *parent, struct dentry *dentry, - umode_t mode) +static struct dentry *vboxsf_dir_mkdir(struct mnt_idmap *idmap, + struct inode *parent, struct dentry *dentry, + umode_t mode) { - return vboxsf_dir_create(parent, dentry, mode, true, true, NULL); + return ERR_PTR(vboxsf_dir_create(parent, dentry, mode, true, true, NULL)); } static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry, diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 40289fe6f5b2..a4480098d2bf 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -298,14 +298,14 @@ xfs_vn_create( return xfs_generic_create(idmap, dir, dentry, mode, 0, NULL); } -STATIC int +STATIC struct dentry * xfs_vn_mkdir( struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { - return xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL); + return ERR_PTR(xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL)); } STATIC struct dentry * diff --git a/include/linux/fs.h b/include/linux/fs.h index 2c3b2f8a621f..45269608ee23 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2211,8 +2211,8 @@ struct inode_operations { int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *, const char *); - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *, - umode_t); + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *, + struct dentry *, umode_t); int (*rmdir) (struct inode *,struct dentry *); int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *, umode_t,dev_t); diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 9aaf5124648b..dc3aa91a6ba0 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -150,14 +150,14 @@ static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode, inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); } -static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct inode *inode; inode = bpf_get_inode(dir->i_sb, dir, mode | S_IFDIR); if (IS_ERR(inode)) - return PTR_ERR(inode); + return ERR_CAST(inode); inode->i_op = &bpf_dir_iops; inode->i_fop = &simple_dir_operations; @@ -166,7 +166,7 @@ static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, inc_nlink(dir); bpf_dentry_finalize(dentry, inode, dir); - return 0; + return NULL; } struct map_iter { diff --git a/mm/shmem.c b/mm/shmem.c index 4ea6109a8043..00ae0146e768 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3889,16 +3889,16 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir, return error; } -static int shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { int error; error = shmem_mknod(idmap, dir, dentry, mode | S_IFDIR, 0); if (error) - return error; + return ERR_PTR(error); inc_nlink(dir); - return 0; + return NULL; } static int shmem_create(struct mnt_idmap *idmap, struct inode *dir, diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index c07d150685d7..6039afae4bfc 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1795,8 +1795,8 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) return error; } -static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, umode_t mode) +static struct dentry *ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) { struct aa_ns *ns, *parent; /* TODO: improve permission check */ @@ -1808,7 +1808,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, AA_MAY_LOAD_POLICY); end_current_label_crit_section(label); if (error) - return error; + return ERR_PTR(error); parent = aa_get_ns(dir->i_private); AA_BUG(d_inode(ns_subns_dir(parent)) != dir); @@ -1843,7 +1843,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, mutex_unlock(&parent->lock); aa_put_ns(parent); - return error; + return ERR_PTR(error); } static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) -- 2.47.1 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-17 5:30 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown @ 2025-02-18 12:20 ` Jan Kara 2025-02-18 22:37 ` NeilBrown 2025-02-18 13:13 ` Jeff Layton 2025-02-19 13:19 ` Christian Brauner 2 siblings, 1 reply; 17+ messages in thread From: Jan Kara @ 2025-02-18 12:20 UTC (permalink / raw) To: NeilBrown Cc: Christian Brauner, Alexander Viro, Jan Kara, linux-fsdevel, linux-kernel On Mon 17-02-25 16:30:03, NeilBrown wrote: > Some filesystems, such as NFS, cifs, ceph, and fuse, do not have > complete control of sequencing on the actual filesystem (e.g. on a > different server) and may find that the inode created for a mkdir > request already exists in the icache and dcache by the time the mkdir > request returns. For example, if the filesystem is mounted twice the > file could be visible on the other mount before it is on the original > mount, and a pair of name_to_handle_at(), open_by_handle_at() could > instantiate the directory inode with an IS_ROOT() dentry before the > first mkdir returns. > > This means that the dentry passed to ->mkdir() may not be the one that > is associated with the inode after the ->mkdir() completes. Some > callers need to interact with the inode after the ->mkdir completes and > they currently need to perform a lookup in the (rare) case that the > dentry is no longer hashed. > > This lookup-after-mkdir requires that the directory remains locked to > avoid races. Planned future patches to lock the dentry rather than the > directory will mean that this lookup cannot be performed atomically with > the mkdir. > > To remove this barrier, this patch changes ->mkdir to return the > resulting dentry if it is different from the one passed in. > Possible returns are: > NULL - the directory was created and no other dentry was used > ERR_PTR() - an error occurred > non-NULL - this other dentry was spliced in > > Not all filesystems reliable result in a positive hashed dentry: > > - NFS does produce the proper dentry, but does not yet return it. The > code change is larger than I wanted to include in this patch > - cifs will, when posix extensions are enabled, unhash the > dentry on success so a subsequent lookup will create it if needed. > - cifs without posix extensions will unhash the dentry if an > internal lookup finds a non-directory where it expected the dir. > - kernfs and tracefs leave the dentry negative and the ->revalidate > operation ensures that lookup will be called to correctly populate > the dentry > - hostfs leaves the dentry negative and uses > .d_delete = always_delete_dentry > so the negative dentry is quickly discarded and a lookup will add a > new entry. > > Signed-off-by: NeilBrown <neilb@suse.de> Looks good to me. I've spotted just a few style nits: > diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst > index 31eea688609a..bd3751dfddcf 100644 > --- a/Documentation/filesystems/vfs.rst > +++ b/Documentation/filesystems/vfs.rst > @@ -562,7 +562,10 @@ otherwise noted. > ``mkdir`` > called by the mkdir(2) system call. Only required if you want > to support creating subdirectories. You will probably need to > - call d_instantiate() just as you would in the create() method > + call d_instantiate() just as you would in the create() method. > + If some dentry other than the one given is spliced in, then it > + much be returned, otherwise NULL is returned is the original dentry ^^^^ must > + is successfully used, else an ERR_PTR() is returned. > > ``rmdir`` > called by the rmdir(2) system call. Only required if you want ... > @@ -918,6 +922,7 @@ static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); > + Bogus empty line here. > } > > static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, ... > @@ -4313,10 +4314,17 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (max_links && dir->i_nlink >= max_links) > return -EMLINK; > > - error = dir->i_op->mkdir(idmap, dir, dentry, mode); > - if (!error) > + de = dir->i_op->mkdir(idmap, dir, dentry, mode); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) { > + fsnotify_mkdir(dir, de); > + /* Cannot return de yet */ > + dput(de); > + } else > fsnotify_mkdir(dir, dentry); The prefered style is: } else { fsnotify_mkdir(dir, dentry); } Otherwise the patch looks good to me at least for the VFS bits and the filesystems I understand like ext2, ext4, ocfs2, udf. So feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-18 12:20 ` Jan Kara @ 2025-02-18 22:37 ` NeilBrown 0 siblings, 0 replies; 17+ messages in thread From: NeilBrown @ 2025-02-18 22:37 UTC (permalink / raw) To: Jan Kara Cc: Christian Brauner, Alexander Viro, Jan Kara, linux-fsdevel, linux-kernel On Tue, 18 Feb 2025, Jan Kara wrote: > > Otherwise the patch looks good to me at least for the VFS bits and the > filesystems I understand like ext2, ext4, ocfs2, udf. So feel free to add: > > Reviewed-by: Jan Kara <jack@suse.cz> > Thanks. I've made the suggested changes and added the Reviewed-by. NeilBrown ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-17 5:30 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 2025-02-18 12:20 ` Jan Kara @ 2025-02-18 13:13 ` Jeff Layton 2025-02-19 13:19 ` Christian Brauner 2 siblings, 0 replies; 17+ messages in thread From: Jeff Layton @ 2025-02-18 13:13 UTC (permalink / raw) To: NeilBrown, Christian Brauner, Alexander Viro, Jan Kara Cc: linux-fsdevel, linux-kernel On Mon, 2025-02-17 at 16:30 +1100, NeilBrown wrote: > Some filesystems, such as NFS, cifs, ceph, and fuse, do not have > complete control of sequencing on the actual filesystem (e.g. on a > different server) and may find that the inode created for a mkdir > request already exists in the icache and dcache by the time the mkdir > request returns. For example, if the filesystem is mounted twice the > file could be visible on the other mount before it is on the original > mount, and a pair of name_to_handle_at(), open_by_handle_at() could > instantiate the directory inode with an IS_ROOT() dentry before the > first mkdir returns. > > This means that the dentry passed to ->mkdir() may not be the one that > is associated with the inode after the ->mkdir() completes. Some > callers need to interact with the inode after the ->mkdir completes and > they currently need to perform a lookup in the (rare) case that the > dentry is no longer hashed. > > This lookup-after-mkdir requires that the directory remains locked to > avoid races. Planned future patches to lock the dentry rather than the > directory will mean that this lookup cannot be performed atomically with > the mkdir. > > To remove this barrier, this patch changes ->mkdir to return the > resulting dentry if it is different from the one passed in. > Possible returns are: > NULL - the directory was created and no other dentry was used > ERR_PTR() - an error occurred > non-NULL - this other dentry was spliced in > > Not all filesystems reliable result in a positive hashed dentry: > > - NFS does produce the proper dentry, but does not yet return it. The > code change is larger than I wanted to include in this patch To be clear: with this patch and NFS, the only breakage is that you get a fsnotify_mkdir() call with the wrong dentry. > - cifs will, when posix extensions are enabled, unhash the > dentry on success so a subsequent lookup will create it if needed. > - cifs without posix extensions will unhash the dentry if an > internal lookup finds a non-directory where it expected the dir. > - kernfs and tracefs leave the dentry negative and the ->revalidate > operation ensures that lookup will be called to correctly populate > the dentry > - hostfs leaves the dentry negative and uses > .d_delete = always_delete_dentry > so the negative dentry is quickly discarded and a lookup will add a > new entry. > > Signed-off-by: NeilBrown <neilb@suse.de> > --- > Documentation/filesystems/locking.rst | 2 +- > Documentation/filesystems/porting.rst | 11 +++++ > Documentation/filesystems/vfs.rst | 7 +++- > fs/9p/vfs_inode.c | 7 ++-- > fs/9p/vfs_inode_dotl.c | 8 ++-- > fs/affs/affs.h | 2 +- > fs/affs/namei.c | 8 ++-- > fs/afs/dir.c | 12 +++--- > fs/autofs/root.c | 14 +++---- > fs/bad_inode.c | 6 +-- > fs/bcachefs/fs.c | 6 +-- > fs/btrfs/inode.c | 8 ++-- > fs/ceph/dir.c | 15 +++++-- > fs/coda/dir.c | 14 +++---- > fs/configfs/dir.c | 6 +-- > fs/ecryptfs/inode.c | 6 +-- > fs/exfat/namei.c | 8 ++-- > fs/ext2/namei.c | 9 +++-- > fs/ext4/namei.c | 10 ++--- > fs/f2fs/namei.c | 14 +++---- > fs/fat/namei_msdos.c | 8 ++-- > fs/fat/namei_vfat.c | 8 ++-- > fs/fuse/dir.c | 58 +++++++++++++++++---------- > fs/gfs2/inode.c | 9 +++-- > fs/hfs/dir.c | 10 ++--- > fs/hfsplus/dir.c | 6 +-- > fs/hostfs/hostfs_kern.c | 8 ++-- > fs/hpfs/namei.c | 10 ++--- > fs/hugetlbfs/inode.c | 6 +-- > fs/jffs2/dir.c | 18 ++++----- > fs/jfs/namei.c | 8 ++-- > fs/kernfs/dir.c | 12 +++--- > fs/minix/namei.c | 8 ++-- > fs/namei.c | 14 +++++-- > fs/nfs/dir.c | 9 +++-- > fs/nfs/internal.h | 4 +- > fs/nilfs2/namei.c | 8 ++-- > fs/ntfs3/namei.c | 8 ++-- > fs/ocfs2/dlmfs/dlmfs.c | 14 ++++--- > fs/ocfs2/namei.c | 10 ++--- > fs/omfs/dir.c | 6 +-- > fs/orangefs/namei.c | 8 ++-- > fs/overlayfs/dir.c | 9 +++-- > fs/ramfs/inode.c | 6 +-- > fs/smb/client/cifsfs.h | 4 +- > fs/smb/client/inode.c | 10 ++--- > fs/sysv/namei.c | 8 ++-- > fs/tracefs/inode.c | 10 ++--- > fs/ubifs/dir.c | 10 ++--- > fs/udf/namei.c | 12 +++--- > fs/ufs/namei.c | 8 ++-- > fs/vboxsf/dir.c | 8 ++-- > fs/xfs/xfs_iops.c | 4 +- > include/linux/fs.h | 4 +- > kernel/bpf/inode.c | 8 ++-- > mm/shmem.c | 8 ++-- > security/apparmor/apparmorfs.c | 8 ++-- > 57 files changed, 294 insertions(+), 246 deletions(-) > > diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst > index d20a32b77b60..0ec0bb6eb0fb 100644 > --- a/Documentation/filesystems/locking.rst > +++ b/Documentation/filesystems/locking.rst > @@ -66,7 +66,7 @@ prototypes:: > int (*link) (struct dentry *,struct inode *,struct dentry *); > int (*unlink) (struct inode *,struct dentry *); > int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); > - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > int (*rmdir) (struct inode *,struct dentry *); > int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); > int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, > diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst > index 159adb02be52..68938b7ca1ab 100644 > --- a/Documentation/filesystems/porting.rst > +++ b/Documentation/filesystems/porting.rst > @@ -1175,3 +1175,14 @@ lookup_one_qstr_excl() is changed to return errors in some cases: > > LOOKUP_EXCL now means "target must not exist". It can be combined with > LOOK_CREATE or LOOKUP_RENAME_TARGET. > + > +--- > + > +** mandatory** > + > +->mkdir() now returns a 'struct dentry *'. If the created inode is > +found to already be in cache and have a dentry (often IS_ROOT), it will > +need to be spliced into the given name in place of the given dentry. > +That dentry now needs to be returned. If the original dentry is used, > +NULL should be returned. Any error should be returned with > +ERR_PTR(). > diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst > index 31eea688609a..bd3751dfddcf 100644 > --- a/Documentation/filesystems/vfs.rst > +++ b/Documentation/filesystems/vfs.rst > @@ -495,7 +495,7 @@ As of kernel 2.6.22, the following members are defined: > int (*link) (struct dentry *,struct inode *,struct dentry *); > int (*unlink) (struct inode *,struct dentry *); > int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); > - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > int (*rmdir) (struct inode *,struct dentry *); > int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); > int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, > @@ -562,7 +562,10 @@ otherwise noted. > ``mkdir`` > called by the mkdir(2) system call. Only required if you want > to support creating subdirectories. You will probably need to > - call d_instantiate() just as you would in the create() method > + call d_instantiate() just as you would in the create() method. > + If some dentry other than the one given is spliced in, then it > + much be returned, otherwise NULL is returned is the original dentry > + is successfully used, else an ERR_PTR() is returned. > > ``rmdir`` > called by the rmdir(2) system call. Only required if you want > diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c > index 3e68521f4e2f..399d455d50d6 100644 > --- a/fs/9p/vfs_inode.c > +++ b/fs/9p/vfs_inode.c > @@ -669,8 +669,8 @@ v9fs_vfs_create(struct mnt_idmap *idmap, struct inode *dir, > * > */ > > -static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int err; > u32 perm; > @@ -692,8 +692,7 @@ static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > if (fid) > p9_fid_put(fid); > - > - return err; > + return ERR_PTR(err); > } > > /** > diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c > index 143ac03b7425..cc2007be2173 100644 > --- a/fs/9p/vfs_inode_dotl.c > +++ b/fs/9p/vfs_inode_dotl.c > @@ -350,9 +350,9 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, > * > */ > > -static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, > - struct inode *dir, struct dentry *dentry, > - umode_t omode) > +static struct dentry *v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, > + struct inode *dir, struct dentry *dentry, > + umode_t omode) > { > int err; > struct v9fs_session_info *v9ses; > @@ -417,7 +417,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, > p9_fid_put(fid); > v9fs_put_acl(dacl, pacl); > p9_fid_put(dfid); > - return err; > + return ERR_PTR(err); > } > > static int > diff --git a/fs/affs/affs.h b/fs/affs/affs.h > index e8c2c4535cb3..ac4e9a02910b 100644 > --- a/fs/affs/affs.h > +++ b/fs/affs/affs.h > @@ -168,7 +168,7 @@ extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsi > extern int affs_unlink(struct inode *dir, struct dentry *dentry); > extern int affs_create(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode, bool); > -extern int affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > +extern struct dentry *affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode); > extern int affs_rmdir(struct inode *dir, struct dentry *dentry); > extern int affs_link(struct dentry *olddentry, struct inode *dir, > diff --git a/fs/affs/namei.c b/fs/affs/namei.c > index 8c154490a2d6..f883be50db12 100644 > --- a/fs/affs/namei.c > +++ b/fs/affs/namei.c > @@ -273,7 +273,7 @@ affs_create(struct mnt_idmap *idmap, struct inode *dir, > return 0; > } > > -int > +struct dentry * > affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode) > { > @@ -285,7 +285,7 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > inode = affs_new_inode(dir); > if (!inode) > - return -ENOSPC; > + return ERR_PTR(-ENOSPC); > > inode->i_mode = S_IFDIR | mode; > affs_mode_to_prot(inode); > @@ -298,9 +298,9 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > clear_nlink(inode); > mark_inode_dirty(inode); > iput(inode); > - return error; > + return ERR_PTR(error); > } > - return 0; > + return NULL; > } > > int > diff --git a/fs/afs/dir.c b/fs/afs/dir.c > index 02cbf38e1a77..5bddcc20786e 100644 > --- a/fs/afs/dir.c > +++ b/fs/afs/dir.c > @@ -33,8 +33,8 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nl > loff_t fpos, u64 ino, unsigned dtype); > static int afs_create(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode, bool excl); > -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode); > +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode); > static int afs_rmdir(struct inode *dir, struct dentry *dentry); > static int afs_unlink(struct inode *dir, struct dentry *dentry); > static int afs_link(struct dentry *from, struct inode *dir, > @@ -1315,8 +1315,8 @@ static const struct afs_operation_ops afs_mkdir_operation = { > /* > * create a directory on an AFS filesystem > */ > -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct afs_operation *op; > struct afs_vnode *dvnode = AFS_FS_I(dir); > @@ -1328,7 +1328,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > op = afs_alloc_operation(NULL, dvnode->volume); > if (IS_ERR(op)) { > d_drop(dentry); > - return PTR_ERR(op); > + return ERR_CAST(op); > } > > fscache_use_cookie(afs_vnode_cache(dvnode), true); > @@ -1344,7 +1344,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > op->ops = &afs_mkdir_operation; > ret = afs_do_sync_operation(op); > afs_dir_unuse_cookie(dvnode, ret); > - return ret; > + return ERR_PTR(ret); > } > > /* > diff --git a/fs/autofs/root.c b/fs/autofs/root.c > index 530d18827e35..174c7205fee4 100644 > --- a/fs/autofs/root.c > +++ b/fs/autofs/root.c > @@ -15,8 +15,8 @@ static int autofs_dir_symlink(struct mnt_idmap *, struct inode *, > struct dentry *, const char *); > static int autofs_dir_unlink(struct inode *, struct dentry *); > static int autofs_dir_rmdir(struct inode *, struct dentry *); > -static int autofs_dir_mkdir(struct mnt_idmap *, struct inode *, > - struct dentry *, umode_t); > +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *, struct inode *, > + struct dentry *, umode_t); > static long autofs_root_ioctl(struct file *, unsigned int, unsigned long); > #ifdef CONFIG_COMPAT > static long autofs_root_compat_ioctl(struct file *, > @@ -720,9 +720,9 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry) > return 0; > } > > -static int autofs_dir_mkdir(struct mnt_idmap *idmap, > - struct inode *dir, struct dentry *dentry, > - umode_t mode) > +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *idmap, > + struct inode *dir, struct dentry *dentry, > + umode_t mode) > { > struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); > struct autofs_info *ino = autofs_dentry_ino(dentry); > @@ -739,7 +739,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, > > inode = autofs_get_inode(dir->i_sb, S_IFDIR | mode); > if (!inode) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > d_add(dentry, inode); > > if (sbi->version < 5) > @@ -751,7 +751,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, > inc_nlink(dir); > inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); > > - return 0; > + return NULL; > } > > /* Get/set timeout ioctl() operation */ > diff --git a/fs/bad_inode.c b/fs/bad_inode.c > index 316d88da2ce1..0ef9bcb744dd 100644 > --- a/fs/bad_inode.c > +++ b/fs/bad_inode.c > @@ -58,10 +58,10 @@ static int bad_inode_symlink(struct mnt_idmap *idmap, > return -EIO; > } > > -static int bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return -EIO; > + return ERR_PTR(-EIO); > } > > static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) > diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c > index 90ade8f648d9..1c94a680fcce 100644 > --- a/fs/bcachefs/fs.c > +++ b/fs/bcachefs/fs.c > @@ -858,10 +858,10 @@ static int bch2_symlink(struct mnt_idmap *idmap, > return bch2_err_class(ret); > } > > -static int bch2_mkdir(struct mnt_idmap *idmap, > - struct inode *vdir, struct dentry *dentry, umode_t mode) > +static struct dentry *bch2_mkdir(struct mnt_idmap *idmap, > + struct inode *vdir, struct dentry *dentry, umode_t mode) > { > - return bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0); > + return ERR_PTR(bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0)); > } > > static int bch2_rename2(struct mnt_idmap *idmap, > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c > index a9322601ab5c..851d3e8a06a7 100644 > --- a/fs/btrfs/inode.c > +++ b/fs/btrfs/inode.c > @@ -6739,18 +6739,18 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, > return err; > } > > -static int btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > > inode = new_inode(dir->i_sb); > if (!inode) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > inode_init_owner(idmap, inode, dir, S_IFDIR | mode); > inode->i_op = &btrfs_dir_inode_operations; > inode->i_fop = &btrfs_dir_file_operations; > - return btrfs_create_common(dir, dentry, inode); > + return ERR_PTR(btrfs_create_common(dir, dentry, inode)); > } > > static noinline int uncompress_inline(struct btrfs_path *path, > diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c > index 62e99e65250d..c1a1c168bb27 100644 > --- a/fs/ceph/dir.c > +++ b/fs/ceph/dir.c > @@ -1092,19 +1092,20 @@ static int ceph_symlink(struct mnt_idmap *idmap, struct inode *dir, > return err; > } > > -static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb); > struct ceph_client *cl = mdsc->fsc->client; > struct ceph_mds_request *req; > struct ceph_acl_sec_ctx as_ctx = {}; > + struct dentry *ret = NULL; > int err; > int op; > > err = ceph_wait_on_conflict_unlink(dentry); > if (err) > - return err; > + return ERR_PTR(err); > > if (ceph_snap(dir) == CEPH_SNAPDIR) { > /* mkdir .snap/foo is a MKSNAP */ > @@ -1166,14 +1167,20 @@ static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, > !req->r_reply_info.head->is_dentry) > err = ceph_handle_notrace_create(dir, dentry); > out_req: > + if (!err && req->r_dentry != dentry) > + /* Some other dentry was spliced in */ > + ret = dget(req->r_dentry); > ceph_mdsc_put_request(req); > out: > if (!err) > + /* Should this use 'ret' ?? */ > ceph_init_inode_acls(d_inode(dentry), &as_ctx); > else > d_drop(dentry); > ceph_release_acl_sec_ctx(&as_ctx); > - return err; > + if (err) > + return ERR_PTR(err); > + return ret; > } > > static int ceph_link(struct dentry *old_dentry, struct inode *dir, > diff --git a/fs/coda/dir.c b/fs/coda/dir.c > index a3e2dfeedfbf..ab69d8f0cec2 100644 > --- a/fs/coda/dir.c > +++ b/fs/coda/dir.c > @@ -166,8 +166,8 @@ static int coda_create(struct mnt_idmap *idmap, struct inode *dir, > return error; > } > > -static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *de, umode_t mode) > +static struct dentry *coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *de, umode_t mode) > { > struct inode *inode; > struct coda_vattr attrs; > @@ -177,14 +177,14 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > struct CodaFid newfid; > > if (is_root_inode(dir) && coda_iscontrol(name, len)) > - return -EPERM; > + return ERR_PTR(-EPERM); > > attrs.va_mode = mode; > - error = venus_mkdir(dir->i_sb, coda_i2f(dir), > + error = venus_mkdir(dir->i_sb, coda_i2f(dir), > name, len, &newfid, &attrs); > if (error) > goto err_out; > - > + > inode = coda_iget(dir->i_sb, &newfid, &attrs); > if (IS_ERR(inode)) { > error = PTR_ERR(inode); > @@ -195,10 +195,10 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > coda_dir_inc_nlink(dir); > coda_dir_update_mtime(dir); > d_instantiate(de, inode); > - return 0; > + return NULL; > err_out: > d_drop(de); > - return error; > + return ERR_PTR(error); > } > > /* try to make de an entry in dir_inodde linked to source_de */ > diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c > index 7d10278db30d..5568cb74b322 100644 > --- a/fs/configfs/dir.c > +++ b/fs/configfs/dir.c > @@ -1280,8 +1280,8 @@ int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys, > } > EXPORT_SYMBOL(configfs_depend_item_unlocked); > > -static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int ret = 0; > int module_got = 0; > @@ -1461,7 +1461,7 @@ static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > put_fragment(frag); > > out: > - return ret; > + return ERR_PTR(ret); > } > > static int configfs_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c > index a9819ddb1ab8..6315dd194228 100644 > --- a/fs/ecryptfs/inode.c > +++ b/fs/ecryptfs/inode.c > @@ -503,8 +503,8 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap, > return rc; > } > > -static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int rc; > struct dentry *lower_dentry; > @@ -526,7 +526,7 @@ static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > inode_unlock(lower_dir); > if (d_really_is_negative(dentry)) > d_drop(dentry); > - return rc; > + return ERR_PTR(rc); > } > > static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c > index 691dd77b6ab5..1660c9bbcfa9 100644 > --- a/fs/exfat/namei.c > +++ b/fs/exfat/namei.c > @@ -835,8 +835,8 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) > return err; > } > > -static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct super_block *sb = dir->i_sb; > struct inode *inode; > @@ -846,7 +846,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > loff_t size = i_size_read(dir); > > if (unlikely(exfat_forced_shutdown(sb))) > - return -EIO; > + return ERR_PTR(-EIO); > > mutex_lock(&EXFAT_SB(sb)->s_lock); > exfat_set_volume_dirty(sb); > @@ -877,7 +877,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > unlock: > mutex_unlock(&EXFAT_SB(sb)->s_lock); > - return err; > + return ERR_PTR(err); > } > > static int exfat_check_dir_empty(struct super_block *sb, > diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c > index 8346ab9534c1..bde617a66cec 100644 > --- a/fs/ext2/namei.c > +++ b/fs/ext2/namei.c > @@ -225,15 +225,16 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, > return err; > } > > -static int ext2_mkdir(struct mnt_idmap * idmap, > - struct inode * dir, struct dentry * dentry, umode_t mode) > +static struct dentry *ext2_mkdir(struct mnt_idmap * idmap, > + struct inode * dir, struct dentry * dentry, > + umode_t mode) > { > struct inode * inode; > int err; > > err = dquot_initialize(dir); > if (err) > - return err; > + return ERR_PTR(err); > > inode_inc_link_count(dir); > > @@ -258,7 +259,7 @@ static int ext2_mkdir(struct mnt_idmap * idmap, > > d_instantiate_new(dentry, inode); > out: > - return err; > + return ERR_PTR(err); > > out_fail: > inode_dec_link_count(inode); > diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c > index 536d56d15072..716cc6096870 100644 > --- a/fs/ext4/namei.c > +++ b/fs/ext4/namei.c > @@ -3004,19 +3004,19 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, > return err; > } > > -static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > handle_t *handle; > struct inode *inode; > int err, err2 = 0, credits, retries = 0; > > if (EXT4_DIR_LINK_MAX(dir)) > - return -EMLINK; > + return ERR_PTR(-EMLINK); > > err = dquot_initialize(dir); > if (err) > - return err; > + return ERR_PTR(err); > > credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + > EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); > @@ -3066,7 +3066,7 @@ static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, > out_retry: > if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) > goto retry; > - return err; > + return ERR_PTR(err); > } > > /* > diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c > index a278c7da8177..24dca4dc85a9 100644 > --- a/fs/f2fs/namei.c > +++ b/fs/f2fs/namei.c > @@ -684,23 +684,23 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir, > return err; > } > > -static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct f2fs_sb_info *sbi = F2FS_I_SB(dir); > struct inode *inode; > int err; > > if (unlikely(f2fs_cp_error(sbi))) > - return -EIO; > + return ERR_PTR(-EIO); > > err = f2fs_dquot_initialize(dir); > if (err) > - return err; > + return ERR_PTR(err); > > inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > inode->i_op = &f2fs_dir_inode_operations; > inode->i_fop = &f2fs_dir_operations; > @@ -722,12 +722,12 @@ static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > f2fs_sync_fs(sbi->sb, 1); > > f2fs_balance_fs(sbi, true); > - return 0; > + return NULL; > > out_fail: > clear_inode_flag(inode, FI_INC_LINK); > f2fs_handle_failed_inode(inode); > - return err; > + return ERR_PTR(err); > } > > static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c > index f06f6ba643cc..23e9b9371ec3 100644 > --- a/fs/fat/namei_msdos.c > +++ b/fs/fat/namei_msdos.c > @@ -339,8 +339,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) > } > > /***** Make a directory */ > -static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct super_block *sb = dir->i_sb; > struct fat_slot_info sinfo; > @@ -389,13 +389,13 @@ static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > mutex_unlock(&MSDOS_SB(sb)->s_lock); > fat_flush_inodes(sb, dir, inode); > - return 0; > + return NULL; > > out_free: > fat_free_clusters(dir, cluster); > out: > mutex_unlock(&MSDOS_SB(sb)->s_lock); > - return err; > + return ERR_PTR(err); > } > > /***** Unlink a file */ > diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c > index 926c26e90ef8..dd910edd2404 100644 > --- a/fs/fat/namei_vfat.c > +++ b/fs/fat/namei_vfat.c > @@ -841,8 +841,8 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) > return err; > } > > -static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct super_block *sb = dir->i_sb; > struct inode *inode; > @@ -877,13 +877,13 @@ static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > d_instantiate(dentry, inode); > > mutex_unlock(&MSDOS_SB(sb)->s_lock); > - return 0; > + return NULL; > > out_free: > fat_free_clusters(dir, cluster); > out: > mutex_unlock(&MSDOS_SB(sb)->s_lock); > - return err; > + return ERR_PTR(err); > } > > static int vfat_get_dotdot_de(struct inode *inode, struct buffer_head **bh, > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index 198862b086ff..2537eefcd023 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -781,9 +781,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, > /* > * Code shared between mknod, mkdir, symlink and link > */ > -static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > - struct fuse_args *args, struct inode *dir, > - struct dentry *entry, umode_t mode) > +static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > + struct fuse_args *args, struct inode *dir, > + struct dentry *entry, umode_t mode) > { > struct fuse_entry_out outarg; > struct inode *inode; > @@ -792,11 +792,11 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > struct fuse_forget_link *forget; > > if (fuse_is_bad(dir)) > - return -EIO; > + return ERR_PTR(-EIO); > > forget = fuse_alloc_forget(); > if (!forget) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > memset(&outarg, 0, sizeof(outarg)); > args->nodeid = get_node_id(dir); > @@ -826,29 +826,27 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); > if (!inode) { > fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > } > kfree(forget); > > d_drop(entry); > d = d_splice_alias(inode, entry); > if (IS_ERR(d)) > - return PTR_ERR(d); > + return d; > > - if (d) { > + if (d) > fuse_change_entry_timeout(d, &outarg); > - dput(d); > - } else { > + else > fuse_change_entry_timeout(entry, &outarg); > - } > fuse_dir_changed(dir); > - return 0; > + return d; > > out_put_forget_req: > if (err == -EEXIST) > fuse_invalidate_entry(entry); > kfree(forget); > - return err; > + return ERR_PTR(err); > } > > static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > @@ -856,6 +854,7 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > { > struct fuse_mknod_in inarg; > struct fuse_mount *fm = get_fuse_mount(dir); > + struct dentry *de; > FUSE_ARGS(args); > > if (!fm->fc->dont_mask) > @@ -871,7 +870,12 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[0].value = &inarg; > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > - return create_new_entry(idmap, fm, &args, dir, entry, mode); > + de = create_new_entry(idmap, fm, &args, dir, entry, mode); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) > + dput(de); > + return 0; > } > > static int fuse_create(struct mnt_idmap *idmap, struct inode *dir, > @@ -898,8 +902,8 @@ static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir, > return err; > } > > -static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *entry, umode_t mode) > +static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *entry, umode_t mode) > { > struct fuse_mkdir_in inarg; > struct fuse_mount *fm = get_fuse_mount(dir); > @@ -918,6 +922,7 @@ static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); > + > } > > static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > @@ -925,6 +930,7 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > { > struct fuse_mount *fm = get_fuse_mount(dir); > unsigned len = strlen(link) + 1; > + struct dentry *de; > FUSE_ARGS(args); > > args.opcode = FUSE_SYMLINK; > @@ -934,7 +940,12 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[1].value = entry->d_name.name; > args.in_args[2].size = len; > args.in_args[2].value = link; > - return create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); > + de = create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) > + dput(de); > + return 0; > } > > void fuse_flush_time_update(struct inode *inode) > @@ -1117,7 +1128,7 @@ static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir, > static int fuse_link(struct dentry *entry, struct inode *newdir, > struct dentry *newent) > { > - int err; > + struct dentry *de; > struct fuse_link_in inarg; > struct inode *inode = d_inode(entry); > struct fuse_mount *fm = get_fuse_mount(inode); > @@ -1131,13 +1142,16 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, > args.in_args[0].value = &inarg; > args.in_args[1].size = newent->d_name.len + 1; > args.in_args[1].value = newent->d_name.name; > - err = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); > - if (!err) > + de = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); > + if (!IS_ERR(de)) { > + if (de) > + dput(de); > + de = NULL; > fuse_update_ctime_in_cache(inode); > - else if (err == -EINTR) > + } else if (PTR_ERR(de) == -EINTR) > fuse_invalidate_attr(inode); > > - return err; > + return PTR_ERR(de); > } > > static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode, > diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c > index 6fbbaaad1cd0..198a8cbaf5e5 100644 > --- a/fs/gfs2/inode.c > +++ b/fs/gfs2/inode.c > @@ -1248,14 +1248,15 @@ static int gfs2_symlink(struct mnt_idmap *idmap, struct inode *dir, > * @dentry: The dentry of the new directory > * @mode: The mode of the new directory > * > - * Returns: errno > + * Returns: the dentry, or ERR_PTR(errno) > */ > > -static int gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > unsigned dsize = gfs2_max_stuffed_size(GFS2_I(dir)); > - return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0); > + > + return ERR_PTR(gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0)); > } > > /** > diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c > index b75c26045df4..86a6b317b474 100644 > --- a/fs/hfs/dir.c > +++ b/fs/hfs/dir.c > @@ -219,26 +219,26 @@ static int hfs_create(struct mnt_idmap *idmap, struct inode *dir, > * in a directory, given the inode for the parent directory and the > * name (and its length) of the new directory. > */ > -static int hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > int res; > > inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); > if (!inode) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); > if (res) { > clear_nlink(inode); > hfs_delete_inode(inode); > iput(inode); > - return res; > + return ERR_PTR(res); > } > d_instantiate(dentry, inode); > mark_inode_dirty(inode); > - return 0; > + return NULL; > } > > /* > diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c > index f5c4b3e31a1c..876bbb80fb4d 100644 > --- a/fs/hfsplus/dir.c > +++ b/fs/hfsplus/dir.c > @@ -523,10 +523,10 @@ static int hfsplus_create(struct mnt_idmap *idmap, struct inode *dir, > return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode, 0); > } > > -static int hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); > + return ERR_PTR(hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0)); > } > > static int hfsplus_rename(struct mnt_idmap *idmap, > diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c > index e0741e468956..ccbb48fe830d 100644 > --- a/fs/hostfs/hostfs_kern.c > +++ b/fs/hostfs/hostfs_kern.c > @@ -679,17 +679,17 @@ static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino, > return err; > } > > -static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, > + struct dentry *dentry, umode_t mode) > { > char *file; > int err; > > if ((file = dentry_name(dentry)) == NULL) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > err = do_mkdir(file, mode); > __putname(file); > - return err; > + return ERR_PTR(err); > } > > static int hostfs_rmdir(struct inode *ino, struct dentry *dentry) > diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c > index d0edf9ed33b6..e3cdc421dfba 100644 > --- a/fs/hpfs/namei.c > +++ b/fs/hpfs/namei.c > @@ -19,8 +19,8 @@ static void hpfs_update_directory_times(struct inode *dir) > hpfs_write_inode_nolock(dir); > } > > -static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > const unsigned char *name = dentry->d_name.name; > unsigned len = dentry->d_name.len; > @@ -35,7 +35,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > int r; > struct hpfs_dirent dee; > int err; > - if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; > + if ((err = hpfs_chk_name(name, &len))) return ERR_PTR(err==-ENOENT ? -EINVAL : err); > hpfs_lock(dir->i_sb); > err = -ENOSPC; > fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); > @@ -112,7 +112,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > hpfs_update_directory_times(dir); > d_instantiate(dentry, result); > hpfs_unlock(dir->i_sb); > - return 0; > + return NULL; > bail3: > iput(result); > bail2: > @@ -123,7 +123,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > hpfs_free_sectors(dir->i_sb, fno, 1); > bail: > hpfs_unlock(dir->i_sb); > - return err; > + return ERR_PTR(err); > } > > static int hpfs_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c > index 0fc179a59830..d98caedbb723 100644 > --- a/fs/hugetlbfs/inode.c > +++ b/fs/hugetlbfs/inode.c > @@ -991,14 +991,14 @@ static int hugetlbfs_mknod(struct mnt_idmap *idmap, struct inode *dir, > return 0; > } > > -static int hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int retval = hugetlbfs_mknod(idmap, dir, dentry, > mode | S_IFDIR, 0); > if (!retval) > inc_nlink(dir); > - return retval; > + return ERR_PTR(retval); > } > > static int hugetlbfs_create(struct mnt_idmap *idmap, > diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c > index 2b2938970da3..dd91f725ded6 100644 > --- a/fs/jffs2/dir.c > +++ b/fs/jffs2/dir.c > @@ -32,8 +32,8 @@ static int jffs2_link (struct dentry *,struct inode *,struct dentry *); > static int jffs2_unlink (struct inode *,struct dentry *); > static int jffs2_symlink (struct mnt_idmap *, struct inode *, > struct dentry *, const char *); > -static int jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, > - umode_t); > +static struct dentry *jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, > + umode_t); > static int jffs2_rmdir (struct inode *,struct dentry *); > static int jffs2_mknod (struct mnt_idmap *, struct inode *,struct dentry *, > umode_t,dev_t); > @@ -446,8 +446,8 @@ static int jffs2_symlink (struct mnt_idmap *idmap, struct inode *dir_i, > } > > > -static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > - struct dentry *dentry, umode_t mode) > +static struct dentry *jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > + struct dentry *dentry, umode_t mode) > { > struct jffs2_inode_info *f, *dir_f; > struct jffs2_sb_info *c; > @@ -464,7 +464,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > > ri = jffs2_alloc_raw_inode(); > if (!ri) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > c = JFFS2_SB_INFO(dir_i->i_sb); > > @@ -477,7 +477,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > > if (ret) { > jffs2_free_raw_inode(ri); > - return ret; > + return ERR_PTR(ret); > } > > inode = jffs2_new_inode(dir_i, mode, ri); > @@ -485,7 +485,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > if (IS_ERR(inode)) { > jffs2_free_raw_inode(ri); > jffs2_complete_reservation(c); > - return PTR_ERR(inode); > + return ERR_CAST(inode); > } > > inode->i_op = &jffs2_dir_inode_operations; > @@ -584,11 +584,11 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > jffs2_complete_reservation(c); > > d_instantiate_new(dentry, inode); > - return 0; > + return NULL; > > fail: > iget_failed(inode); > - return ret; > + return ERR_PTR(ret); > } > > static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) > diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c > index fc8ede43afde..65a218eba8fa 100644 > --- a/fs/jfs/namei.c > +++ b/fs/jfs/namei.c > @@ -187,13 +187,13 @@ static int jfs_create(struct mnt_idmap *idmap, struct inode *dip, > * dentry - dentry of child directory > * mode - create mode (rwxrwxrwx). > * > - * RETURN: Errors from subroutines > + * RETURN: ERR_PTR() of errors from subroutines. > * > * note: > * EACCES: user needs search+write permission on the parent directory > */ > -static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, > - struct dentry *dentry, umode_t mode) > +static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, > + struct dentry *dentry, umode_t mode) > { > int rc = 0; > tid_t tid; /* transaction id */ > @@ -308,7 +308,7 @@ static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, > out1: > > jfs_info("jfs_mkdir: rc:%d", rc); > - return rc; > + return ERR_PTR(rc); > } > > /* > diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c > index 5f0f8b95f44c..d296aad70800 100644 > --- a/fs/kernfs/dir.c > +++ b/fs/kernfs/dir.c > @@ -1230,24 +1230,24 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, > return d_splice_alias(inode, dentry); > } > > -static int kernfs_iop_mkdir(struct mnt_idmap *idmap, > - struct inode *dir, struct dentry *dentry, > - umode_t mode) > +static struct dentry *kernfs_iop_mkdir(struct mnt_idmap *idmap, > + struct inode *dir, struct dentry *dentry, > + umode_t mode) > { > struct kernfs_node *parent = dir->i_private; > struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops; > int ret; > > if (!scops || !scops->mkdir) > - return -EPERM; > + return ERR_PTR(-EPERM); > > if (!kernfs_get_active(parent)) > - return -ENODEV; > + return ERR_PTR(-ENODEV); > > ret = scops->mkdir(parent, dentry->d_name.name, mode); > > kernfs_put_active(parent); > - return ret; > + return ERR_PTR(ret); > } > > static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/minix/namei.c b/fs/minix/namei.c > index 5d9c1406fe27..8938536d8d3c 100644 > --- a/fs/minix/namei.c > +++ b/fs/minix/namei.c > @@ -104,15 +104,15 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, > return add_nondir(dentry, inode); > } > > -static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode * inode; > int err; > > inode = minix_new_inode(dir, S_IFDIR | mode); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > inode_inc_link_count(dir); > minix_set_inode(inode, 0); > @@ -128,7 +128,7 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > d_instantiate(dentry, inode); > out: > - return err; > + return ERR_PTR(err); > > out_fail: > inode_dec_link_count(inode); > diff --git a/fs/namei.c b/fs/namei.c > index 865a009fdebc..19d5ea340a18 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -4297,6 +4297,7 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > { > int error; > unsigned max_links = dir->i_sb->s_max_links; > + struct dentry *de; > > error = may_create(idmap, dir, dentry); > if (error) > @@ -4313,10 +4314,17 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (max_links && dir->i_nlink >= max_links) > return -EMLINK; > > - error = dir->i_op->mkdir(idmap, dir, dentry, mode); > - if (!error) > + de = dir->i_op->mkdir(idmap, dir, dentry, mode); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) { > + fsnotify_mkdir(dir, de); > + /* Cannot return de yet */ > + dput(de); > + } else > fsnotify_mkdir(dir, dentry); > - return error; > + > + return 0; > } > EXPORT_SYMBOL(vfs_mkdir); > > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c > index 56cf16a72334..5700f73d48bc 100644 > --- a/fs/nfs/dir.c > +++ b/fs/nfs/dir.c > @@ -2422,8 +2422,8 @@ EXPORT_SYMBOL_GPL(nfs_mknod); > /* > * See comments for nfs_proc_create regarding failed operations. > */ > -int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct iattr attr; > int error; > @@ -2439,10 +2439,11 @@ int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > trace_nfs_mkdir_exit(dir, dentry, error); > if (error != 0) > goto out_err; > - return 0; > + /* FIXME - ->mkdir might have used an alternate dentry */ > + return NULL; > out_err: > d_drop(dentry); > - return error; > + return ERR_PTR(error); > } > EXPORT_SYMBOL_GPL(nfs_mkdir); > > diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h > index fae2c7ae4acc..1ac1d3eec517 100644 > --- a/fs/nfs/internal.h > +++ b/fs/nfs/internal.h > @@ -400,8 +400,8 @@ struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); > void nfs_d_prune_case_insensitive_aliases(struct inode *inode); > int nfs_create(struct mnt_idmap *, struct inode *, struct dentry *, > umode_t, bool); > -int nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > - umode_t); > +struct dentry *nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > + umode_t); > int nfs_rmdir(struct inode *, struct dentry *); > int nfs_unlink(struct inode *, struct dentry *); > int nfs_symlink(struct mnt_idmap *, struct inode *, struct dentry *, > diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c > index 953fbd5f0851..40f4b1a28705 100644 > --- a/fs/nilfs2/namei.c > +++ b/fs/nilfs2/namei.c > @@ -218,8 +218,8 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, > return err; > } > > -static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > struct nilfs_transaction_info ti; > @@ -227,7 +227,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > err = nilfs_transaction_begin(dir->i_sb, &ti, 1); > if (err) > - return err; > + return ERR_PTR(err); > > inc_nlink(dir); > > @@ -258,7 +258,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > else > nilfs_transaction_abort(dir->i_sb); > > - return err; > + return ERR_PTR(err); > > out_fail: > drop_nlink(inode); > diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c > index abf7e81584a9..652735a0b0c4 100644 > --- a/fs/ntfs3/namei.c > +++ b/fs/ntfs3/namei.c > @@ -201,11 +201,11 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, > /* > * ntfs_mkdir- inode_operations::mkdir > */ > -static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, > - NULL, 0, NULL); > + return ERR_PTR(ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, > + NULL, 0, NULL)); > } > > /* > diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c > index 2a7f36643895..f632fbfe59e8 100644 > --- a/fs/ocfs2/dlmfs/dlmfs.c > +++ b/fs/ocfs2/dlmfs/dlmfs.c > @@ -402,10 +402,10 @@ static struct inode *dlmfs_get_inode(struct inode *parent, > * File creation. Allocate an inode, and we're done.. > */ > /* SMP-safe */ > -static int dlmfs_mkdir(struct mnt_idmap * idmap, > - struct inode * dir, > - struct dentry * dentry, > - umode_t mode) > +static struct dentry *dlmfs_mkdir(struct mnt_idmap * idmap, > + struct inode * dir, > + struct dentry * dentry, > + umode_t mode) > { > int status; > struct inode *inode = NULL; > @@ -446,9 +446,11 @@ static int dlmfs_mkdir(struct mnt_idmap * idmap, > > status = 0; > bail: > - if (status < 0) > + if (status < 0) { > iput(inode); > - return status; > + return ERR_PTR(status); > + } > + return NULL; > } > > static int dlmfs_create(struct mnt_idmap *idmap, > diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c > index 0ec63a1a94b8..99278c8f0e24 100644 > --- a/fs/ocfs2/namei.c > +++ b/fs/ocfs2/namei.c > @@ -644,10 +644,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, > suballoc_loc, suballoc_bit); > } > > -static int ocfs2_mkdir(struct mnt_idmap *idmap, > - struct inode *dir, > - struct dentry *dentry, > - umode_t mode) > +static struct dentry *ocfs2_mkdir(struct mnt_idmap *idmap, > + struct inode *dir, > + struct dentry *dentry, > + umode_t mode) > { > int ret; > > @@ -657,7 +657,7 @@ static int ocfs2_mkdir(struct mnt_idmap *idmap, > if (ret) > mlog_errno(ret); > > - return ret; > + return ERR_PTR(ret); > } > > static int ocfs2_create(struct mnt_idmap *idmap, > diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c > index 6bda275826d6..2ed541fccf33 100644 > --- a/fs/omfs/dir.c > +++ b/fs/omfs/dir.c > @@ -279,10 +279,10 @@ static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) > return err; > } > > -static int omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return omfs_add_node(dir, dentry, mode | S_IFDIR); > + return ERR_PTR(omfs_add_node(dir, dentry, mode | S_IFDIR)); > } > > static int omfs_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c > index 200558ec72f0..82395fe2b956 100644 > --- a/fs/orangefs/namei.c > +++ b/fs/orangefs/namei.c > @@ -300,8 +300,8 @@ static int orangefs_symlink(struct mnt_idmap *idmap, > return ret; > } > > -static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct orangefs_inode_s *parent = ORANGEFS_I(dir); > struct orangefs_kernel_op_s *new_op; > @@ -312,7 +312,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR); > if (!new_op) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > new_op->upcall.req.mkdir.parent_refn = parent->refn; > > @@ -366,7 +366,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > __orangefs_setattr(dir, &iattr); > out: > op_release(new_op); > - return ret; > + return ERR_PTR(ret); > } > > static int orangefs_rename(struct mnt_idmap *idmap, > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c > index c9993ff66fc2..21c3aaf7b274 100644 > --- a/fs/overlayfs/dir.c > +++ b/fs/overlayfs/dir.c > @@ -282,7 +282,8 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, > * XXX: if we ever use ovl_obtain_alias() to decode directory > * file handles, need to use ovl_get_inode_locked() and > * d_instantiate_new() here to prevent from creating two > - * hashed directory inode aliases. > + * hashed directory inode aliases. We then need to return > + * the obtained alias to ovl_mkdir(). > */ > inode = ovl_get_inode(dentry->d_sb, &oip); > if (IS_ERR(inode)) > @@ -687,10 +688,10 @@ static int ovl_create(struct mnt_idmap *idmap, struct inode *dir, > return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); > } > > -static int ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); > + return ERR_PTR(ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL)); > } > > static int ovl_mknod(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c > index 8006faaaf0ec..775fa905fda0 100644 > --- a/fs/ramfs/inode.c > +++ b/fs/ramfs/inode.c > @@ -119,13 +119,13 @@ ramfs_mknod(struct mnt_idmap *idmap, struct inode *dir, > return error; > } > > -static int ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int retval = ramfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); > if (!retval) > inc_nlink(dir); > - return retval; > + return ERR_PTR(retval); > } > > static int ramfs_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h > index 831fee962c4d..8dea0cf3a8de 100644 > --- a/fs/smb/client/cifsfs.h > +++ b/fs/smb/client/cifsfs.h > @@ -59,8 +59,8 @@ extern int cifs_unlink(struct inode *dir, struct dentry *dentry); > extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); > extern int cifs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, > umode_t, dev_t); > -extern int cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > - umode_t); > +extern struct dentry *cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > + umode_t); > extern int cifs_rmdir(struct inode *, struct dentry *); > extern int cifs_rename2(struct mnt_idmap *, struct inode *, > struct dentry *, struct inode *, struct dentry *, > diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c > index 9cc31cf6ebd0..685a176f7f7e 100644 > --- a/fs/smb/client/inode.c > +++ b/fs/smb/client/inode.c > @@ -2194,8 +2194,8 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, > } > #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ > > -int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > - struct dentry *direntry, umode_t mode) > +struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > + struct dentry *direntry, umode_t mode) > { > int rc = 0; > unsigned int xid; > @@ -2211,10 +2211,10 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > > cifs_sb = CIFS_SB(inode->i_sb); > if (unlikely(cifs_forced_shutdown(cifs_sb))) > - return -EIO; > + return ERR_PTR(-EIO); > tlink = cifs_sb_tlink(cifs_sb); > if (IS_ERR(tlink)) > - return PTR_ERR(tlink); > + return ERR_CAST(tlink); > tcon = tlink_tcon(tlink); > > xid = get_xid(); > @@ -2270,7 +2270,7 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > free_dentry_path(page); > free_xid(xid); > cifs_put_tlink(tlink); > - return rc; > + return ERR_PTR(rc); > } > > int cifs_rmdir(struct inode *inode, struct dentry *direntry) > diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c > index fb8bd8437872..ba037727c1e6 100644 > --- a/fs/sysv/namei.c > +++ b/fs/sysv/namei.c > @@ -110,8 +110,8 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, > return add_nondir(dentry, inode); > } > > -static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode * inode; > int err; > @@ -135,9 +135,9 @@ static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (err) > goto out_fail; > > - d_instantiate(dentry, inode); > + d_instantiate(dentry, inode); > out: > - return err; > + return ERR_PTR(err); > > out_fail: > inode_dec_link_count(inode); > diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c > index 53214499e384..cb1af30b49f5 100644 > --- a/fs/tracefs/inode.c > +++ b/fs/tracefs/inode.c > @@ -109,9 +109,9 @@ static char *get_dname(struct dentry *dentry) > return name; > } > > -static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, > - struct inode *inode, struct dentry *dentry, > - umode_t mode) > +static struct dentry *tracefs_syscall_mkdir(struct mnt_idmap *idmap, > + struct inode *inode, struct dentry *dentry, > + umode_t mode) > { > struct tracefs_inode *ti; > char *name; > @@ -119,7 +119,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, > > name = get_dname(dentry); > if (!name) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > /* > * This is a new directory that does not take the default of > @@ -141,7 +141,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, > > kfree(name); > > - return ret; > + return ERR_PTR(ret); > } > > static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) > diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c > index fda82f3e16e8..3c3d3ad4fa6c 100644 > --- a/fs/ubifs/dir.c > +++ b/fs/ubifs/dir.c > @@ -1002,8 +1002,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) > return err; > } > > -static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > struct ubifs_inode *dir_ui = ubifs_inode(dir); > @@ -1023,7 +1023,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > err = ubifs_budget_space(c, &req); > if (err) > - return err; > + return ERR_PTR(err); > > err = ubifs_prepare_create(dir, dentry, &nm); > if (err) > @@ -1060,7 +1060,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > ubifs_release_budget(c, &req); > d_instantiate(dentry, inode); > fscrypt_free_filename(&nm); > - return 0; > + return NULL; > > out_cancel: > dir->i_size -= sz_change; > @@ -1074,7 +1074,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > fscrypt_free_filename(&nm); > out_budg: > ubifs_release_budget(c, &req); > - return err; > + return ERR_PTR(err); > } > > static int ubifs_mknod(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/udf/namei.c b/fs/udf/namei.c > index 2cb49b6b0716..5f2e9a892bff 100644 > --- a/fs/udf/namei.c > +++ b/fs/udf/namei.c > @@ -419,8 +419,8 @@ static int udf_mknod(struct mnt_idmap *idmap, struct inode *dir, > return udf_add_nondir(dentry, inode); > } > > -static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > struct udf_fileident_iter iter; > @@ -430,7 +430,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > inode = udf_new_inode(dir, S_IFDIR | mode); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > iinfo = UDF_I(inode); > inode->i_op = &udf_dir_inode_operations; > @@ -439,7 +439,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (err) { > clear_nlink(inode); > discard_new_inode(inode); > - return err; > + return ERR_PTR(err); > } > set_nlink(inode, 2); > iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); > @@ -456,7 +456,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (err) { > clear_nlink(inode); > discard_new_inode(inode); > - return err; > + return ERR_PTR(err); > } > iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); > iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location); > @@ -471,7 +471,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > mark_inode_dirty(dir); > d_instantiate_new(dentry, inode); > > - return 0; > + return NULL; > } > > static int empty_dir(struct inode *dir) > diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c > index 38a024c8cccd..5b3c85c93242 100644 > --- a/fs/ufs/namei.c > +++ b/fs/ufs/namei.c > @@ -166,8 +166,8 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, > return error; > } > > -static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > - struct dentry * dentry, umode_t mode) > +static struct dentry *ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > + struct dentry * dentry, umode_t mode) > { > struct inode * inode; > int err; > @@ -194,7 +194,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > goto out_fail; > > d_instantiate_new(dentry, inode); > - return 0; > + return NULL; > > out_fail: > inode_dec_link_count(inode); > @@ -202,7 +202,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > discard_new_inode(inode); > out_dir: > inode_dec_link_count(dir); > - return err; > + return ERR_PTR(err); > } > > static int ufs_unlink(struct inode *dir, struct dentry *dentry) > diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c > index a859ac9b74ba..770e29ec3557 100644 > --- a/fs/vboxsf/dir.c > +++ b/fs/vboxsf/dir.c > @@ -303,11 +303,11 @@ static int vboxsf_dir_mkfile(struct mnt_idmap *idmap, > return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL); > } > > -static int vboxsf_dir_mkdir(struct mnt_idmap *idmap, > - struct inode *parent, struct dentry *dentry, > - umode_t mode) > +static struct dentry *vboxsf_dir_mkdir(struct mnt_idmap *idmap, > + struct inode *parent, struct dentry *dentry, > + umode_t mode) > { > - return vboxsf_dir_create(parent, dentry, mode, true, true, NULL); > + return ERR_PTR(vboxsf_dir_create(parent, dentry, mode, true, true, NULL)); > } > > static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry, > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c > index 40289fe6f5b2..a4480098d2bf 100644 > --- a/fs/xfs/xfs_iops.c > +++ b/fs/xfs/xfs_iops.c > @@ -298,14 +298,14 @@ xfs_vn_create( > return xfs_generic_create(idmap, dir, dentry, mode, 0, NULL); > } > > -STATIC int > +STATIC struct dentry * > xfs_vn_mkdir( > struct mnt_idmap *idmap, > struct inode *dir, > struct dentry *dentry, > umode_t mode) > { > - return xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL); > + return ERR_PTR(xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL)); > } > > STATIC struct dentry * > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 2c3b2f8a621f..45269608ee23 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2211,8 +2211,8 @@ struct inode_operations { > int (*unlink) (struct inode *,struct dentry *); > int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *, > const char *); > - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *, > - umode_t); > + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *, > + struct dentry *, umode_t); > int (*rmdir) (struct inode *,struct dentry *); > int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *, > umode_t,dev_t); > diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c > index 9aaf5124648b..dc3aa91a6ba0 100644 > --- a/kernel/bpf/inode.c > +++ b/kernel/bpf/inode.c > @@ -150,14 +150,14 @@ static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode, > inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); > } > > -static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > > inode = bpf_get_inode(dir->i_sb, dir, mode | S_IFDIR); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > inode->i_op = &bpf_dir_iops; > inode->i_fop = &simple_dir_operations; > @@ -166,7 +166,7 @@ static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > inc_nlink(dir); > > bpf_dentry_finalize(dentry, inode, dir); > - return 0; > + return NULL; > } > > struct map_iter { > diff --git a/mm/shmem.c b/mm/shmem.c > index 4ea6109a8043..00ae0146e768 100644 > --- a/mm/shmem.c > +++ b/mm/shmem.c > @@ -3889,16 +3889,16 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir, > return error; > } > > -static int shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int error; > > error = shmem_mknod(idmap, dir, dentry, mode | S_IFDIR, 0); > if (error) > - return error; > + return ERR_PTR(error); > inc_nlink(dir); > - return 0; > + return NULL; > } > > static int shmem_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c > index c07d150685d7..6039afae4bfc 100644 > --- a/security/apparmor/apparmorfs.c > +++ b/security/apparmor/apparmorfs.c > @@ -1795,8 +1795,8 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) > return error; > } > > -static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct aa_ns *ns, *parent; > /* TODO: improve permission check */ > @@ -1808,7 +1808,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > AA_MAY_LOAD_POLICY); > end_current_label_crit_section(label); > if (error) > - return error; > + return ERR_PTR(error); > > parent = aa_get_ns(dir->i_private); > AA_BUG(d_inode(ns_subns_dir(parent)) != dir); > @@ -1843,7 +1843,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > mutex_unlock(&parent->lock); > aa_put_ns(parent); > > - return error; > + return ERR_PTR(error); > } > > static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) Reviewed-by: Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * 2025-02-17 5:30 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 2025-02-18 12:20 ` Jan Kara 2025-02-18 13:13 ` Jeff Layton @ 2025-02-19 13:19 ` Christian Brauner 2 siblings, 0 replies; 17+ messages in thread From: Christian Brauner @ 2025-02-19 13:19 UTC (permalink / raw) To: NeilBrown; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, linux-kernel On Mon, Feb 17, 2025 at 04:30:03PM +1100, NeilBrown wrote: > Some filesystems, such as NFS, cifs, ceph, and fuse, do not have > complete control of sequencing on the actual filesystem (e.g. on a > different server) and may find that the inode created for a mkdir > request already exists in the icache and dcache by the time the mkdir > request returns. For example, if the filesystem is mounted twice the > file could be visible on the other mount before it is on the original > mount, and a pair of name_to_handle_at(), open_by_handle_at() could > instantiate the directory inode with an IS_ROOT() dentry before the > first mkdir returns. Imho, this example also belongs into Documentation/. > > This means that the dentry passed to ->mkdir() may not be the one that > is associated with the inode after the ->mkdir() completes. Some > callers need to interact with the inode after the ->mkdir completes and > they currently need to perform a lookup in the (rare) case that the > dentry is no longer hashed. > > This lookup-after-mkdir requires that the directory remains locked to > avoid races. Planned future patches to lock the dentry rather than the > directory will mean that this lookup cannot be performed atomically with > the mkdir. > > To remove this barrier, this patch changes ->mkdir to return the > resulting dentry if it is different from the one passed in. > Possible returns are: > NULL - the directory was created and no other dentry was used > ERR_PTR() - an error occurred > non-NULL - this other dentry was spliced in > > Not all filesystems reliable result in a positive hashed dentry: > > - NFS does produce the proper dentry, but does not yet return it. The > code change is larger than I wanted to include in this patch > - cifs will, when posix extensions are enabled, unhash the > dentry on success so a subsequent lookup will create it if needed. > - cifs without posix extensions will unhash the dentry if an > internal lookup finds a non-directory where it expected the dir. > - kernfs and tracefs leave the dentry negative and the ->revalidate > operation ensures that lookup will be called to correctly populate > the dentry > - hostfs leaves the dentry negative and uses > .d_delete = always_delete_dentry > so the negative dentry is quickly discarded and a lookup will add a > new entry. > > Signed-off-by: NeilBrown <neilb@suse.de> > --- Thanks, this is a great improvement and makes mkdir a lot easier to understand imho. Two nits below. > Documentation/filesystems/locking.rst | 2 +- > Documentation/filesystems/porting.rst | 11 +++++ > Documentation/filesystems/vfs.rst | 7 +++- > fs/9p/vfs_inode.c | 7 ++-- > fs/9p/vfs_inode_dotl.c | 8 ++-- > fs/affs/affs.h | 2 +- > fs/affs/namei.c | 8 ++-- > fs/afs/dir.c | 12 +++--- > fs/autofs/root.c | 14 +++---- > fs/bad_inode.c | 6 +-- > fs/bcachefs/fs.c | 6 +-- > fs/btrfs/inode.c | 8 ++-- > fs/ceph/dir.c | 15 +++++-- > fs/coda/dir.c | 14 +++---- > fs/configfs/dir.c | 6 +-- > fs/ecryptfs/inode.c | 6 +-- > fs/exfat/namei.c | 8 ++-- > fs/ext2/namei.c | 9 +++-- > fs/ext4/namei.c | 10 ++--- > fs/f2fs/namei.c | 14 +++---- > fs/fat/namei_msdos.c | 8 ++-- > fs/fat/namei_vfat.c | 8 ++-- > fs/fuse/dir.c | 58 +++++++++++++++++---------- > fs/gfs2/inode.c | 9 +++-- > fs/hfs/dir.c | 10 ++--- > fs/hfsplus/dir.c | 6 +-- > fs/hostfs/hostfs_kern.c | 8 ++-- > fs/hpfs/namei.c | 10 ++--- > fs/hugetlbfs/inode.c | 6 +-- > fs/jffs2/dir.c | 18 ++++----- > fs/jfs/namei.c | 8 ++-- > fs/kernfs/dir.c | 12 +++--- > fs/minix/namei.c | 8 ++-- > fs/namei.c | 14 +++++-- > fs/nfs/dir.c | 9 +++-- > fs/nfs/internal.h | 4 +- > fs/nilfs2/namei.c | 8 ++-- > fs/ntfs3/namei.c | 8 ++-- > fs/ocfs2/dlmfs/dlmfs.c | 14 ++++--- > fs/ocfs2/namei.c | 10 ++--- > fs/omfs/dir.c | 6 +-- > fs/orangefs/namei.c | 8 ++-- > fs/overlayfs/dir.c | 9 +++-- > fs/ramfs/inode.c | 6 +-- > fs/smb/client/cifsfs.h | 4 +- > fs/smb/client/inode.c | 10 ++--- > fs/sysv/namei.c | 8 ++-- > fs/tracefs/inode.c | 10 ++--- > fs/ubifs/dir.c | 10 ++--- > fs/udf/namei.c | 12 +++--- > fs/ufs/namei.c | 8 ++-- > fs/vboxsf/dir.c | 8 ++-- > fs/xfs/xfs_iops.c | 4 +- > include/linux/fs.h | 4 +- > kernel/bpf/inode.c | 8 ++-- > mm/shmem.c | 8 ++-- > security/apparmor/apparmorfs.c | 8 ++-- > 57 files changed, 294 insertions(+), 246 deletions(-) > > diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst > index d20a32b77b60..0ec0bb6eb0fb 100644 > --- a/Documentation/filesystems/locking.rst > +++ b/Documentation/filesystems/locking.rst > @@ -66,7 +66,7 @@ prototypes:: > int (*link) (struct dentry *,struct inode *,struct dentry *); > int (*unlink) (struct inode *,struct dentry *); > int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); > - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > int (*rmdir) (struct inode *,struct dentry *); > int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); > int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, > diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst > index 159adb02be52..68938b7ca1ab 100644 > --- a/Documentation/filesystems/porting.rst > +++ b/Documentation/filesystems/porting.rst > @@ -1175,3 +1175,14 @@ lookup_one_qstr_excl() is changed to return errors in some cases: > > LOOKUP_EXCL now means "target must not exist". It can be combined with > LOOK_CREATE or LOOKUP_RENAME_TARGET. > + > +--- > + > +** mandatory** > + > +->mkdir() now returns a 'struct dentry *'. If the created inode is > +found to already be in cache and have a dentry (often IS_ROOT), it will > +need to be spliced into the given name in place of the given dentry. > +That dentry now needs to be returned. If the original dentry is used, > +NULL should be returned. Any error should be returned with > +ERR_PTR(). > diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst > index 31eea688609a..bd3751dfddcf 100644 > --- a/Documentation/filesystems/vfs.rst > +++ b/Documentation/filesystems/vfs.rst > @@ -495,7 +495,7 @@ As of kernel 2.6.22, the following members are defined: > int (*link) (struct dentry *,struct inode *,struct dentry *); > int (*unlink) (struct inode *,struct dentry *); > int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,const char *); > - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t); > int (*rmdir) (struct inode *,struct dentry *); > int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *,umode_t,dev_t); > int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, > @@ -562,7 +562,10 @@ otherwise noted. > ``mkdir`` > called by the mkdir(2) system call. Only required if you want > to support creating subdirectories. You will probably need to > - call d_instantiate() just as you would in the create() method > + call d_instantiate() just as you would in the create() method. > + If some dentry other than the one given is spliced in, then it > + much be returned, otherwise NULL is returned is the original dentry ^^^^^^^ ^^^^^^^^^^^^^^^^^ s/much/must/ s/is/if/ ? > + is successfully used, else an ERR_PTR() is returned. > > ``rmdir`` > called by the rmdir(2) system call. Only required if you want > diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c > index 3e68521f4e2f..399d455d50d6 100644 > --- a/fs/9p/vfs_inode.c > +++ b/fs/9p/vfs_inode.c > @@ -669,8 +669,8 @@ v9fs_vfs_create(struct mnt_idmap *idmap, struct inode *dir, > * > */ > > -static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int err; > u32 perm; > @@ -692,8 +692,7 @@ static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > if (fid) > p9_fid_put(fid); > - > - return err; > + return ERR_PTR(err); > } > > /** > diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c > index 143ac03b7425..cc2007be2173 100644 > --- a/fs/9p/vfs_inode_dotl.c > +++ b/fs/9p/vfs_inode_dotl.c > @@ -350,9 +350,9 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, > * > */ > > -static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, > - struct inode *dir, struct dentry *dentry, > - umode_t omode) > +static struct dentry *v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, > + struct inode *dir, struct dentry *dentry, > + umode_t omode) > { > int err; > struct v9fs_session_info *v9ses; > @@ -417,7 +417,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, > p9_fid_put(fid); > v9fs_put_acl(dacl, pacl); > p9_fid_put(dfid); > - return err; > + return ERR_PTR(err); > } > > static int > diff --git a/fs/affs/affs.h b/fs/affs/affs.h > index e8c2c4535cb3..ac4e9a02910b 100644 > --- a/fs/affs/affs.h > +++ b/fs/affs/affs.h > @@ -168,7 +168,7 @@ extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsi > extern int affs_unlink(struct inode *dir, struct dentry *dentry); > extern int affs_create(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode, bool); > -extern int affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > +extern struct dentry *affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode); > extern int affs_rmdir(struct inode *dir, struct dentry *dentry); > extern int affs_link(struct dentry *olddentry, struct inode *dir, > diff --git a/fs/affs/namei.c b/fs/affs/namei.c > index 8c154490a2d6..f883be50db12 100644 > --- a/fs/affs/namei.c > +++ b/fs/affs/namei.c > @@ -273,7 +273,7 @@ affs_create(struct mnt_idmap *idmap, struct inode *dir, > return 0; > } > > -int > +struct dentry * > affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode) > { > @@ -285,7 +285,7 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > inode = affs_new_inode(dir); > if (!inode) > - return -ENOSPC; > + return ERR_PTR(-ENOSPC); > > inode->i_mode = S_IFDIR | mode; > affs_mode_to_prot(inode); > @@ -298,9 +298,9 @@ affs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > clear_nlink(inode); > mark_inode_dirty(inode); > iput(inode); > - return error; > + return ERR_PTR(error); > } > - return 0; > + return NULL; > } > > int > diff --git a/fs/afs/dir.c b/fs/afs/dir.c > index 02cbf38e1a77..5bddcc20786e 100644 > --- a/fs/afs/dir.c > +++ b/fs/afs/dir.c > @@ -33,8 +33,8 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nl > loff_t fpos, u64 ino, unsigned dtype); > static int afs_create(struct mnt_idmap *idmap, struct inode *dir, > struct dentry *dentry, umode_t mode, bool excl); > -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode); > +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode); > static int afs_rmdir(struct inode *dir, struct dentry *dentry); > static int afs_unlink(struct inode *dir, struct dentry *dentry); > static int afs_link(struct dentry *from, struct inode *dir, > @@ -1315,8 +1315,8 @@ static const struct afs_operation_ops afs_mkdir_operation = { > /* > * create a directory on an AFS filesystem > */ > -static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct afs_operation *op; > struct afs_vnode *dvnode = AFS_FS_I(dir); > @@ -1328,7 +1328,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > op = afs_alloc_operation(NULL, dvnode->volume); > if (IS_ERR(op)) { > d_drop(dentry); > - return PTR_ERR(op); > + return ERR_CAST(op); > } > > fscache_use_cookie(afs_vnode_cache(dvnode), true); > @@ -1344,7 +1344,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > op->ops = &afs_mkdir_operation; > ret = afs_do_sync_operation(op); > afs_dir_unuse_cookie(dvnode, ret); > - return ret; > + return ERR_PTR(ret); > } > > /* > diff --git a/fs/autofs/root.c b/fs/autofs/root.c > index 530d18827e35..174c7205fee4 100644 > --- a/fs/autofs/root.c > +++ b/fs/autofs/root.c > @@ -15,8 +15,8 @@ static int autofs_dir_symlink(struct mnt_idmap *, struct inode *, > struct dentry *, const char *); > static int autofs_dir_unlink(struct inode *, struct dentry *); > static int autofs_dir_rmdir(struct inode *, struct dentry *); > -static int autofs_dir_mkdir(struct mnt_idmap *, struct inode *, > - struct dentry *, umode_t); > +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *, struct inode *, > + struct dentry *, umode_t); > static long autofs_root_ioctl(struct file *, unsigned int, unsigned long); > #ifdef CONFIG_COMPAT > static long autofs_root_compat_ioctl(struct file *, > @@ -720,9 +720,9 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry) > return 0; > } > > -static int autofs_dir_mkdir(struct mnt_idmap *idmap, > - struct inode *dir, struct dentry *dentry, > - umode_t mode) > +static struct dentry *autofs_dir_mkdir(struct mnt_idmap *idmap, > + struct inode *dir, struct dentry *dentry, > + umode_t mode) > { > struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); > struct autofs_info *ino = autofs_dentry_ino(dentry); > @@ -739,7 +739,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, > > inode = autofs_get_inode(dir->i_sb, S_IFDIR | mode); > if (!inode) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > d_add(dentry, inode); > > if (sbi->version < 5) > @@ -751,7 +751,7 @@ static int autofs_dir_mkdir(struct mnt_idmap *idmap, > inc_nlink(dir); > inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); > > - return 0; > + return NULL; > } > > /* Get/set timeout ioctl() operation */ > diff --git a/fs/bad_inode.c b/fs/bad_inode.c > index 316d88da2ce1..0ef9bcb744dd 100644 > --- a/fs/bad_inode.c > +++ b/fs/bad_inode.c > @@ -58,10 +58,10 @@ static int bad_inode_symlink(struct mnt_idmap *idmap, > return -EIO; > } > > -static int bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *bad_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return -EIO; > + return ERR_PTR(-EIO); > } > > static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) > diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c > index 90ade8f648d9..1c94a680fcce 100644 > --- a/fs/bcachefs/fs.c > +++ b/fs/bcachefs/fs.c > @@ -858,10 +858,10 @@ static int bch2_symlink(struct mnt_idmap *idmap, > return bch2_err_class(ret); > } > > -static int bch2_mkdir(struct mnt_idmap *idmap, > - struct inode *vdir, struct dentry *dentry, umode_t mode) > +static struct dentry *bch2_mkdir(struct mnt_idmap *idmap, > + struct inode *vdir, struct dentry *dentry, umode_t mode) > { > - return bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0); > + return ERR_PTR(bch2_mknod(idmap, vdir, dentry, mode|S_IFDIR, 0)); > } > > static int bch2_rename2(struct mnt_idmap *idmap, > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c > index a9322601ab5c..851d3e8a06a7 100644 > --- a/fs/btrfs/inode.c > +++ b/fs/btrfs/inode.c > @@ -6739,18 +6739,18 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, > return err; > } > > -static int btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *btrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > > inode = new_inode(dir->i_sb); > if (!inode) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > inode_init_owner(idmap, inode, dir, S_IFDIR | mode); > inode->i_op = &btrfs_dir_inode_operations; > inode->i_fop = &btrfs_dir_file_operations; > - return btrfs_create_common(dir, dentry, inode); > + return ERR_PTR(btrfs_create_common(dir, dentry, inode)); > } > > static noinline int uncompress_inline(struct btrfs_path *path, > diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c > index 62e99e65250d..c1a1c168bb27 100644 > --- a/fs/ceph/dir.c > +++ b/fs/ceph/dir.c > @@ -1092,19 +1092,20 @@ static int ceph_symlink(struct mnt_idmap *idmap, struct inode *dir, > return err; > } > > -static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb); > struct ceph_client *cl = mdsc->fsc->client; > struct ceph_mds_request *req; > struct ceph_acl_sec_ctx as_ctx = {}; > + struct dentry *ret = NULL; > int err; > int op; > > err = ceph_wait_on_conflict_unlink(dentry); > if (err) > - return err; > + return ERR_PTR(err); > > if (ceph_snap(dir) == CEPH_SNAPDIR) { > /* mkdir .snap/foo is a MKSNAP */ > @@ -1166,14 +1167,20 @@ static int ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, > !req->r_reply_info.head->is_dentry) > err = ceph_handle_notrace_create(dir, dentry); > out_req: > + if (!err && req->r_dentry != dentry) > + /* Some other dentry was spliced in */ > + ret = dget(req->r_dentry); > ceph_mdsc_put_request(req); > out: > if (!err) > + /* Should this use 'ret' ?? */ > ceph_init_inode_acls(d_inode(dentry), &as_ctx); > else > d_drop(dentry); > ceph_release_acl_sec_ctx(&as_ctx); > - return err; > + if (err) > + return ERR_PTR(err); > + return ret; > } > > static int ceph_link(struct dentry *old_dentry, struct inode *dir, > diff --git a/fs/coda/dir.c b/fs/coda/dir.c > index a3e2dfeedfbf..ab69d8f0cec2 100644 > --- a/fs/coda/dir.c > +++ b/fs/coda/dir.c > @@ -166,8 +166,8 @@ static int coda_create(struct mnt_idmap *idmap, struct inode *dir, > return error; > } > > -static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *de, umode_t mode) > +static struct dentry *coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *de, umode_t mode) > { > struct inode *inode; > struct coda_vattr attrs; > @@ -177,14 +177,14 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > struct CodaFid newfid; > > if (is_root_inode(dir) && coda_iscontrol(name, len)) > - return -EPERM; > + return ERR_PTR(-EPERM); > > attrs.va_mode = mode; > - error = venus_mkdir(dir->i_sb, coda_i2f(dir), > + error = venus_mkdir(dir->i_sb, coda_i2f(dir), > name, len, &newfid, &attrs); > if (error) > goto err_out; > - > + > inode = coda_iget(dir->i_sb, &newfid, &attrs); > if (IS_ERR(inode)) { > error = PTR_ERR(inode); > @@ -195,10 +195,10 @@ static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, > coda_dir_inc_nlink(dir); > coda_dir_update_mtime(dir); > d_instantiate(de, inode); > - return 0; > + return NULL; > err_out: > d_drop(de); > - return error; > + return ERR_PTR(error); > } > > /* try to make de an entry in dir_inodde linked to source_de */ > diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c > index 7d10278db30d..5568cb74b322 100644 > --- a/fs/configfs/dir.c > +++ b/fs/configfs/dir.c > @@ -1280,8 +1280,8 @@ int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys, > } > EXPORT_SYMBOL(configfs_depend_item_unlocked); > > -static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int ret = 0; > int module_got = 0; > @@ -1461,7 +1461,7 @@ static int configfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > put_fragment(frag); > > out: > - return ret; > + return ERR_PTR(ret); > } > > static int configfs_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c > index a9819ddb1ab8..6315dd194228 100644 > --- a/fs/ecryptfs/inode.c > +++ b/fs/ecryptfs/inode.c > @@ -503,8 +503,8 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap, > return rc; > } > > -static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int rc; > struct dentry *lower_dentry; > @@ -526,7 +526,7 @@ static int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > inode_unlock(lower_dir); > if (d_really_is_negative(dentry)) > d_drop(dentry); > - return rc; > + return ERR_PTR(rc); > } > > static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c > index 691dd77b6ab5..1660c9bbcfa9 100644 > --- a/fs/exfat/namei.c > +++ b/fs/exfat/namei.c > @@ -835,8 +835,8 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) > return err; > } > > -static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct super_block *sb = dir->i_sb; > struct inode *inode; > @@ -846,7 +846,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > loff_t size = i_size_read(dir); > > if (unlikely(exfat_forced_shutdown(sb))) > - return -EIO; > + return ERR_PTR(-EIO); > > mutex_lock(&EXFAT_SB(sb)->s_lock); > exfat_set_volume_dirty(sb); > @@ -877,7 +877,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > unlock: > mutex_unlock(&EXFAT_SB(sb)->s_lock); > - return err; > + return ERR_PTR(err); > } > > static int exfat_check_dir_empty(struct super_block *sb, > diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c > index 8346ab9534c1..bde617a66cec 100644 > --- a/fs/ext2/namei.c > +++ b/fs/ext2/namei.c > @@ -225,15 +225,16 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, > return err; > } > > -static int ext2_mkdir(struct mnt_idmap * idmap, > - struct inode * dir, struct dentry * dentry, umode_t mode) > +static struct dentry *ext2_mkdir(struct mnt_idmap * idmap, > + struct inode * dir, struct dentry * dentry, > + umode_t mode) > { > struct inode * inode; > int err; > > err = dquot_initialize(dir); > if (err) > - return err; > + return ERR_PTR(err); > > inode_inc_link_count(dir); > > @@ -258,7 +259,7 @@ static int ext2_mkdir(struct mnt_idmap * idmap, > > d_instantiate_new(dentry, inode); > out: > - return err; > + return ERR_PTR(err); > > out_fail: > inode_dec_link_count(inode); > diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c > index 536d56d15072..716cc6096870 100644 > --- a/fs/ext4/namei.c > +++ b/fs/ext4/namei.c > @@ -3004,19 +3004,19 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, > return err; > } > > -static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > handle_t *handle; > struct inode *inode; > int err, err2 = 0, credits, retries = 0; > > if (EXT4_DIR_LINK_MAX(dir)) > - return -EMLINK; > + return ERR_PTR(-EMLINK); > > err = dquot_initialize(dir); > if (err) > - return err; > + return ERR_PTR(err); > > credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + > EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); > @@ -3066,7 +3066,7 @@ static int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, > out_retry: > if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) > goto retry; > - return err; > + return ERR_PTR(err); > } > > /* > diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c > index a278c7da8177..24dca4dc85a9 100644 > --- a/fs/f2fs/namei.c > +++ b/fs/f2fs/namei.c > @@ -684,23 +684,23 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir, > return err; > } > > -static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct f2fs_sb_info *sbi = F2FS_I_SB(dir); > struct inode *inode; > int err; > > if (unlikely(f2fs_cp_error(sbi))) > - return -EIO; > + return ERR_PTR(-EIO); > > err = f2fs_dquot_initialize(dir); > if (err) > - return err; > + return ERR_PTR(err); > > inode = f2fs_new_inode(idmap, dir, S_IFDIR | mode, NULL); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > inode->i_op = &f2fs_dir_inode_operations; > inode->i_fop = &f2fs_dir_operations; > @@ -722,12 +722,12 @@ static int f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > f2fs_sync_fs(sbi->sb, 1); > > f2fs_balance_fs(sbi, true); > - return 0; > + return NULL; > > out_fail: > clear_inode_flag(inode, FI_INC_LINK); > f2fs_handle_failed_inode(inode); > - return err; > + return ERR_PTR(err); > } > > static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c > index f06f6ba643cc..23e9b9371ec3 100644 > --- a/fs/fat/namei_msdos.c > +++ b/fs/fat/namei_msdos.c > @@ -339,8 +339,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) > } > > /***** Make a directory */ > -static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct super_block *sb = dir->i_sb; > struct fat_slot_info sinfo; > @@ -389,13 +389,13 @@ static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > mutex_unlock(&MSDOS_SB(sb)->s_lock); > fat_flush_inodes(sb, dir, inode); > - return 0; > + return NULL; > > out_free: > fat_free_clusters(dir, cluster); > out: > mutex_unlock(&MSDOS_SB(sb)->s_lock); > - return err; > + return ERR_PTR(err); > } > > /***** Unlink a file */ > diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c > index 926c26e90ef8..dd910edd2404 100644 > --- a/fs/fat/namei_vfat.c > +++ b/fs/fat/namei_vfat.c > @@ -841,8 +841,8 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) > return err; > } > > -static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct super_block *sb = dir->i_sb; > struct inode *inode; > @@ -877,13 +877,13 @@ static int vfat_mkdir(struct mnt_idmap *idmap, struct inode *dir, > d_instantiate(dentry, inode); > > mutex_unlock(&MSDOS_SB(sb)->s_lock); > - return 0; > + return NULL; > > out_free: > fat_free_clusters(dir, cluster); > out: > mutex_unlock(&MSDOS_SB(sb)->s_lock); > - return err; > + return ERR_PTR(err); > } > > static int vfat_get_dotdot_de(struct inode *inode, struct buffer_head **bh, > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index 198862b086ff..2537eefcd023 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -781,9 +781,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, > /* > * Code shared between mknod, mkdir, symlink and link > */ > -static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > - struct fuse_args *args, struct inode *dir, > - struct dentry *entry, umode_t mode) > +static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > + struct fuse_args *args, struct inode *dir, > + struct dentry *entry, umode_t mode) > { > struct fuse_entry_out outarg; > struct inode *inode; > @@ -792,11 +792,11 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > struct fuse_forget_link *forget; > > if (fuse_is_bad(dir)) > - return -EIO; > + return ERR_PTR(-EIO); > > forget = fuse_alloc_forget(); > if (!forget) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > memset(&outarg, 0, sizeof(outarg)); > args->nodeid = get_node_id(dir); > @@ -826,29 +826,27 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); > if (!inode) { > fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > } > kfree(forget); > > d_drop(entry); > d = d_splice_alias(inode, entry); > if (IS_ERR(d)) > - return PTR_ERR(d); > + return d; > > - if (d) { > + if (d) > fuse_change_entry_timeout(d, &outarg); > - dput(d); > - } else { > + else > fuse_change_entry_timeout(entry, &outarg); > - } > fuse_dir_changed(dir); > - return 0; > + return d; > > out_put_forget_req: > if (err == -EEXIST) > fuse_invalidate_entry(entry); > kfree(forget); > - return err; > + return ERR_PTR(err); > } > > static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > @@ -856,6 +854,7 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > { > struct fuse_mknod_in inarg; > struct fuse_mount *fm = get_fuse_mount(dir); > + struct dentry *de; > FUSE_ARGS(args); > > if (!fm->fc->dont_mask) > @@ -871,7 +870,12 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[0].value = &inarg; > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > - return create_new_entry(idmap, fm, &args, dir, entry, mode); > + de = create_new_entry(idmap, fm, &args, dir, entry, mode); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) > + dput(de); > + return 0; > } > > static int fuse_create(struct mnt_idmap *idmap, struct inode *dir, > @@ -898,8 +902,8 @@ static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir, > return err; > } > > -static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *entry, umode_t mode) > +static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *entry, umode_t mode) > { > struct fuse_mkdir_in inarg; > struct fuse_mount *fm = get_fuse_mount(dir); > @@ -918,6 +922,7 @@ static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); > + > } > > static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > @@ -925,6 +930,7 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > { > struct fuse_mount *fm = get_fuse_mount(dir); > unsigned len = strlen(link) + 1; > + struct dentry *de; > FUSE_ARGS(args); > > args.opcode = FUSE_SYMLINK; > @@ -934,7 +940,12 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[1].value = entry->d_name.name; > args.in_args[2].size = len; > args.in_args[2].value = link; > - return create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); > + de = create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) > + dput(de); > + return 0; > } > > void fuse_flush_time_update(struct inode *inode) > @@ -1117,7 +1128,7 @@ static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir, > static int fuse_link(struct dentry *entry, struct inode *newdir, > struct dentry *newent) > { > - int err; > + struct dentry *de; > struct fuse_link_in inarg; > struct inode *inode = d_inode(entry); > struct fuse_mount *fm = get_fuse_mount(inode); > @@ -1131,13 +1142,16 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, > args.in_args[0].value = &inarg; > args.in_args[1].size = newent->d_name.len + 1; > args.in_args[1].value = newent->d_name.name; > - err = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); > - if (!err) > + de = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); > + if (!IS_ERR(de)) { > + if (de) > + dput(de); > + de = NULL; > fuse_update_ctime_in_cache(inode); > - else if (err == -EINTR) > + } else if (PTR_ERR(de) == -EINTR) > fuse_invalidate_attr(inode); > > - return err; > + return PTR_ERR(de); > } > > static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode, > diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c > index 6fbbaaad1cd0..198a8cbaf5e5 100644 > --- a/fs/gfs2/inode.c > +++ b/fs/gfs2/inode.c > @@ -1248,14 +1248,15 @@ static int gfs2_symlink(struct mnt_idmap *idmap, struct inode *dir, > * @dentry: The dentry of the new directory > * @mode: The mode of the new directory > * > - * Returns: errno > + * Returns: the dentry, or ERR_PTR(errno) > */ > > -static int gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *gfs2_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > unsigned dsize = gfs2_max_stuffed_size(GFS2_I(dir)); > - return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0); > + > + return ERR_PTR(gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0)); > } > > /** > diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c > index b75c26045df4..86a6b317b474 100644 > --- a/fs/hfs/dir.c > +++ b/fs/hfs/dir.c > @@ -219,26 +219,26 @@ static int hfs_create(struct mnt_idmap *idmap, struct inode *dir, > * in a directory, given the inode for the parent directory and the > * name (and its length) of the new directory. > */ > -static int hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > int res; > > inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); > if (!inode) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); > if (res) { > clear_nlink(inode); > hfs_delete_inode(inode); > iput(inode); > - return res; > + return ERR_PTR(res); > } > d_instantiate(dentry, inode); > mark_inode_dirty(inode); > - return 0; > + return NULL; > } > > /* > diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c > index f5c4b3e31a1c..876bbb80fb4d 100644 > --- a/fs/hfsplus/dir.c > +++ b/fs/hfsplus/dir.c > @@ -523,10 +523,10 @@ static int hfsplus_create(struct mnt_idmap *idmap, struct inode *dir, > return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode, 0); > } > > -static int hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hfsplus_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); > + return ERR_PTR(hfsplus_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0)); > } > > static int hfsplus_rename(struct mnt_idmap *idmap, > diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c > index e0741e468956..ccbb48fe830d 100644 > --- a/fs/hostfs/hostfs_kern.c > +++ b/fs/hostfs/hostfs_kern.c > @@ -679,17 +679,17 @@ static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino, > return err; > } > > -static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, > + struct dentry *dentry, umode_t mode) > { > char *file; > int err; > > if ((file = dentry_name(dentry)) == NULL) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > err = do_mkdir(file, mode); > __putname(file); > - return err; > + return ERR_PTR(err); > } > > static int hostfs_rmdir(struct inode *ino, struct dentry *dentry) > diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c > index d0edf9ed33b6..e3cdc421dfba 100644 > --- a/fs/hpfs/namei.c > +++ b/fs/hpfs/namei.c > @@ -19,8 +19,8 @@ static void hpfs_update_directory_times(struct inode *dir) > hpfs_write_inode_nolock(dir); > } > > -static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > const unsigned char *name = dentry->d_name.name; > unsigned len = dentry->d_name.len; > @@ -35,7 +35,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > int r; > struct hpfs_dirent dee; > int err; > - if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; > + if ((err = hpfs_chk_name(name, &len))) return ERR_PTR(err==-ENOENT ? -EINVAL : err); > hpfs_lock(dir->i_sb); > err = -ENOSPC; > fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); > @@ -112,7 +112,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > hpfs_update_directory_times(dir); > d_instantiate(dentry, result); > hpfs_unlock(dir->i_sb); > - return 0; > + return NULL; > bail3: > iput(result); > bail2: > @@ -123,7 +123,7 @@ static int hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > hpfs_free_sectors(dir->i_sb, fno, 1); > bail: > hpfs_unlock(dir->i_sb); > - return err; > + return ERR_PTR(err); > } > > static int hpfs_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c > index 0fc179a59830..d98caedbb723 100644 > --- a/fs/hugetlbfs/inode.c > +++ b/fs/hugetlbfs/inode.c > @@ -991,14 +991,14 @@ static int hugetlbfs_mknod(struct mnt_idmap *idmap, struct inode *dir, > return 0; > } > > -static int hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int retval = hugetlbfs_mknod(idmap, dir, dentry, > mode | S_IFDIR, 0); > if (!retval) > inc_nlink(dir); > - return retval; > + return ERR_PTR(retval); > } > > static int hugetlbfs_create(struct mnt_idmap *idmap, > diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c > index 2b2938970da3..dd91f725ded6 100644 > --- a/fs/jffs2/dir.c > +++ b/fs/jffs2/dir.c > @@ -32,8 +32,8 @@ static int jffs2_link (struct dentry *,struct inode *,struct dentry *); > static int jffs2_unlink (struct inode *,struct dentry *); > static int jffs2_symlink (struct mnt_idmap *, struct inode *, > struct dentry *, const char *); > -static int jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, > - umode_t); > +static struct dentry *jffs2_mkdir (struct mnt_idmap *, struct inode *,struct dentry *, > + umode_t); > static int jffs2_rmdir (struct inode *,struct dentry *); > static int jffs2_mknod (struct mnt_idmap *, struct inode *,struct dentry *, > umode_t,dev_t); > @@ -446,8 +446,8 @@ static int jffs2_symlink (struct mnt_idmap *idmap, struct inode *dir_i, > } > > > -static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > - struct dentry *dentry, umode_t mode) > +static struct dentry *jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > + struct dentry *dentry, umode_t mode) > { > struct jffs2_inode_info *f, *dir_f; > struct jffs2_sb_info *c; > @@ -464,7 +464,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > > ri = jffs2_alloc_raw_inode(); > if (!ri) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > c = JFFS2_SB_INFO(dir_i->i_sb); > > @@ -477,7 +477,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > > if (ret) { > jffs2_free_raw_inode(ri); > - return ret; > + return ERR_PTR(ret); > } > > inode = jffs2_new_inode(dir_i, mode, ri); > @@ -485,7 +485,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > if (IS_ERR(inode)) { > jffs2_free_raw_inode(ri); > jffs2_complete_reservation(c); > - return PTR_ERR(inode); > + return ERR_CAST(inode); > } > > inode->i_op = &jffs2_dir_inode_operations; > @@ -584,11 +584,11 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i, > jffs2_complete_reservation(c); > > d_instantiate_new(dentry, inode); > - return 0; > + return NULL; > > fail: > iget_failed(inode); > - return ret; > + return ERR_PTR(ret); > } > > static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) > diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c > index fc8ede43afde..65a218eba8fa 100644 > --- a/fs/jfs/namei.c > +++ b/fs/jfs/namei.c > @@ -187,13 +187,13 @@ static int jfs_create(struct mnt_idmap *idmap, struct inode *dip, > * dentry - dentry of child directory > * mode - create mode (rwxrwxrwx). > * > - * RETURN: Errors from subroutines > + * RETURN: ERR_PTR() of errors from subroutines. > * > * note: > * EACCES: user needs search+write permission on the parent directory > */ > -static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, > - struct dentry *dentry, umode_t mode) > +static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, > + struct dentry *dentry, umode_t mode) > { > int rc = 0; > tid_t tid; /* transaction id */ > @@ -308,7 +308,7 @@ static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, > out1: > > jfs_info("jfs_mkdir: rc:%d", rc); > - return rc; > + return ERR_PTR(rc); > } > > /* > diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c > index 5f0f8b95f44c..d296aad70800 100644 > --- a/fs/kernfs/dir.c > +++ b/fs/kernfs/dir.c > @@ -1230,24 +1230,24 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, > return d_splice_alias(inode, dentry); > } > > -static int kernfs_iop_mkdir(struct mnt_idmap *idmap, > - struct inode *dir, struct dentry *dentry, > - umode_t mode) > +static struct dentry *kernfs_iop_mkdir(struct mnt_idmap *idmap, > + struct inode *dir, struct dentry *dentry, > + umode_t mode) > { > struct kernfs_node *parent = dir->i_private; > struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops; > int ret; > > if (!scops || !scops->mkdir) > - return -EPERM; > + return ERR_PTR(-EPERM); > > if (!kernfs_get_active(parent)) > - return -ENODEV; > + return ERR_PTR(-ENODEV); > > ret = scops->mkdir(parent, dentry->d_name.name, mode); > > kernfs_put_active(parent); > - return ret; > + return ERR_PTR(ret); > } > > static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) > diff --git a/fs/minix/namei.c b/fs/minix/namei.c > index 5d9c1406fe27..8938536d8d3c 100644 > --- a/fs/minix/namei.c > +++ b/fs/minix/namei.c > @@ -104,15 +104,15 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, > return add_nondir(dentry, inode); > } > > -static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode * inode; > int err; > > inode = minix_new_inode(dir, S_IFDIR | mode); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > inode_inc_link_count(dir); > minix_set_inode(inode, 0); > @@ -128,7 +128,7 @@ static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > d_instantiate(dentry, inode); > out: > - return err; > + return ERR_PTR(err); > > out_fail: > inode_dec_link_count(inode); > diff --git a/fs/namei.c b/fs/namei.c > index 865a009fdebc..19d5ea340a18 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -4297,6 +4297,7 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > { > int error; > unsigned max_links = dir->i_sb->s_max_links; > + struct dentry *de; > > error = may_create(idmap, dir, dentry); > if (error) > @@ -4313,10 +4314,17 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (max_links && dir->i_nlink >= max_links) > return -EMLINK; > > - error = dir->i_op->mkdir(idmap, dir, dentry, mode); > - if (!error) > + de = dir->i_op->mkdir(idmap, dir, dentry, mode); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) { > + fsnotify_mkdir(dir, de); > + /* Cannot return de yet */ > + dput(de); > + } else > fsnotify_mkdir(dir, dentry); > - return error; > + > + return 0; > } > EXPORT_SYMBOL(vfs_mkdir); > > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c > index 56cf16a72334..5700f73d48bc 100644 > --- a/fs/nfs/dir.c > +++ b/fs/nfs/dir.c > @@ -2422,8 +2422,8 @@ EXPORT_SYMBOL_GPL(nfs_mknod); > /* > * See comments for nfs_proc_create regarding failed operations. > */ > -int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct iattr attr; > int error; > @@ -2439,10 +2439,11 @@ int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > trace_nfs_mkdir_exit(dir, dentry, error); > if (error != 0) > goto out_err; > - return 0; > + /* FIXME - ->mkdir might have used an alternate dentry */ > + return NULL; > out_err: > d_drop(dentry); > - return error; > + return ERR_PTR(error); > } > EXPORT_SYMBOL_GPL(nfs_mkdir); > > diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h > index fae2c7ae4acc..1ac1d3eec517 100644 > --- a/fs/nfs/internal.h > +++ b/fs/nfs/internal.h > @@ -400,8 +400,8 @@ struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); > void nfs_d_prune_case_insensitive_aliases(struct inode *inode); > int nfs_create(struct mnt_idmap *, struct inode *, struct dentry *, > umode_t, bool); > -int nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > - umode_t); > +struct dentry *nfs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > + umode_t); > int nfs_rmdir(struct inode *, struct dentry *); > int nfs_unlink(struct inode *, struct dentry *); > int nfs_symlink(struct mnt_idmap *, struct inode *, struct dentry *, > diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c > index 953fbd5f0851..40f4b1a28705 100644 > --- a/fs/nilfs2/namei.c > +++ b/fs/nilfs2/namei.c > @@ -218,8 +218,8 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, > return err; > } > > -static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > struct nilfs_transaction_info ti; > @@ -227,7 +227,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > err = nilfs_transaction_begin(dir->i_sb, &ti, 1); > if (err) > - return err; > + return ERR_PTR(err); > > inc_nlink(dir); > > @@ -258,7 +258,7 @@ static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > else > nilfs_transaction_abort(dir->i_sb); > > - return err; > + return ERR_PTR(err); > > out_fail: > drop_nlink(inode); > diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c > index abf7e81584a9..652735a0b0c4 100644 > --- a/fs/ntfs3/namei.c > +++ b/fs/ntfs3/namei.c > @@ -201,11 +201,11 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, > /* > * ntfs_mkdir- inode_operations::mkdir > */ > -static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, > - NULL, 0, NULL); > + return ERR_PTR(ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, > + NULL, 0, NULL)); > } > > /* > diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c > index 2a7f36643895..f632fbfe59e8 100644 > --- a/fs/ocfs2/dlmfs/dlmfs.c > +++ b/fs/ocfs2/dlmfs/dlmfs.c > @@ -402,10 +402,10 @@ static struct inode *dlmfs_get_inode(struct inode *parent, > * File creation. Allocate an inode, and we're done.. > */ > /* SMP-safe */ > -static int dlmfs_mkdir(struct mnt_idmap * idmap, > - struct inode * dir, > - struct dentry * dentry, > - umode_t mode) > +static struct dentry *dlmfs_mkdir(struct mnt_idmap * idmap, > + struct inode * dir, > + struct dentry * dentry, > + umode_t mode) > { > int status; > struct inode *inode = NULL; > @@ -446,9 +446,11 @@ static int dlmfs_mkdir(struct mnt_idmap * idmap, > > status = 0; > bail: > - if (status < 0) > + if (status < 0) { > iput(inode); > - return status; > + return ERR_PTR(status); > + } > + return NULL; > } > > static int dlmfs_create(struct mnt_idmap *idmap, > diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c > index 0ec63a1a94b8..99278c8f0e24 100644 > --- a/fs/ocfs2/namei.c > +++ b/fs/ocfs2/namei.c > @@ -644,10 +644,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, > suballoc_loc, suballoc_bit); > } > > -static int ocfs2_mkdir(struct mnt_idmap *idmap, > - struct inode *dir, > - struct dentry *dentry, > - umode_t mode) > +static struct dentry *ocfs2_mkdir(struct mnt_idmap *idmap, > + struct inode *dir, > + struct dentry *dentry, > + umode_t mode) > { > int ret; > > @@ -657,7 +657,7 @@ static int ocfs2_mkdir(struct mnt_idmap *idmap, > if (ret) > mlog_errno(ret); > > - return ret; > + return ERR_PTR(ret); > } > > static int ocfs2_create(struct mnt_idmap *idmap, > diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c > index 6bda275826d6..2ed541fccf33 100644 > --- a/fs/omfs/dir.c > +++ b/fs/omfs/dir.c > @@ -279,10 +279,10 @@ static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) > return err; > } > > -static int omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *omfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return omfs_add_node(dir, dentry, mode | S_IFDIR); > + return ERR_PTR(omfs_add_node(dir, dentry, mode | S_IFDIR)); > } > > static int omfs_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c > index 200558ec72f0..82395fe2b956 100644 > --- a/fs/orangefs/namei.c > +++ b/fs/orangefs/namei.c > @@ -300,8 +300,8 @@ static int orangefs_symlink(struct mnt_idmap *idmap, > return ret; > } > > -static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct orangefs_inode_s *parent = ORANGEFS_I(dir); > struct orangefs_kernel_op_s *new_op; > @@ -312,7 +312,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR); > if (!new_op) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > new_op->upcall.req.mkdir.parent_refn = parent->refn; > > @@ -366,7 +366,7 @@ static int orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > __orangefs_setattr(dir, &iattr); > out: > op_release(new_op); > - return ret; > + return ERR_PTR(ret); > } > > static int orangefs_rename(struct mnt_idmap *idmap, > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c > index c9993ff66fc2..21c3aaf7b274 100644 > --- a/fs/overlayfs/dir.c > +++ b/fs/overlayfs/dir.c > @@ -282,7 +282,8 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, > * XXX: if we ever use ovl_obtain_alias() to decode directory > * file handles, need to use ovl_get_inode_locked() and > * d_instantiate_new() here to prevent from creating two > - * hashed directory inode aliases. > + * hashed directory inode aliases. We then need to return > + * the obtained alias to ovl_mkdir(). > */ > inode = ovl_get_inode(dentry->d_sb, &oip); > if (IS_ERR(inode)) > @@ -687,10 +688,10 @@ static int ovl_create(struct mnt_idmap *idmap, struct inode *dir, > return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); > } > > -static int ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ovl_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > - return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); > + return ERR_PTR(ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL)); > } > > static int ovl_mknod(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c > index 8006faaaf0ec..775fa905fda0 100644 > --- a/fs/ramfs/inode.c > +++ b/fs/ramfs/inode.c > @@ -119,13 +119,13 @@ ramfs_mknod(struct mnt_idmap *idmap, struct inode *dir, > return error; > } > > -static int ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ramfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int retval = ramfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0); > if (!retval) > inc_nlink(dir); > - return retval; > + return ERR_PTR(retval); > } > > static int ramfs_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h > index 831fee962c4d..8dea0cf3a8de 100644 > --- a/fs/smb/client/cifsfs.h > +++ b/fs/smb/client/cifsfs.h > @@ -59,8 +59,8 @@ extern int cifs_unlink(struct inode *dir, struct dentry *dentry); > extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); > extern int cifs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, > umode_t, dev_t); > -extern int cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > - umode_t); > +extern struct dentry *cifs_mkdir(struct mnt_idmap *, struct inode *, struct dentry *, > + umode_t); > extern int cifs_rmdir(struct inode *, struct dentry *); > extern int cifs_rename2(struct mnt_idmap *, struct inode *, > struct dentry *, struct inode *, struct dentry *, > diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c > index 9cc31cf6ebd0..685a176f7f7e 100644 > --- a/fs/smb/client/inode.c > +++ b/fs/smb/client/inode.c > @@ -2194,8 +2194,8 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, > } > #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ > > -int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > - struct dentry *direntry, umode_t mode) > +struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > + struct dentry *direntry, umode_t mode) > { > int rc = 0; > unsigned int xid; > @@ -2211,10 +2211,10 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > > cifs_sb = CIFS_SB(inode->i_sb); > if (unlikely(cifs_forced_shutdown(cifs_sb))) > - return -EIO; > + return ERR_PTR(-EIO); > tlink = cifs_sb_tlink(cifs_sb); > if (IS_ERR(tlink)) > - return PTR_ERR(tlink); > + return ERR_CAST(tlink); > tcon = tlink_tcon(tlink); > > xid = get_xid(); > @@ -2270,7 +2270,7 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, > free_dentry_path(page); > free_xid(xid); > cifs_put_tlink(tlink); > - return rc; > + return ERR_PTR(rc); > } > > int cifs_rmdir(struct inode *inode, struct dentry *direntry) > diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c > index fb8bd8437872..ba037727c1e6 100644 > --- a/fs/sysv/namei.c > +++ b/fs/sysv/namei.c > @@ -110,8 +110,8 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, > return add_nondir(dentry, inode); > } > > -static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode * inode; > int err; > @@ -135,9 +135,9 @@ static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (err) > goto out_fail; > > - d_instantiate(dentry, inode); > + d_instantiate(dentry, inode); > out: > - return err; > + return ERR_PTR(err); > > out_fail: > inode_dec_link_count(inode); > diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c > index 53214499e384..cb1af30b49f5 100644 > --- a/fs/tracefs/inode.c > +++ b/fs/tracefs/inode.c > @@ -109,9 +109,9 @@ static char *get_dname(struct dentry *dentry) > return name; > } > > -static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, > - struct inode *inode, struct dentry *dentry, > - umode_t mode) > +static struct dentry *tracefs_syscall_mkdir(struct mnt_idmap *idmap, > + struct inode *inode, struct dentry *dentry, > + umode_t mode) > { > struct tracefs_inode *ti; > char *name; > @@ -119,7 +119,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, > > name = get_dname(dentry); > if (!name) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > /* > * This is a new directory that does not take the default of > @@ -141,7 +141,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, > > kfree(name); > > - return ret; > + return ERR_PTR(ret); > } > > static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) > diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c > index fda82f3e16e8..3c3d3ad4fa6c 100644 > --- a/fs/ubifs/dir.c > +++ b/fs/ubifs/dir.c > @@ -1002,8 +1002,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) > return err; > } > > -static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > struct ubifs_inode *dir_ui = ubifs_inode(dir); > @@ -1023,7 +1023,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > err = ubifs_budget_space(c, &req); > if (err) > - return err; > + return ERR_PTR(err); > > err = ubifs_prepare_create(dir, dentry, &nm); > if (err) > @@ -1060,7 +1060,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > ubifs_release_budget(c, &req); > d_instantiate(dentry, inode); > fscrypt_free_filename(&nm); > - return 0; > + return NULL; > > out_cancel: > dir->i_size -= sz_change; > @@ -1074,7 +1074,7 @@ static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, > fscrypt_free_filename(&nm); > out_budg: > ubifs_release_budget(c, &req); > - return err; > + return ERR_PTR(err); > } > > static int ubifs_mknod(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/fs/udf/namei.c b/fs/udf/namei.c > index 2cb49b6b0716..5f2e9a892bff 100644 > --- a/fs/udf/namei.c > +++ b/fs/udf/namei.c > @@ -419,8 +419,8 @@ static int udf_mknod(struct mnt_idmap *idmap, struct inode *dir, > return udf_add_nondir(dentry, inode); > } > > -static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > struct udf_fileident_iter iter; > @@ -430,7 +430,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > > inode = udf_new_inode(dir, S_IFDIR | mode); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > iinfo = UDF_I(inode); > inode->i_op = &udf_dir_inode_operations; > @@ -439,7 +439,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (err) { > clear_nlink(inode); > discard_new_inode(inode); > - return err; > + return ERR_PTR(err); > } > set_nlink(inode, 2); > iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); > @@ -456,7 +456,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > if (err) { > clear_nlink(inode); > discard_new_inode(inode); > - return err; > + return ERR_PTR(err); > } > iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); > iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location); > @@ -471,7 +471,7 @@ static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > mark_inode_dirty(dir); > d_instantiate_new(dentry, inode); > > - return 0; > + return NULL; > } > > static int empty_dir(struct inode *dir) > diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c > index 38a024c8cccd..5b3c85c93242 100644 > --- a/fs/ufs/namei.c > +++ b/fs/ufs/namei.c > @@ -166,8 +166,8 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, > return error; > } > > -static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > - struct dentry * dentry, umode_t mode) > +static struct dentry *ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > + struct dentry * dentry, umode_t mode) > { > struct inode * inode; > int err; > @@ -194,7 +194,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > goto out_fail; > > d_instantiate_new(dentry, inode); > - return 0; > + return NULL; > > out_fail: > inode_dec_link_count(inode); > @@ -202,7 +202,7 @@ static int ufs_mkdir(struct mnt_idmap * idmap, struct inode * dir, > discard_new_inode(inode); > out_dir: > inode_dec_link_count(dir); > - return err; > + return ERR_PTR(err); > } > > static int ufs_unlink(struct inode *dir, struct dentry *dentry) > diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c > index a859ac9b74ba..770e29ec3557 100644 > --- a/fs/vboxsf/dir.c > +++ b/fs/vboxsf/dir.c > @@ -303,11 +303,11 @@ static int vboxsf_dir_mkfile(struct mnt_idmap *idmap, > return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL); > } > > -static int vboxsf_dir_mkdir(struct mnt_idmap *idmap, > - struct inode *parent, struct dentry *dentry, > - umode_t mode) > +static struct dentry *vboxsf_dir_mkdir(struct mnt_idmap *idmap, > + struct inode *parent, struct dentry *dentry, > + umode_t mode) > { > - return vboxsf_dir_create(parent, dentry, mode, true, true, NULL); > + return ERR_PTR(vboxsf_dir_create(parent, dentry, mode, true, true, NULL)); > } > > static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry, > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c > index 40289fe6f5b2..a4480098d2bf 100644 > --- a/fs/xfs/xfs_iops.c > +++ b/fs/xfs/xfs_iops.c > @@ -298,14 +298,14 @@ xfs_vn_create( > return xfs_generic_create(idmap, dir, dentry, mode, 0, NULL); > } > > -STATIC int > +STATIC struct dentry * > xfs_vn_mkdir( > struct mnt_idmap *idmap, > struct inode *dir, > struct dentry *dentry, > umode_t mode) > { > - return xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL); > + return ERR_PTR(xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL)); > } > > STATIC struct dentry * > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 2c3b2f8a621f..45269608ee23 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2211,8 +2211,8 @@ struct inode_operations { > int (*unlink) (struct inode *,struct dentry *); > int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *, > const char *); > - int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *, > - umode_t); > + struct dentry *(*mkdir) (struct mnt_idmap *, struct inode *, > + struct dentry *, umode_t); > int (*rmdir) (struct inode *,struct dentry *); > int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *, > umode_t,dev_t); > diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c > index 9aaf5124648b..dc3aa91a6ba0 100644 > --- a/kernel/bpf/inode.c > +++ b/kernel/bpf/inode.c > @@ -150,14 +150,14 @@ static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode, > inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); > } > > -static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct inode *inode; > > inode = bpf_get_inode(dir->i_sb, dir, mode | S_IFDIR); > if (IS_ERR(inode)) > - return PTR_ERR(inode); > + return ERR_CAST(inode); > > inode->i_op = &bpf_dir_iops; > inode->i_fop = &simple_dir_operations; > @@ -166,7 +166,7 @@ static int bpf_mkdir(struct mnt_idmap *idmap, struct inode *dir, > inc_nlink(dir); > > bpf_dentry_finalize(dentry, inode, dir); > - return 0; > + return NULL; > } > > struct map_iter { > diff --git a/mm/shmem.c b/mm/shmem.c > index 4ea6109a8043..00ae0146e768 100644 > --- a/mm/shmem.c > +++ b/mm/shmem.c > @@ -3889,16 +3889,16 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir, > return error; > } > > -static int shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *shmem_mkdir(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > int error; > > error = shmem_mknod(idmap, dir, dentry, mode | S_IFDIR, 0); > if (error) > - return error; > + return ERR_PTR(error); > inc_nlink(dir); > - return 0; > + return NULL; > } > > static int shmem_create(struct mnt_idmap *idmap, struct inode *dir, > diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c > index c07d150685d7..6039afae4bfc 100644 > --- a/security/apparmor/apparmorfs.c > +++ b/security/apparmor/apparmorfs.c > @@ -1795,8 +1795,8 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) > return error; > } > > -static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, umode_t mode) > +static struct dentry *ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > + struct dentry *dentry, umode_t mode) > { > struct aa_ns *ns, *parent; > /* TODO: improve permission check */ > @@ -1808,7 +1808,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > AA_MAY_LOAD_POLICY); > end_current_label_crit_section(label); > if (error) > - return error; > + return ERR_PTR(error); > > parent = aa_get_ns(dir->i_private); > AA_BUG(d_inode(ns_subns_dir(parent)) != dir); > @@ -1843,7 +1843,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, > mutex_unlock(&parent->lock); > aa_put_ns(parent); > > - return error; > + return ERR_PTR(error); > } > > static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) > -- > 2.47.1 > ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-02-19 13:19 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-02-14 5:16 [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry NeilBrown 2025-02-14 5:16 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 2025-02-15 8:09 ` kernel test robot 2025-02-17 15:58 ` kernel test robot 2025-02-14 5:16 ` [PATCH 2/3] nfs: change mkdir inode_operation to return alternate dentry if needed NeilBrown 2025-02-14 5:16 ` [PATCH 3/3] VFS: Change vfs_mkdir() to return the dentry NeilBrown 2025-02-15 4:10 ` kernel test robot 2025-02-15 6:36 ` kernel test robot 2025-02-14 6:00 ` [PATCH 0/3} Change ->mkdir() and vfs_mkdir() to return a dentry Al Viro 2025-02-14 6:13 ` Al Viro 2025-02-14 6:33 ` Al Viro 2025-02-17 3:53 ` NeilBrown -- strict thread matches above, loose matches on Subject: below -- 2025-02-17 5:30 [PATCH 0/3 RFC v2] change " NeilBrown 2025-02-17 5:30 ` [PATCH 1/3] Change inode_operations.mkdir to return struct dentry * NeilBrown 2025-02-18 12:20 ` Jan Kara 2025-02-18 22:37 ` NeilBrown 2025-02-18 13:13 ` Jeff Layton 2025-02-19 13:19 ` Christian Brauner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox