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, ...@@ -1686,6 +1686,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
goto error; goto error;
} }
exp_get(exp);
if (d_mountpoint(dentry)) { if (d_mountpoint(dentry)) {
if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry,
&exp))) { &exp))) {
...@@ -1697,6 +1698,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, ...@@ -1697,6 +1698,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
* this call will be retried. * this call will be retried.
*/ */
dput(dentry); dput(dentry);
exp_put(exp);
nfserr = nfserr_dropit; nfserr = nfserr_dropit;
goto error; goto error;
} }
...@@ -1707,6 +1709,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, ...@@ -1707,6 +1709,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
dentry, p, &buflen, cd->rd_bmval, dentry, p, &buflen, cd->rd_bmval,
cd->rd_rqstp); cd->rd_rqstp);
dput(dentry); dput(dentry);
exp_put(exp);
if (!nfserr) { if (!nfserr) {
p += buflen; p += buflen;
goto out; goto out;
......
...@@ -141,10 +141,11 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -141,10 +141,11 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
/* Obtain dentry and export. */ /* Obtain dentry and export. */
err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC); err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
if (err) if (err)
goto out; return err;
dparent = fhp->fh_dentry; dparent = fhp->fh_dentry;
exp = fhp->fh_export; exp = fhp->fh_export;
exp_get(exp);
err = nfserr_acces; err = nfserr_acces;
...@@ -210,6 +211,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -210,6 +211,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
err = nfserr_noent; err = nfserr_noent;
dput(dentry); dput(dentry);
out: out:
exp_put(exp);
return err; return err;
out_nfserr: out_nfserr:
......
...@@ -110,6 +110,10 @@ static inline void exp_put(struct svc_export *exp) ...@@ -110,6 +110,10 @@ static inline void exp_put(struct svc_export *exp)
svc_export_put(&exp->h, &svc_export_cache); 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 * static inline struct svc_export *
exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
struct cache_req *reqp) struct cache_req *reqp)
...@@ -118,7 +122,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, ...@@ -118,7 +122,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
if (ek && !IS_ERR(ek)) { if (ek && !IS_ERR(ek)) {
struct svc_export *exp = ek->ek_export; struct svc_export *exp = ek->ek_export;
int err; int err;
cache_get(&exp->h); exp_get(exp);
expkey_put(&ek->h, &svc_expkey_cache); expkey_put(&ek->h, &svc_expkey_cache);
if (exp && if (exp &&
(err = cache_check(&svc_export_cache, &exp->h, reqp))) (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