mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-12 16:11:04 +00:00
knfsd: nfsd: make all exp_finding functions return -errno's on err
Currently exp_find(), exp_get_by_name(), and friends, return an export on success, and on failure return: errors -EAGAIN (drop this request pending an upcall) or -ETIMEDOUT (an upcall has timed out), or return NULL, which can mean either that there was a memory allocation failure, or that an export was not found, or that a passed-in export lacks an auth_domain. Many callers seem to assume that NULL means that an export was not found, which may lead to bugs in the case of a memory allocation failure. Modify these functions to distinguish between the two NULL cases by returning either -ENOENT or -ENOMEM. They now never return NULL. We get to simplify some code in the process. We return -ENOENT in the case of a missing auth_domain. This case should probably be removed (or converted to a bug) after confirming that it can never happen. Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
47f9940c55
commit
2d3bb25209
@ -739,16 +739,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!clp)
|
if (!clp)
|
||||||
return NULL;
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
key.ek_client = clp;
|
key.ek_client = clp;
|
||||||
key.ek_fsidtype = fsid_type;
|
key.ek_fsidtype = fsid_type;
|
||||||
memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
|
memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
|
||||||
|
|
||||||
ek = svc_expkey_lookup(&key);
|
ek = svc_expkey_lookup(&key);
|
||||||
if (ek != NULL)
|
if (ek == NULL)
|
||||||
if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
|
return ERR_PTR(-ENOMEM);
|
||||||
ek = ERR_PTR(err);
|
err = cache_check(&svc_expkey_cache, &ek->h, reqp);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
return ek;
|
return ek;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,30 +811,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
|
|||||||
struct cache_req *reqp)
|
struct cache_req *reqp)
|
||||||
{
|
{
|
||||||
struct svc_export *exp, key;
|
struct svc_export *exp, key;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!clp)
|
if (!clp)
|
||||||
return NULL;
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
key.ex_client = clp;
|
key.ex_client = clp;
|
||||||
key.ex_mnt = mnt;
|
key.ex_mnt = mnt;
|
||||||
key.ex_dentry = dentry;
|
key.ex_dentry = dentry;
|
||||||
|
|
||||||
exp = svc_export_lookup(&key);
|
exp = svc_export_lookup(&key);
|
||||||
if (exp != NULL) {
|
if (exp == NULL)
|
||||||
int err;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
err = cache_check(&svc_export_cache, &exp->h, reqp);
|
||||||
err = cache_check(&svc_export_cache, &exp->h, reqp);
|
if (err)
|
||||||
switch (err) {
|
return ERR_PTR(err);
|
||||||
case 0: break;
|
|
||||||
case -EAGAIN:
|
|
||||||
case -ETIMEDOUT:
|
|
||||||
exp = ERR_PTR(err);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
exp = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +841,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
|
|||||||
dget(dentry);
|
dget(dentry);
|
||||||
exp = exp_get_by_name(clp, mnt, dentry, reqp);
|
exp = exp_get_by_name(clp, mnt, dentry, reqp);
|
||||||
|
|
||||||
while (exp == NULL && !IS_ROOT(dentry)) {
|
while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
|
|
||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
@ -901,7 +894,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
|
ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
|
||||||
if (ek && !IS_ERR(ek)) {
|
if (!IS_ERR(ek)) {
|
||||||
ek->h.expiry_time = get_seconds()-1;
|
ek->h.expiry_time = get_seconds()-1;
|
||||||
cache_put(&ek->h, &svc_expkey_cache);
|
cache_put(&ek->h, &svc_expkey_cache);
|
||||||
}
|
}
|
||||||
@ -939,7 +932,7 @@ static void exp_unhash(struct svc_export *exp)
|
|||||||
struct inode *inode = exp->ex_dentry->d_inode;
|
struct inode *inode = exp->ex_dentry->d_inode;
|
||||||
|
|
||||||
ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
|
ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
|
||||||
if (ek && !IS_ERR(ek)) {
|
if (!IS_ERR(ek)) {
|
||||||
ek->h.expiry_time = get_seconds()-1;
|
ek->h.expiry_time = get_seconds()-1;
|
||||||
cache_put(&ek->h, &svc_expkey_cache);
|
cache_put(&ek->h, &svc_expkey_cache);
|
||||||
}
|
}
|
||||||
@ -990,13 +983,12 @@ exp_export(struct nfsctl_export *nxp)
|
|||||||
|
|
||||||
/* must make sure there won't be an ex_fsid clash */
|
/* must make sure there won't be an ex_fsid clash */
|
||||||
if ((nxp->ex_flags & NFSEXP_FSID) &&
|
if ((nxp->ex_flags & NFSEXP_FSID) &&
|
||||||
(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
|
(!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
|
||||||
!IS_ERR(fsid_key) &&
|
|
||||||
fsid_key->ek_mnt &&
|
fsid_key->ek_mnt &&
|
||||||
(fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
|
(fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
if (exp) {
|
if (!IS_ERR(exp)) {
|
||||||
/* just a flags/id/fsid update */
|
/* just a flags/id/fsid update */
|
||||||
|
|
||||||
exp_fsid_unhash(exp);
|
exp_fsid_unhash(exp);
|
||||||
@ -1105,7 +1097,7 @@ exp_unexport(struct nfsctl_export *nxp)
|
|||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
|
exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
|
||||||
path_release(&nd);
|
path_release(&nd);
|
||||||
if (!exp)
|
if (IS_ERR(exp))
|
||||||
goto out_domain;
|
goto out_domain;
|
||||||
|
|
||||||
exp_do_unexport(exp);
|
exp_do_unexport(exp);
|
||||||
@ -1150,10 +1142,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
|
|||||||
err = PTR_ERR(exp);
|
err = PTR_ERR(exp);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!exp) {
|
|
||||||
dprintk("nfsd: exp_rootfh export not found.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fh must be initialized before calling fh_compose
|
* fh must be initialized before calling fh_compose
|
||||||
@ -1177,13 +1165,13 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
|
|||||||
{
|
{
|
||||||
struct svc_export *exp;
|
struct svc_export *exp;
|
||||||
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
|
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
|
||||||
if (!ek || IS_ERR(ek))
|
if (IS_ERR(ek))
|
||||||
return ERR_PTR(PTR_ERR(ek));
|
return ERR_PTR(PTR_ERR(ek));
|
||||||
|
|
||||||
exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
|
exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
|
||||||
cache_put(&ek->h, &svc_expkey_cache);
|
cache_put(&ek->h, &svc_expkey_cache);
|
||||||
|
|
||||||
if (!exp || IS_ERR(exp))
|
if (IS_ERR(exp))
|
||||||
return ERR_PTR(PTR_ERR(exp));
|
return ERR_PTR(PTR_ERR(exp));
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
@ -1205,10 +1193,10 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
|
|||||||
mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
|
mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
|
||||||
|
|
||||||
exp = exp_find(clp, FSID_NUM, fsidv, creq);
|
exp = exp_find(clp, FSID_NUM, fsidv, creq);
|
||||||
|
if (PTR_ERR(exp) == -ENOENT)
|
||||||
|
return nfserr_perm;
|
||||||
if (IS_ERR(exp))
|
if (IS_ERR(exp))
|
||||||
return nfserrno(PTR_ERR(exp));
|
return nfserrno(PTR_ERR(exp));
|
||||||
if (exp == NULL)
|
|
||||||
return nfserr_perm;
|
|
||||||
rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
|
rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
|
||||||
exp_put(exp);
|
exp_put(exp);
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -160,16 +160,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
|||||||
&rqstp->rq_chandle);
|
&rqstp->rq_chandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
|
error = nfserr_stale;
|
||||||
|| PTR_ERR(exp) == -ETIMEDOUT)) {
|
if (PTR_ERR(exp) == -ENOENT)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (IS_ERR(exp)) {
|
||||||
error = nfserrno(PTR_ERR(exp));
|
error = nfserrno(PTR_ERR(exp));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = nfserr_stale;
|
|
||||||
if (!exp || IS_ERR(exp))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Check if the request originated from a secure port. */
|
/* Check if the request originated from a secure port. */
|
||||||
error = nfserr_perm;
|
error = nfserr_perm;
|
||||||
if (!rqstp->rq_secure && EX_SECURE(exp)) {
|
if (!rqstp->rq_secure && EX_SECURE(exp)) {
|
||||||
|
@ -192,15 +192,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
|
|||||||
|
|
||||||
exp2 = exp_parent(exp->ex_client, mnt, dentry,
|
exp2 = exp_parent(exp->ex_client, mnt, dentry,
|
||||||
&rqstp->rq_chandle);
|
&rqstp->rq_chandle);
|
||||||
if (IS_ERR(exp2)) {
|
if (PTR_ERR(exp2) == -ENOENT) {
|
||||||
|
dput(dentry);
|
||||||
|
dentry = dget(dparent);
|
||||||
|
} else if (IS_ERR(exp2)) {
|
||||||
host_err = PTR_ERR(exp2);
|
host_err = PTR_ERR(exp2);
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
mntput(mnt);
|
mntput(mnt);
|
||||||
goto out_nfserr;
|
goto out_nfserr;
|
||||||
}
|
|
||||||
if (!exp2) {
|
|
||||||
dput(dentry);
|
|
||||||
dentry = dget(dparent);
|
|
||||||
} else {
|
} else {
|
||||||
exp_put(exp);
|
exp_put(exp);
|
||||||
exp = exp2;
|
exp = exp2;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user