NFSD: Cleanup for nfsd4_path()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 12 Sep 2011 23:37:06 +0000 (19:37 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 14 Sep 2011 02:43:42 +0000 (22:43 -0400)
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: Trond Myklebust <Trond.Myklebust@netapp.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/export.c
fs/nfsd/nfs4xdr.c
include/linux/nfsd/export.h

index d491421..99229b0 100644 (file)
@@ -1009,7 +1009,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
        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];
 
@@ -1029,7 +1029,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
        struct svc_export *exp;
        __be32 rv;
 
-       exp = find_fsidzero_export(rqstp);
+       exp = rqst_find_fsidzero_export(rqstp);
        if (IS_ERR(exp))
                return nfserrno(PTR_ERR(exp));
        rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
index 182570b..5252d66 100644 (file)
@@ -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
- * Returned string is safe to use as long as the caller holds a reference
- * to @exp.
+ * Encode a path in RFC3530 'pathname4' format
  */
-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;
-       char *path = NULL, *rootpath;
-       size_t rootlen;
+       struct path cur = {
+               .mnt = path->mnt,
+               .dentry = path->dentry,
+       };
+       __be32 *p = *pp;
+       struct dentry **components = NULL;
+       unsigned int ncomponents = 0;
+       __be32 err = nfserr_jukebox;
 
-       fh_init(&tmp_fh, NFS4_FHSIZE);
-       *stat = exp_pseudoroot(rqstp, &tmp_fh);
-       if (*stat)
-               return NULL;
-       rootpath = tmp_fh.fh_export->ex_pathname;
+       dprintk("nfsd4_encode_components(");
 
-       path = exp->ex_pathname;
+       path_get(&cur);
+       /* First walk the path up to the nfsd root, and store the
+        * dentries/path components in an array.
+        */
+       for (;;) {
+               if (cur.dentry == root->dentry && cur.mnt == root->mnt)
+                       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);
+       }
 
-       rootlen = strlen(rootpath);
-       if (strncmp(path, rootpath, rootlen)) {
-               dprintk("nfsd: fs_locations failed;"
-                       "%s is not contained in %s\n", path, rootpath);
-               *stat = nfserr_notsupp;
-               path = NULL;
-               goto out;
+       *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:
-       fh_put(&tmp_fh);
-       return path;
+
+       *pp = p;
+       err = 0;
+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,
        int i;
        __be32 *p = *pp;
        struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
-       char *root = nfsd4_path(rqstp, exp, &status);
 
-       if (status)
-               return status;
-       status = nfsd4_encode_components('/', root, &p, buflen);
+       status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen);
        if (status)
                return status;
        if ((*buflen -= 4) < 0)
index 8a31a20..7ba3fd4 100644 (file)
@@ -137,6 +137,7 @@ struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
                                             struct path *);
 struct svc_export *    rqst_exp_parent(struct svc_rqst *,
                                        struct path *);
+struct svc_export *    rqst_find_fsidzero_export(struct svc_rqst *);
 int                    exp_rootfh(struct auth_domain *, 
                                        char *path, struct knfsd_fh *, int maxsize);
 __be32                 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);