[PATCH] knfsd: nfsd4: actually use all the pieces to implement referrals
authorJ.Bruce Fields <bfields@fieldses.org>
Wed, 4 Oct 2006 09:16:20 +0000 (02:16 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 4 Oct 2006 14:55:23 +0000 (07:55 -0700)
Use all the pieces set up so far to implement referral support, allowing
return of NFS4ERR_MOVED and fs_locations attribute.

Signed-off-by: Manoj Naik <manoj@almaden.ibm.com>
Signed-off-by: Fred Isaman <iisaman@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4xdr.c
include/linux/nfsd/nfsd.h

index 38b0f91..8333db1 100644 (file)
@@ -802,13 +802,29 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
                * require a valid current filehandle
                */
-               if ((!current_fh->fh_dentry) &&
-                  !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
-                  (op->opnum == OP_SETCLIENTID) ||
-                  (op->opnum == OP_SETCLIENTID_CONFIRM) ||
-                  (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
-                  (op->opnum == OP_RELEASE_LOCKOWNER))) {
-                       op->status = nfserr_nofilehandle;
+               if (!current_fh->fh_dentry) {
+                       if (!((op->opnum == OP_PUTFH) ||
+                             (op->opnum == OP_PUTROOTFH) ||
+                             (op->opnum == OP_SETCLIENTID) ||
+                             (op->opnum == OP_SETCLIENTID_CONFIRM) ||
+                             (op->opnum == OP_RENEW) ||
+                             (op->opnum == OP_RESTOREFH) ||
+                             (op->opnum == OP_RELEASE_LOCKOWNER))) {
+                               op->status = nfserr_nofilehandle;
+                               goto encode_op;
+                       }
+               }
+               /* Check must be done at start of each operation, except
+                * for GETATTR and ops not listed as returning NFS4ERR_MOVED
+                */
+               else if (current_fh->fh_export->ex_fslocs.migrated &&
+                        !((op->opnum == OP_GETATTR) ||
+                          (op->opnum == OP_PUTROOTFH) ||
+                          (op->opnum == OP_PUTPUBFH) ||
+                          (op->opnum == OP_RENEW) ||
+                          (op->opnum == OP_SETCLIENTID) ||
+                          (op->opnum == OP_RELEASE_LOCKOWNER))) {
+                       op->status = nfserr_moved;
                        goto encode_op;
                }
                switch (op->opnum) {
index 0589852..41fc241 100644 (file)
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
+/*
+ * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
+ * directory in order to indicate to the client that a filesystem boundary is present
+ * We use a fixed fsid for a referral
+ */
+#define NFS4_REFERRAL_FSID_MAJOR       0x8000000ULL
+#define NFS4_REFERRAL_FSID_MINOR       0x8000000ULL
+
 static int
 check_filename(char *str, int len, int err)
 {
@@ -1385,6 +1393,25 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
        return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
 }
 
+#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
+                             FATTR4_WORD0_RDATTR_ERROR)
+#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+
+static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+{
+       /* As per referral draft:  */
+       if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
+           *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
+               if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
+                   *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
+                       *rdattr_err = NFSERR_MOVED;
+               else
+                       return nfserr_moved;
+       }
+       *bmval0 &= WORD0_ABSENT_FS_ATTRS;
+       *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+       return 0;
+}
 
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
@@ -1407,6 +1434,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        u32 *attrlenp;
        u32 dummy;
        u64 dummy64;
+       u32 rdattr_err = 0;
        u32 *p = buffer;
        int status;
        int aclsupport = 0;
@@ -1416,6 +1444,12 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
        BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
 
+       if (exp->ex_fslocs.migrated) {
+               status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+               if (status)
+                       goto out;
+       }
+
        status = vfs_getattr(exp->ex_mnt, dentry, &stat);
        if (status)
                goto out_nfserr;
@@ -1461,12 +1495,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        attrlenp = p++;                /* to be backfilled later */
 
        if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
+               u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
                if ((buflen -= 12) < 0)
                        goto out_resource;
+               if (!aclsupport)
+                       word0 &= ~FATTR4_WORD0_ACL;
+               if (!exp->ex_fslocs.locations)
+                       word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
                WRITE32(2);
-               WRITE32(aclsupport ?
-                       NFSD_SUPPORTED_ATTRS_WORD0 :
-                       NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL);
+               WRITE32(word0);
                WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
        }
        if (bmval0 & FATTR4_WORD0_TYPE) {
@@ -1520,7 +1557,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        if (bmval0 & FATTR4_WORD0_FSID) {
                if ((buflen -= 16) < 0)
                        goto out_resource;
-               if (is_fsid(fhp, rqstp->rq_reffh)) {
+               if (exp->ex_fslocs.migrated) {
+                       WRITE64(NFS4_REFERRAL_FSID_MAJOR);
+                       WRITE64(NFS4_REFERRAL_FSID_MINOR);
+               } else if (is_fsid(fhp, rqstp->rq_reffh)) {
                        WRITE64((u64)exp->ex_fsid);
                        WRITE64((u64)0);
                } else {
@@ -1543,7 +1583,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
-               WRITE32(0);
+               WRITE32(rdattr_err);
        }
        if (bmval0 & FATTR4_WORD0_ACL) {
                struct nfs4_ace *ace;
@@ -1970,7 +2010,6 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ge
        nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
                                    resp->p, &buflen, getattr->ga_bmval,
                                    resp->rqstp);
-
        if (!nfserr)
                resp->p += buflen;
        return nfserr;
index 8094142..d0d4aae 100644 (file)
@@ -216,6 +216,7 @@ void                nfsd_lockd_shutdown(void);
 #define        nfserr_clid_inuse       __constant_htonl(NFSERR_CLID_INUSE)
 #define        nfserr_stale_clientid   __constant_htonl(NFSERR_STALE_CLIENTID)
 #define        nfserr_resource         __constant_htonl(NFSERR_RESOURCE)
+#define        nfserr_moved            __constant_htonl(NFSERR_MOVED)
 #define        nfserr_nofilehandle     __constant_htonl(NFSERR_NOFILEHANDLE)
 #define        nfserr_minor_vers_mismatch      __constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
 #define nfserr_share_denied    __constant_htonl(NFSERR_SHARE_DENIED)