Whamcloud - gitweb
LU-1994 kernel: fix reference counting with l_dentry_open
authorJeff Mahoney <jeffm@suse.com>
Thu, 21 Feb 2013 15:05:53 +0000 (10:05 -0500)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 22 Mar 2013 18:18:55 +0000 (14:18 -0400)
Commit 78b1d1bd (LU-1994 kernel: 3.6 dentry_open uses struct path
as first arg) added support for the new dentry_open call that
accepts struct path instead of a dentry/vfsmount pair, but missed
the new reference counting rules that go along with it.

Upstream commit 765927b2 also makes dentry_open grab references itself
so it no longer frees references that weren't passed to it.

On failure, we'll end up with an extra reference to the dentry
that was passed in.

Since new dentry_open is the one that will be around for the
foreseeable future, let's just map to that directly for the path case.

For the other two cases, we'll take the references ourselves in
ll_dentry_open, free them on failure, and adjust callers to expect
that it won't free any references passed to it.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Change-Id: I05a95cf735a5b2d70273a485335d571fcda7a6b0
Reviewed-on: http://review.whamcloud.com/5330
Reviewed-by: James Simmons <uja.ornl@gmail.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Hudson
Reviewed-by: Peng Tao <bergwolf@gmail.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>

index d25c168..e0a29ff 100644 (file)
@@ -140,19 +140,28 @@ static inline void ll_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
 #define ll_blkdev_put(a, b) blkdev_put(a)
-static inline struct file *ll_dentry_open(struct dentry *dentry,
-                                         struct vfsmount *mnt, int flags,
-                                         const struct cred *cred)
-       struct path path = { .mnt = mnt, .dentry = dentry };
-       return dentry_open(&path, flags, cred);
-#elif defined HAVE_DENTRY_OPEN_4ARGS
-       return dentry_open(dentry, mnt, flags, cred);
+#define ll_dentry_open(a,b,c)  dentry_open(a,b,c)
-       return dentry_open(dentry, mnt, flags);
+ * dentry_open handles its own reference counting since Linux v3.6
+ * (commit 765927b2). Callers should free their own references.
+ *
+ * Prior versions expected the caller to increment the references.
+ * The references are retained on success and freed on error.
+ */
+static inline struct file *ll_dentry_open(struct path *path, int flags,
+                                         const struct cred *cred)
+       mntget(path->mnt);
+       dget(path->dentry);
+       return dentry_open(path->dentry, path->mnt, flags, cred);
+# else
+       return dentry_open(path->dentry, path->mnt, flags);
+# endif
 #define ll_vfs_symlink(dir, dentry, mnt, path, mode) \
index a4f9340..a4538cc 100644 (file)
@@ -234,12 +234,15 @@ put_old:
-/* Note: dput(dchild) will be called if there is an error */
+/* Note: dput(dchild) will *not* be called if there is an error */
 struct l_file *l_dentry_open(struct lvfs_run_ctxt *ctxt, struct l_dentry *de,
-                             int flags)
+                            int flags)
-        mntget(ctxt->pwdmnt);
-        return ll_dentry_open(de, ctxt->pwdmnt, flags, current_cred());
+       struct path path = {
+               .dentry = de,
+               .mnt = ctxt->pwdmnt,
+       };
+       return ll_dentry_open(&path, flags, current_cred());
index 1debe27..9373474 100644 (file)
@@ -624,9 +624,9 @@ static int llog_lvfs_open(const struct lu_env *env,  struct llog_handle *handle,
                               logid->lgl_ogen, rc);
                        GOTO(out, rc);
-               /* l_dentry_open will call dput(dchild) if there is an error */
                handle->lgh_file = l_dentry_open(&obd->obd_lvfs_ctxt, dchild,
                                                 O_RDWR | O_LARGEFILE);
+               l_dput(dchild);
                if (IS_ERR(handle->lgh_file)) {
                        rc = PTR_ERR(handle->lgh_file);
                        handle->lgh_file = NULL;
@@ -736,6 +736,7 @@ static int llog_lvfs_create(const struct lu_env *env,
                        GOTO(out, rc = PTR_ERR(dchild));
                file = l_dentry_open(&obd->obd_lvfs_ctxt, dchild, open_flags);
+               l_dput(dchild);
                if (IS_ERR(file))
                        GOTO(out, rc = PTR_ERR(file));
                handle->lgh_id.lgl_oseq = oa->o_seq;