From: Jeff Mahoney Date: Thu, 21 Feb 2013 15:05:53 +0000 (-0500) Subject: LU-1994 kernel: fix reference counting with l_dentry_open X-Git-Tag: 2.3.63~15 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=1e149bef8d832aade6c04b65b8308b71c6d523ed;hp=34d5ccc193c948c5946f2363976de09eb0f2ab10 LU-1994 kernel: fix reference counting with l_dentry_open 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 Change-Id: I05a95cf735a5b2d70273a485335d571fcda7a6b0 Reviewed-on: http://review.whamcloud.com/5330 Reviewed-by: James Simmons Reviewed-by: Andreas Dilger Tested-by: Hudson Reviewed-by: Peng Tao Tested-by: Maloo --- diff --git a/lustre/include/linux/lustre_compat25.h b/lustre/include/linux/lustre_compat25.h index d25c168..e0a29ff 100644 --- a/lustre/include/linux/lustre_compat25.h +++ b/lustre/include/linux/lustre_compat25.h @@ -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) #endif -static inline struct file *ll_dentry_open(struct dentry *dentry, - struct vfsmount *mnt, int flags, - const struct cred *cred) -{ #ifdef HAVE_DENTRY_OPEN_USE_PATH - 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) #else - return dentry_open(dentry, mnt, flags); -#endif +/* + * 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); +# ifdef HAVE_DENTRY_OPEN_4ARGS + return dentry_open(path->dentry, path->mnt, flags, cred); +# else + return dentry_open(path->dentry, path->mnt, flags); +# endif } +#endif #ifdef HAVE_SECURITY_PLUG #define ll_vfs_symlink(dir, dentry, mnt, path, mode) \ diff --git a/lustre/lvfs/lvfs_linux.c b/lustre/lvfs/lvfs_linux.c index a4f9340..a4538cc 100644 --- a/lustre/lvfs/lvfs_linux.c +++ b/lustre/lvfs/lvfs_linux.c @@ -234,12 +234,15 @@ put_old: } EXPORT_SYMBOL(lustre_rename); -/* 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()); } EXPORT_SYMBOL(l_dentry_open); diff --git a/lustre/obdclass/llog_lvfs.c b/lustre/obdclass/llog_lvfs.c index 1debe27..9373474 100644 --- a/lustre/obdclass/llog_lvfs.c +++ b/lustre/obdclass/llog_lvfs.c @@ -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;