From: NeilBrown <[email protected]>

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 <[email protected]>
Signed-off-by: NeilBrown <[email protected]>
---
 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 c417ba4bcec3..4c72af174540 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 10e732360ace..8faab04dc79f 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -252,10 +252,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,
@@ -365,8 +362,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 0ef73d739a31..3d82c6a19197 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -125,6 +125,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


Reply via email to