
From: NeilBrown <neilb@cse.unsw.edu.au>

fh_compose currently consumes a reference to the dentry but not the export
point.  This is both inconsistent and confusing.  

It is better if a routine like this doesn't consume reference points, so with
this patch, it doesn't.  This fixes a couple of very subtle and unusual
reference counting errors.


---

 25-akpm/fs/nfsd/export.c  |    3 +--
 25-akpm/fs/nfsd/nfs3xdr.c |   12 +++++++-----
 25-akpm/fs/nfsd/nfs4xdr.c |    1 +
 25-akpm/fs/nfsd/nfsfh.c   |    2 +-
 25-akpm/fs/nfsd/nfsproc.c |    1 +
 25-akpm/fs/nfsd/vfs.c     |    9 +++++++--
 6 files changed, 18 insertions(+), 10 deletions(-)

diff -puN fs/nfsd/export.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry fs/nfsd/export.c
--- 25/fs/nfsd/export.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry	Tue May 18 15:27:41 2004
+++ 25-akpm/fs/nfsd/export.c	Tue May 18 15:27:41 2004
@@ -899,7 +899,7 @@ exp_rootfh(svc_client *clp, char *path, 
 	 * fh must be initialized before calling fh_compose
 	 */
 	fh_init(&fh, maxsize);
-	if (fh_compose(&fh, exp, dget(nd.dentry), NULL))
+	if (fh_compose(&fh, exp, nd.dentry, NULL))
 		err = -EINVAL;
 	else
 		err = 0;
@@ -932,7 +932,6 @@ exp_pseudoroot(struct auth_domain *clp, 
 	if (!fsid_key || IS_ERR(fsid_key))
 		return nfserr_perm;
 
-	dget(fsid_key->ek_export->ex_dentry);
 	rv = fh_compose(fhp, fsid_key->ek_export, 
 			  fsid_key->ek_export->ex_dentry, NULL);
 	expkey_put(&fsid_key->h, &svc_expkey_cache);
diff -puN fs/nfsd/nfs3xdr.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry fs/nfsd/nfs3xdr.c
--- 25/fs/nfsd/nfs3xdr.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry	Tue May 18 15:27:41 2004
+++ 25-akpm/fs/nfsd/nfs3xdr.c	Tue May 18 15:27:41 2004
@@ -799,6 +799,7 @@ compose_entry_fh(struct nfsd3_readdirres
 {
 	struct svc_export	*exp;
 	struct dentry		*dparent, *dchild;
+	int rv = 0;
 
 	dparent = cd->fh.fh_dentry;
 	exp  = cd->fh.fh_export;
@@ -813,11 +814,12 @@ compose_entry_fh(struct nfsd3_readdirres
 		dchild = lookup_one_len(name, dparent, namlen);
 	if (IS_ERR(dchild))
 		return 1;
-	if (d_mountpoint(dchild))
-		return 1;
-	if (fh_compose(fhp, exp, dchild, &cd->fh) != 0 || !dchild->d_inode)
-		return 1;
-	return 0;
+	if (d_mountpoint(dchild) ||
+	    fh_compose(fhp, exp, dchild, &cd->fh) != 0 ||
+	    !dchild->d_inode)
+		rv = 1;
+	dput(dchild);
+	return rv;
 }
 
 /*
diff -puN fs/nfsd/nfs4xdr.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry fs/nfsd/nfs4xdr.c
--- 25/fs/nfsd/nfs4xdr.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry	Tue May 18 15:27:41 2004
+++ 25-akpm/fs/nfsd/nfs4xdr.c	Tue May 18 15:27:41 2004
@@ -1706,6 +1706,7 @@ nfsd4_encode_dirent(struct readdir_cd *c
 		nfserr = nfsd4_encode_fattr(NULL, exp,
 				dentry, p, &buflen, cd->rd_bmval,
 				cd->rd_rqstp);
+		dput(dentry);
 		if (!nfserr) {
 			p += buflen;
 			goto out;
diff -puN fs/nfsd/nfsfh.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry fs/nfsd/nfsfh.c
--- 25/fs/nfsd/nfsfh.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry	Tue May 18 15:27:41 2004
+++ 25-akpm/fs/nfsd/nfsfh.c	Tue May 18 15:27:41 2004
@@ -367,7 +367,7 @@ fh_compose(struct svc_fh *fhp, struct sv
 		printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
 		       fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
 
-	fhp->fh_dentry = dentry; /* our internal copy */
+	fhp->fh_dentry = dget(dentry); /* our internal copy */
 	fhp->fh_export = exp;
 	cache_get(&exp->h);
 
diff -puN fs/nfsd/nfsproc.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry fs/nfsd/nfsproc.c
--- 25/fs/nfsd/nfsproc.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry	Tue May 18 15:27:41 2004
+++ 25-akpm/fs/nfsd/nfsproc.c	Tue May 18 15:27:41 2004
@@ -212,6 +212,7 @@ nfsd_proc_create(struct svc_rqst *rqstp,
 	nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
 	if (!nfserr && !dchild->d_inode)
 		nfserr = nfserr_noent;
+	dput(dchild);
 	if (nfserr) {
 		if (nfserr != nfserr_noent)
 			goto out_unlock;
diff -puN fs/nfsd/vfs.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry fs/nfsd/vfs.c
--- 25/fs/nfsd/vfs.c~knfsd-4-of-10-change-fh_compose-to-not-consume-a-reference-to-the-dentry	Tue May 18 15:27:41 2004
+++ 25-akpm/fs/nfsd/vfs.c	Tue May 18 15:27:41 2004
@@ -208,6 +208,7 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
 	err = fh_compose(resfh, exp, dentry, fhp);
 	if (!err && !dentry->d_inode)
 		err = nfserr_noent;
+	dput(dentry);
 out:
 	return err;
 
@@ -859,7 +860,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
 		char *fname, int flen, struct iattr *iap,
 		int type, dev_t rdev, struct svc_fh *resfhp)
 {
-	struct dentry	*dentry, *dchild;
+	struct dentry	*dentry, *dchild = NULL;
 	struct inode	*dirp;
 	int		err;
 
@@ -965,6 +966,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
 	if (!err)
 		err = fh_update(resfhp);
 out:
+	if (dchild && !IS_ERR(dchild))
+		dput(dchild);
 	return err;
 
 out_nfserr:
@@ -982,7 +985,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 		struct svc_fh *resfhp, int createmode, u32 *verifier,
 	        int *truncp)
 {
-	struct dentry	*dentry, *dchild;
+	struct dentry	*dentry, *dchild = NULL;
 	struct inode	*dirp;
 	int		err;
 	__u32		v_mtime=0, v_atime=0;
@@ -1111,6 +1114,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 
  out:
 	fh_unlock(fhp);
+	if (dchild && !IS_ERR(dchild))
+		dput(dchild);
  	return err;
  
  out_nfserr:

_
