nfsd4: fix error return when pseudoroot missing
[safe/jmp/linux-2.6] / fs / nfsd / export.c
index 3f6d51b..b73baba 100644 (file)
@@ -85,6 +85,11 @@ static void expkey_request(struct cache_detail *cd,
        (*bpp)[-1] = '\n';
 }
 
+static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
+}
+
 static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
 static struct cache_detail svc_expkey_cache;
@@ -259,7 +264,7 @@ static struct cache_detail svc_expkey_cache = {
        .hash_table     = expkey_table,
        .name           = "nfsd.fh",
        .cache_put      = expkey_put,
-       .cache_request  = expkey_request,
+       .cache_upcall   = expkey_upcall,
        .cache_parse    = expkey_parse,
        .cache_show     = expkey_show,
        .match          = expkey_match,
@@ -355,6 +360,11 @@ static void svc_export_request(struct cache_detail *cd,
        (*bpp)[-1] = '\n';
 }
 
+static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
+}
+
 static struct svc_export *svc_export_update(struct svc_export *new,
                                            struct svc_export *old);
 static struct svc_export *svc_export_lookup(struct svc_export *);
@@ -464,16 +474,11 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
                if (err)
                        return err;
                /*
-                * Just a quick sanity check; we could also try to check
-                * whether this pseudoflavor is supported, but at worst
-                * an unsupported pseudoflavor on the export would just
-                * be a pseudoflavor that won't match the flavor of any
-                * authenticated request.  The administrator will
-                * probably discover the problem when someone fails to
-                * authenticate.
+                * XXX: It would be nice to also check whether this
+                * pseudoflavor is supported, so we can discover the
+                * problem at export time instead of when a client fails
+                * to authenticate.
                 */
-               if (f->pseudoflavor < 0)
-                       return -EINVAL;
                err = get_int(mesg, &f->flags);
                if (err)
                        return err;
@@ -729,7 +734,7 @@ struct cache_detail svc_export_cache = {
        .hash_table     = export_table,
        .name           = "nfsd.export",
        .cache_put      = svc_export_put,
-       .cache_request  = svc_export_request,
+       .cache_upcall   = svc_export_upcall,
        .cache_parse    = svc_export_parse,
        .cache_show     = svc_export_show,
        .match          = svc_export_match,
@@ -871,23 +876,19 @@ static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
 /*
  * Find the export entry for a given dentry.
  */
-static struct svc_export *exp_parent(svc_client *clp, struct vfsmount *mnt,
-                                    struct dentry *dentry,
-                                    struct cache_req *reqp)
+static struct svc_export *exp_parent(svc_client *clp, struct path *path)
 {
-       struct path path = {.mnt = mnt, .dentry = dentry};
-       svc_export *exp;
-
-       dget(path.dentry);
-       exp = exp_get_by_name(clp, &path, reqp);
-
-       while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path.dentry)) {
-               struct dentry *parent = dget_parent(path.dentry);
-               dput(path.dentry);
-               path.dentry = parent;
-               exp = exp_get_by_name(clp, &path, reqp);
+       struct dentry *saved = dget(path->dentry);
+       svc_export *exp = exp_get_by_name(clp, path, NULL);
+
+       while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
+               struct dentry *parent = dget_parent(path->dentry);
+               dput(path->dentry);
+               path->dentry = parent;
+               exp = exp_get_by_name(clp, path, NULL);
        }
-       dput(path.dentry);
+       dput(path->dentry);
+       path->dentry = saved;
        return exp;
 }
 
@@ -1174,7 +1175,7 @@ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
        dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
                 name, path.dentry, clp->name,
                 inode->i_sb->s_id, inode->i_ino);
-       exp = exp_parent(clp, path.mnt, path.dentry, NULL);
+       exp = exp_parent(clp, &path);
        if (IS_ERR(exp)) {
                err = PTR_ERR(exp);
                goto out;
@@ -1244,18 +1245,15 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
  * use exp_get_by_name() or exp_find().
  */
 struct svc_export *
-rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
-               struct dentry *dentry)
+rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
 {
        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
-       struct path path = {.mnt = mnt, .dentry = dentry};
 
        if (rqstp->rq_client == NULL)
                goto gss;
 
        /* First try the auth_unix client: */
-       exp = exp_get_by_name(rqstp->rq_client, &path,
-                                               &rqstp->rq_chandle);
+       exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
        if (PTR_ERR(exp) == -ENOENT)
                goto gss;
        if (IS_ERR(exp))
@@ -1267,8 +1265,7 @@ gss:
        /* Otherwise, try falling back on gss client */
        if (rqstp->rq_gssclient == NULL)
                return exp;
-       gssexp = exp_get_by_name(rqstp->rq_gssclient, &path,
-                                               &rqstp->rq_chandle);
+       gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
        if (PTR_ERR(gssexp) == -ENOENT)
                return exp;
        if (!IS_ERR(exp))
@@ -1307,23 +1304,36 @@ gss:
 }
 
 struct svc_export *
-rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
-               struct dentry *dentry)
+rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
 {
-       struct svc_export *exp;
+       struct dentry *saved = dget(path->dentry);
+       struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
+
+       while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
+               struct dentry *parent = dget_parent(path->dentry);
+               dput(path->dentry);
+               path->dentry = parent;
+               exp = rqst_exp_get_by_name(rqstp, path);
+       }
+       dput(path->dentry);
+       path->dentry = saved;
+       return exp;
+}
 
-       dget(dentry);
-       exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
+static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp)
+{
+       struct svc_export *exp;
+       u32 fsidv[2];
 
-       while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
-               struct dentry *parent;
+       mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
 
-               parent = dget_parent(dentry);
-               dput(dentry);
-               dentry = parent;
-               exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
-       }
-       dput(dentry);
+       exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
+       /*
+        * We shouldn't have accepting an nfsv4 request at all if we
+        * don't have a pseudoexport!:
+        */
+       if (IS_ERR(exp) && PTR_ERR(exp) == -ENOENT)
+               exp = ERR_PTR(-ESERVERFAULT);
        return exp;
 }
 
@@ -1337,17 +1347,16 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
 {
        struct svc_export *exp;
        __be32 rv;
-       u32 fsidv[2];
 
-       mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
-
-       exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
+       exp = find_fsidzero_export(rqstp);
        if (IS_ERR(exp))
                return nfserrno(PTR_ERR(exp));
        rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
        if (rv)
                goto out;
        rv = check_nfsd_access(exp, rqstp);
+       if (rv)
+               fh_put(fhp);
 out:
        exp_put(exp);
        return rv;
@@ -1522,7 +1531,7 @@ static int e_show(struct seq_file *m, void *p)
        return svc_export_show(m, &svc_export_cache, cp);
 }
 
-struct seq_operations nfs_exports_op = {
+const struct seq_operations nfs_exports_op = {
        .start  = e_start,
        .next   = e_next,
        .stop   = e_stop,