[prev in list] [next in list] [prev in thread] [next in thread]
List: linux-nfsv4
Subject: [PATCH 17/17] nfsd4: actually use all the pieces to implement
From: "J. Bruce Fields" <bfields () fieldses ! org>
Date: 2006-06-27 4:20:08
Message-ID: 20060627042008.6202.49778.stgit () puzzle ! fieldses ! org
[Download RAW message or body]
From: Manoj Naik <manoj@almaden.ibm.com>
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>
---
fs/nfsd/nfs4proc.c | 37 ++++++++++++++++++++++++------
fs/nfsd/nfs4xdr.c | 55 ++++++++++++++++++++++++++++++++++++++++-----
include/linux/nfsd/nfsd.h | 1 +
3 files changed, 79 insertions(+), 14 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 2392b42..14ce38f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -743,7 +743,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
struct svc_fh *save_fh = NULL;
struct nfs4_stateowner *replay_owner = NULL;
int slack_space; /* in words, not bytes! */
- int status;
+ int status, moved;
status = nfserr_resource;
current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
@@ -804,13 +804,34 @@ nfsd4_proc_compound(struct svc_rqst *rqs
* 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 ((moved = nfsd4_is_referral(rqstp,
+ current_fh->fh_export)) &&
+ !((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))) {
+ if (moved < 0)
+ /* XXX need better error handling */
+ op->status = nfserr_resource;
+ else
+ op->status = nfserr_moved;
goto encode_op;
}
switch (op->opnum) {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 9bf6a61..cf4863e 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -60,6 +60,14 @@ #include <linux/nfs4_acl.h>
#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
+ * FIX: Using a fixed fsid for referral, maybe use a variant of the current fsid?
+ */
+#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
+#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
+
static int
check_filename(char *str, int len, int err)
{
@@ -1358,6 +1366,25 @@ nfsd4_encode_aclname(struct svc_rqst *rq
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
@@ -1380,9 +1407,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
u32 *attrlenp;
u32 dummy;
u64 dummy64;
+ u32 rdattr_err = 0;
u32 *p = buffer;
int status;
int aclsupport = 0;
+ int moved;
struct nfs4_acl *acl = NULL;
struct nfsd4_fs_locations *fs_locations = NULL;
@@ -1390,6 +1419,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
+ moved = nfsd4_is_referral(rqstp, exp);
+ if (moved < 0)
+ return nfserr_serverfault;
+ if (moved) {
+ 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;
@@ -1445,12 +1483,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
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)
+ 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) {
@@ -1504,7 +1545,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
if (bmval0 & FATTR4_WORD0_FSID) {
if ((buflen -= 16) < 0)
goto out_resource;
- if (is_fsid(fhp, rqstp->rq_reffh)) {
+ if (moved) {
+ 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 {
@@ -1527,7 +1571,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
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;
@@ -1955,7 +1999,6 @@ nfsd4_encode_getattr(struct nfsd4_compou
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;
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index cc8162c..87e91a9 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -260,6 +260,7 @@ #define nfserr_same __constant_htonl(NF
#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)
_______________________________________________
NFSv4 mailing list
NFSv4@linux-nfs.org
http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic