Commit a1de7361 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] kNFSd: Change fh_compose to NOT consume a reference to the dentry.

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.
parent 4fc69688
...@@ -899,7 +899,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) ...@@ -899,7 +899,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
* fh must be initialized before calling fh_compose * fh must be initialized before calling fh_compose
*/ */
fh_init(&fh, maxsize); fh_init(&fh, maxsize);
if (fh_compose(&fh, exp, dget(nd.dentry), NULL)) if (fh_compose(&fh, exp, nd.dentry, NULL))
err = -EINVAL; err = -EINVAL;
else else
err = 0; err = 0;
...@@ -932,7 +932,6 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, ...@@ -932,7 +932,6 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
if (!fsid_key || IS_ERR(fsid_key)) if (!fsid_key || IS_ERR(fsid_key))
return nfserr_perm; return nfserr_perm;
dget(fsid_key->ek_export->ex_dentry);
rv = fh_compose(fhp, fsid_key->ek_export, rv = fh_compose(fhp, fsid_key->ek_export,
fsid_key->ek_export->ex_dentry, NULL); fsid_key->ek_export->ex_dentry, NULL);
expkey_put(&fsid_key->h, &svc_expkey_cache); expkey_put(&fsid_key->h, &svc_expkey_cache);
......
...@@ -799,6 +799,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, ...@@ -799,6 +799,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
{ {
struct svc_export *exp; struct svc_export *exp;
struct dentry *dparent, *dchild; struct dentry *dparent, *dchild;
int rv = 0;
dparent = cd->fh.fh_dentry; dparent = cd->fh.fh_dentry;
exp = cd->fh.fh_export; exp = cd->fh.fh_export;
...@@ -813,11 +814,12 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, ...@@ -813,11 +814,12 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
dchild = lookup_one_len(name, dparent, namlen); dchild = lookup_one_len(name, dparent, namlen);
if (IS_ERR(dchild)) if (IS_ERR(dchild))
return 1; return 1;
if (d_mountpoint(dchild)) if (d_mountpoint(dchild) ||
return 1; fh_compose(fhp, exp, dchild, &cd->fh) != 0 ||
if (fh_compose(fhp, exp, dchild, &cd->fh) != 0 || !dchild->d_inode) !dchild->d_inode)
return 1; rv = 1;
return 0; dput(dchild);
return rv;
} }
/* /*
......
...@@ -1706,6 +1706,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, ...@@ -1706,6 +1706,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
nfserr = nfsd4_encode_fattr(NULL, exp, nfserr = nfsd4_encode_fattr(NULL, exp,
dentry, p, &buflen, cd->rd_bmval, dentry, p, &buflen, cd->rd_bmval,
cd->rd_rqstp); cd->rd_rqstp);
dput(dentry);
if (!nfserr) { if (!nfserr) {
p += buflen; p += buflen;
goto out; goto out;
......
...@@ -367,7 +367,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -367,7 +367,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n", 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_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; fhp->fh_export = exp;
cache_get(&exp->h); cache_get(&exp->h);
......
...@@ -212,6 +212,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -212,6 +212,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
if (!nfserr && !dchild->d_inode) if (!nfserr && !dchild->d_inode)
nfserr = nfserr_noent; nfserr = nfserr_noent;
dput(dchild);
if (nfserr) { if (nfserr) {
if (nfserr != nfserr_noent) if (nfserr != nfserr_noent)
goto out_unlock; goto out_unlock;
......
...@@ -208,6 +208,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -208,6 +208,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
err = fh_compose(resfh, exp, dentry, fhp); err = fh_compose(resfh, exp, dentry, fhp);
if (!err && !dentry->d_inode) if (!err && !dentry->d_inode)
err = nfserr_noent; err = nfserr_noent;
dput(dentry);
out: out:
return err; return err;
...@@ -859,7 +860,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -859,7 +860,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *fname, int flen, struct iattr *iap, char *fname, int flen, struct iattr *iap,
int type, dev_t rdev, struct svc_fh *resfhp) int type, dev_t rdev, struct svc_fh *resfhp)
{ {
struct dentry *dentry, *dchild; struct dentry *dentry, *dchild = NULL;
struct inode *dirp; struct inode *dirp;
int err; int err;
...@@ -965,6 +966,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -965,6 +966,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!err) if (!err)
err = fh_update(resfhp); err = fh_update(resfhp);
out: out:
if (dchild && !IS_ERR(dchild))
dput(dchild);
return err; return err;
out_nfserr: out_nfserr:
...@@ -982,7 +985,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -982,7 +985,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct svc_fh *resfhp, int createmode, u32 *verifier, struct svc_fh *resfhp, int createmode, u32 *verifier,
int *truncp) int *truncp)
{ {
struct dentry *dentry, *dchild; struct dentry *dentry, *dchild = NULL;
struct inode *dirp; struct inode *dirp;
int err; int err;
__u32 v_mtime=0, v_atime=0; __u32 v_mtime=0, v_atime=0;
...@@ -1111,6 +1114,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1111,6 +1114,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
out: out:
fh_unlock(fhp); fh_unlock(fhp);
if (dchild && !IS_ERR(dchild))
dput(dchild);
return err; return err;
out_nfserr: out_nfserr:
......
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