From: NeilBrown Occasionally the caller of end_creating() wants to keep using the dentry. Rather then requiring them to dget() the dentry (when not an error) before calling end_creating(), provide end_creating_keep() which does this. cachefiles and overlayfs make use of this. Reviewed-by: Amir Goldstein Reviewed-by: Jeff Layton Signed-off-by: NeilBrown --- fs/cachefiles/namei.c | 3 +-- fs/overlayfs/dir.c | 8 ++------ fs/overlayfs/super.c | 11 +++-------- include/linux/namei.h | 22 ++++++++++++++++++++++ 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 59327618ac42..ef22ac19545b 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -155,8 +155,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, /* Tell rmdir() it's not allowed to delete the subdir */ inode_lock(d_inode(subdir)); - dget(subdir); - end_creating(subdir); + end_creating_keep(subdir); if (!__cachefiles_mark_inode_in_use(NULL, d_inode(subdir))) { pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n", diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 739f974dc258..d21f81a524f6 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -251,10 +251,7 @@ struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir, if (IS_ERR(ret)) return ret; ret = ovl_create_real(ofs, workdir, ret, attr); - if (!IS_ERR(ret)) - dget(ret); - end_creating(ret); - return ret; + return end_creating_keep(ret); } static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper, @@ -364,8 +361,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, if (IS_ERR(newdentry)) return PTR_ERR(newdentry); - dget(newdentry); - end_creating(newdentry); + end_creating_keep(newdentry); if (ovl_type_merge(dentry->d_parent) && d_is_dir(newdentry) && !ovl_allow_offline_changes(ofs)) { diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 3acda985c8a3..7b8fc1cab6eb 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -319,8 +319,7 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, }; if (work->d_inode) { - dget(work); - end_creating(work); + end_creating_keep(work); if (persist) return work; err = -EEXIST; @@ -336,9 +335,7 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, } work = ovl_do_mkdir(ofs, dir, work, attr.ia_mode); - if (!IS_ERR(work)) - dget(work); - end_creating(work); + end_creating_keep(work); err = PTR_ERR(work); if (IS_ERR(work)) goto out_err; @@ -630,9 +627,7 @@ static struct dentry *ovl_lookup_or_create(struct ovl_fs *ofs, if (!child->d_inode) child = ovl_create_real(ofs, parent, child, OVL_CATTR(mode)); - if (!IS_ERR(child)) - dget(child); - end_creating(child); + end_creating_keep(child); } dput(parent); diff --git a/include/linux/namei.h b/include/linux/namei.h index b4d95b79b5a8..58600cf234bc 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -126,6 +126,28 @@ static inline void end_creating(struct dentry *child) end_dirop(child); } +/* end_creating_keep - finish action started with start_creating() and return result + * @child: dentry returned by start_creating() or vfs_mkdir() + * + * Unlock and return the child. This can be called after + * start_creating() whether that function succeeded or not, + * but it is not needed on failure. + * + * If vfs_mkdir() was called then the value returned from that function + * should be given for @child rather than the original dentry, as vfs_mkdir() + * may have provided a new dentry. + * + * Returns: @child, which may be a dentry or an error. + * + */ +static inline struct dentry *end_creating_keep(struct dentry *child) +{ + if (!IS_ERR(child)) + dget(child); + end_dirop(child); + return child; +} + /** * end_removing - finish action started with start_removing * @child: dentry returned by start_removing() -- 2.50.0.107.gf914562f5916.dirty