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

nfsd_cross_mnt can release the reference to the passed svc_export structure
when it returns a different svc_export structure.  So we need to make sure we
have a counted reference before, and drop the reference afterwards.


---

 25-akpm/fs/nfsd/nfs4xdr.c           |    3 +++
 25-akpm/fs/nfsd/vfs.c               |    4 +++-
 25-akpm/include/linux/nfsd/export.h |    6 +++++-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff -puN fs/nfsd/nfs4xdr.c~knfsd-5-of-10-protect-reference-to-exp-across-calls-to-nfsd_cross_mnt fs/nfsd/nfs4xdr.c
--- 25/fs/nfsd/nfs4xdr.c~knfsd-5-of-10-protect-reference-to-exp-across-calls-to-nfsd_cross_mnt	Tue May 18 15:27:42 2004
+++ 25-akpm/fs/nfsd/nfs4xdr.c	Tue May 18 15:27:42 2004
@@ -1686,6 +1686,7 @@ nfsd4_encode_dirent(struct readdir_cd *c
 			goto error;
 		}
 
+		exp_get(exp);
 		if (d_mountpoint(dentry)) {
 			if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, 
 					 &exp))) {	
@@ -1697,6 +1698,7 @@ nfsd4_encode_dirent(struct readdir_cd *c
 			 * this call will be retried.
 			 */
 				dput(dentry);
+				exp_put(exp);
 				nfserr = nfserr_dropit;
 				goto error;
 			}
@@ -1707,6 +1709,7 @@ nfsd4_encode_dirent(struct readdir_cd *c
 				dentry, p, &buflen, cd->rd_bmval,
 				cd->rd_rqstp);
 		dput(dentry);
+		exp_put(exp);
 		if (!nfserr) {
 			p += buflen;
 			goto out;
diff -puN fs/nfsd/vfs.c~knfsd-5-of-10-protect-reference-to-exp-across-calls-to-nfsd_cross_mnt fs/nfsd/vfs.c
--- 25/fs/nfsd/vfs.c~knfsd-5-of-10-protect-reference-to-exp-across-calls-to-nfsd_cross_mnt	Tue May 18 15:27:42 2004
+++ 25-akpm/fs/nfsd/vfs.c	Tue May 18 15:27:42 2004
@@ -141,10 +141,11 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
 	/* Obtain dentry and export. */
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
 	if (err)
-		goto out;
+		return err;
 
 	dparent = fhp->fh_dentry;
 	exp  = fhp->fh_export;
+	exp_get(exp);
 
 	err = nfserr_acces;
 
@@ -210,6 +211,7 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
 		err = nfserr_noent;
 	dput(dentry);
 out:
+	exp_put(exp);
 	return err;
 
 out_nfserr:
diff -puN include/linux/nfsd/export.h~knfsd-5-of-10-protect-reference-to-exp-across-calls-to-nfsd_cross_mnt include/linux/nfsd/export.h
--- 25/include/linux/nfsd/export.h~knfsd-5-of-10-protect-reference-to-exp-across-calls-to-nfsd_cross_mnt	Tue May 18 15:27:42 2004
+++ 25-akpm/include/linux/nfsd/export.h	Tue May 18 15:27:42 2004
@@ -110,6 +110,10 @@ static inline void exp_put(struct svc_ex
 	svc_export_put(&exp->h, &svc_export_cache);
 }
 
+static inline void exp_get(struct svc_export *exp)
+{
+	cache_get(&exp->h);
+}
 static inline struct svc_export *
 exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
 	 struct cache_req *reqp)
@@ -118,7 +122,7 @@ exp_find(struct auth_domain *clp, int fs
 	if (ek && !IS_ERR(ek)) {
 		struct svc_export *exp = ek->ek_export;
 		int err;
-		cache_get(&exp->h);
+		exp_get(exp);
 		expkey_put(&ek->h, &svc_expkey_cache);
 		if (exp &&
 		    (err = cache_check(&svc_export_cache, &exp->h, reqp)))

_