Merge branch 'for-2.6.34' of git://linux-nfs.org/~bfields/linux
[linux-2.6.git] / fs / nfsd / nfs4xdr.c
index 00ed16a..78c7e24 100644 (file)
  * at the end of nfs4svc_decode_compoundargs.
  */
 
-#include <linux/param.h>
-#include <linux/smp.h>
-#include <linux/fs.h>
 #include <linux/namei.h>
-#include <linux/vfs.h>
+#include <linux/statfs.h>
 #include <linux/utsname.h>
-#include <linux/sunrpc/xdr.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/state.h>
-#include <linux/nfsd/xdr4.h>
 #include <linux/nfsd_idmap.h>
-#include <linux/nfs4.h>
 #include <linux/nfs4_acl.h>
-#include <linux/sunrpc/gss_api.h>
 #include <linux/sunrpc/svcauth_gss.h>
 
+#include "xdr4.h"
+#include "vfs.h"
+
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
 /*
@@ -1442,7 +1434,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                }
                op->opnum = ntohl(*argp->p++);
 
-               if (op->opnum >= OP_ACCESS && op->opnum < ops->nops)
+               if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
                        op->status = ops->decoders[op->opnum](argp, &op->u);
                else {
                        op->opnum = OP_ILLEGAL;
@@ -1599,7 +1591,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
 static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
 {
        struct svc_fh tmp_fh;
-       char *path, *rootpath;
+       char *path = NULL, *rootpath;
+       size_t rootlen;
 
        fh_init(&tmp_fh, NFS4_FHSIZE);
        *stat = exp_pseudoroot(rqstp, &tmp_fh);
@@ -1609,14 +1602,18 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
 
        path = exp->ex_pathname;
 
-       if (strncmp(path, rootpath, strlen(rootpath))) {
+       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;
-               return NULL;
+               path = NULL;
+               goto out;
        }
-
-       return path + strlen(rootpath);
+       path += rootlen;
+out:
+       fh_put(&tmp_fh);
+       return path;
 }
 
 /*
@@ -2124,9 +2121,15 @@ out_acl:
                 * and this is the root of a cross-mounted filesystem.
                 */
                if (ignore_crossmnt == 0 &&
-                   exp->ex_path.mnt->mnt_root->d_inode == dentry->d_inode) {
-                       err = vfs_getattr(exp->ex_path.mnt->mnt_parent,
-                               exp->ex_path.mnt->mnt_mountpoint, &stat);
+                   dentry == exp->ex_path.mnt->mnt_root) {
+                       struct path path = exp->ex_path;
+                       path_get(&path);
+                       while (follow_up(&path)) {
+                               if (path.dentry != path.mnt->mnt_root)
+                                       break;
+                       }
+                       err = vfs_getattr(path.mnt, path.dentry, &stat);
+                       path_put(&path);
                        if (err)
                                goto out_nfserr;
                }
@@ -2199,11 +2202,14 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
         * we will not follow the cross mount and will fill the attribtutes
         * directly from the mountpoint dentry.
         */
-       if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
-               ignore_crossmnt = 1;
-       else if (d_mountpoint(dentry)) {
+       if (nfsd_mountpoint(dentry, exp)) {
                int err;
 
+               if (!(exp->ex_flags & NFSEXP_V4ROOT)
+                               && !attributes_need_mount(cd->rd_bmval)) {
+                       ignore_crossmnt = 1;
+                       goto out_encode;
+               }
                /*
                 * Why the heck aren't we just using nfsd_lookup??
                 * Different "."/".." handling?  Something else?
@@ -2219,6 +2225,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
                        goto out_put;
 
        }
+out_encode:
        nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
                                        cd->rd_rqstp, ignore_crossmnt);
 out_put: