Commit 8dfec5a1 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] kNFSd: Protect reference to exp across calls to nfsd_cross_mnt

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.
parent a1de7361
......@@ -1686,6 +1686,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
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 *ccd, const char *name, int namlen,
* 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 *ccd, const char *name, int namlen,
dentry, p, &buflen, cd->rd_bmval,
cd->rd_rqstp);
dput(dentry);
exp_put(exp);
if (!nfserr) {
p += buflen;
goto out;
......
......@@ -141,10 +141,11 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
/* 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, struct svc_fh *fhp, const char *name,
err = nfserr_noent;
dput(dentry);
out:
exp_put(exp);
return err;
out_nfserr:
......
......@@ -110,6 +110,10 @@ static inline void exp_put(struct svc_export *exp)
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 fsid_type, u32 *fsidv,
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)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment