Commit ed748aac authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields

NFSD: Cleanup for nfsd4_path()

The current code is sort of hackish in that it assumes a referral is always
matched to an export. When we add support for junctions that may not be the
case.
We can replace nfsd4_path() with a function that encodes the components
directly from the dentries. Since nfsd4_path is currently the only user of
the 'ex_pathname' field in struct svc_export, this has the added benefit
of allowing us to get rid of that.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent ee626a77
...@@ -1009,7 +1009,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path) ...@@ -1009,7 +1009,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
return exp; return exp;
} }
static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp) struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
{ {
u32 fsidv[2]; u32 fsidv[2];
...@@ -1029,7 +1029,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) ...@@ -1029,7 +1029,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
struct svc_export *exp; struct svc_export *exp;
__be32 rv; __be32 rv;
exp = find_fsidzero_export(rqstp); exp = rqst_find_fsidzero_export(rqstp);
if (IS_ERR(exp)) if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp)); return nfserrno(PTR_ERR(exp));
rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
......
...@@ -1696,36 +1696,89 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, ...@@ -1696,36 +1696,89 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
} }
/* /*
* Return the path to an export point in the pseudo filesystem namespace * Encode a path in RFC3530 'pathname4' format
* Returned string is safe to use as long as the caller holds a reference
* to @exp.
*/ */
static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) static __be32 nfsd4_encode_path(const struct path *root,
const struct path *path, __be32 **pp, int *buflen)
{ {
struct svc_fh tmp_fh; struct path cur = {
char *path = NULL, *rootpath; .mnt = path->mnt,
size_t rootlen; .dentry = path->dentry,
};
fh_init(&tmp_fh, NFS4_FHSIZE); __be32 *p = *pp;
*stat = exp_pseudoroot(rqstp, &tmp_fh); struct dentry **components = NULL;
if (*stat) unsigned int ncomponents = 0;
return NULL; __be32 err = nfserr_jukebox;
rootpath = tmp_fh.fh_export->ex_pathname;
path = exp->ex_pathname; dprintk("nfsd4_encode_components(");
rootlen = strlen(rootpath); path_get(&cur);
if (strncmp(path, rootpath, rootlen)) { /* First walk the path up to the nfsd root, and store the
dprintk("nfsd: fs_locations failed;" * dentries/path components in an array.
"%s is not contained in %s\n", path, rootpath); */
*stat = nfserr_notsupp; for (;;) {
path = NULL; if (cur.dentry == root->dentry && cur.mnt == root->mnt)
goto out; break;
if (cur.dentry == cur.mnt->mnt_root) {
if (follow_up(&cur))
continue;
goto out_free;
}
if ((ncomponents & 15) == 0) {
struct dentry **new;
new = krealloc(components,
sizeof(*new) * (ncomponents + 16),
GFP_KERNEL);
if (!new)
goto out_free;
components = new;
}
components[ncomponents++] = cur.dentry;
cur.dentry = dget_parent(cur.dentry);
}
*buflen -= 4;
if (*buflen < 0)
goto out_free;
WRITE32(ncomponents);
while (ncomponents) {
struct dentry *dentry = components[ncomponents - 1];
unsigned int len = dentry->d_name.len;
*buflen -= 4 + (XDR_QUADLEN(len) << 2);
if (*buflen < 0)
goto out_free;
WRITE32(len);
WRITEMEM(dentry->d_name.name, len);
dprintk("/%s", dentry->d_name.name);
dput(dentry);
ncomponents--;
} }
path += rootlen;
out: *pp = p;
fh_put(&tmp_fh); err = 0;
return path; out_free:
dprintk(")\n");
while (ncomponents)
dput(components[--ncomponents]);
kfree(components);
path_put(&cur);
return err;
}
static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp,
const struct path *path, __be32 **pp, int *buflen)
{
struct svc_export *exp_ps;
__be32 res;
exp_ps = rqst_find_fsidzero_export(rqstp);
if (IS_ERR(exp_ps))
return nfserrno(PTR_ERR(exp_ps));
res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen);
exp_put(exp_ps);
return res;
} }
/* /*
...@@ -1739,11 +1792,8 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, ...@@ -1739,11 +1792,8 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
int i; int i;
__be32 *p = *pp; __be32 *p = *pp;
struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
char *root = nfsd4_path(rqstp, exp, &status);
if (status) status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen);
return status;
status = nfsd4_encode_components('/', root, &p, buflen);
if (status) if (status)
return status; return status;
if ((*buflen -= 4) < 0) if ((*buflen -= 4) < 0)
......
...@@ -137,6 +137,7 @@ struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, ...@@ -137,6 +137,7 @@ struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
struct path *); struct path *);
struct svc_export * rqst_exp_parent(struct svc_rqst *, struct svc_export * rqst_exp_parent(struct svc_rqst *,
struct path *); struct path *);
struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *);
int exp_rootfh(struct auth_domain *, int exp_rootfh(struct auth_domain *,
char *path, struct knfsd_fh *, int maxsize); char *path, struct knfsd_fh *, int maxsize);
__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
......
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