From: Trond Myklebust <trond.myklebust@fys.uio.no>

NFSv4: Split out the code for retrieving static server information out of the
GETATTR compound.


---

 fs/nfs/nfs4proc.c       |   73 ++++-----------------
 fs/nfs/nfs4xdr.c        |  160 ++++++++++++++++++++++++++++++++++++++----------
 include/linux/nfs4.h    |    1 
 include/linux/nfs_xdr.h |    1 
 4 files changed, 144 insertions(+), 91 deletions(-)

diff -puN fs/nfs/nfs4proc.c~nfs-20-fsinfo_xdr fs/nfs/nfs4proc.c
--- 25/fs/nfs/nfs4proc.c~nfs-20-fsinfo_xdr	2004-01-09 22:16:20.000000000 -0800
+++ 25-akpm/fs/nfs/nfs4proc.c	2004-01-09 22:16:20.000000000 -0800
@@ -56,6 +56,9 @@ extern struct rpc_procinfo nfs4_procedur
 
 extern nfs4_stateid zero_stateid;
 
+static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
+
+
 static void
 nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
 		    struct nfs_server *server, char *tag)
@@ -177,44 +180,16 @@ u32 nfs4_statfs_bitmap[2] = {
 	| FATTR4_WORD1_SPACE_TOTAL
 };
 
-u32 nfs4_fsinfo_bitmap[2] = {
-	FATTR4_WORD0_MAXFILESIZE
-	| FATTR4_WORD0_MAXREAD
-        | FATTR4_WORD0_MAXWRITE
-	| FATTR4_WORD0_LEASE_TIME,
-	0
-};
-
 u32 nfs4_pathconf_bitmap[2] = {
 	FATTR4_WORD0_MAXLINK
 	| FATTR4_WORD0_MAXNAME,
 	0
 };
 
-/* mount bitmap: fattr bitmap + lease time */
-u32 nfs4_mount_bitmap[2] = {
-	FATTR4_WORD0_TYPE
-	| FATTR4_WORD0_CHANGE
-	| FATTR4_WORD0_SIZE
-	| FATTR4_WORD0_FSID
-	| FATTR4_WORD0_FILEID
-	| FATTR4_WORD0_LEASE_TIME,
-	FATTR4_WORD1_MODE
-	| FATTR4_WORD1_NUMLINKS
-	| FATTR4_WORD1_OWNER
-	| FATTR4_WORD1_OWNER_GROUP
-	| FATTR4_WORD1_RAWDEV
-	| FATTR4_WORD1_SPACE_USED
-	| FATTR4_WORD1_TIME_ACCESS
-	| FATTR4_WORD1_TIME_METADATA
-	| FATTR4_WORD1_TIME_MODIFY
-};
-
 static inline void
 __nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
 		     struct nfs_fattr *fattr,
 		     struct nfs_fsstat *fsstat,
-		     struct nfs_fsinfo *fsinfo,
 		     struct nfs_pathconf *pathconf)
 {
         struct nfs4_getattr *getattr = GET_OP(cp, getattr);
@@ -222,7 +197,6 @@ __nfs4_setup_getattr(struct nfs4_compoun
         getattr->gt_bmval = bitmap;
         getattr->gt_attrs = fattr;
 	getattr->gt_fsstat = fsstat;
-	getattr->gt_fsinfo = fsinfo;
 	getattr->gt_pathconf = pathconf;
 
         OPNUM(cp) = OP_GETATTR;
@@ -234,16 +208,7 @@ nfs4_setup_getattr(struct nfs4_compound 
 		struct nfs_fattr *fattr)
 {
 	__nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
-			NULL, NULL, NULL);
-}
-
-static void
-nfs4_setup_getrootattr(struct nfs4_compound *cp,
-		struct nfs_fattr *fattr,
-		struct nfs_fsinfo *fsinfo)
-{
-	__nfs4_setup_getattr(cp, nfs4_mount_bitmap,
-			fattr, NULL, fsinfo, NULL);
+			NULL, NULL);
 }
 
 static void
@@ -251,15 +216,7 @@ nfs4_setup_statfs(struct nfs4_compound *
 		struct nfs_fsstat *fsstat)
 {
 	__nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
-			NULL, fsstat, NULL, NULL);
-}
-
-static void
-nfs4_setup_fsinfo(struct nfs4_compound *cp,
-		struct nfs_fsinfo *fsinfo)
-{
-	__nfs4_setup_getattr(cp, nfs4_fsinfo_bitmap,
-			NULL, NULL, fsinfo, NULL);
+			NULL, fsstat, NULL);
 }
 
 static void
@@ -267,7 +224,7 @@ nfs4_setup_pathconf(struct nfs4_compound
 		struct nfs_pathconf *pathconf)
 {
 	__nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
-			NULL, NULL, NULL, pathconf);
+			NULL, NULL, pathconf);
 }
 
 static void
@@ -759,7 +716,7 @@ nfs4_proc_get_root(struct nfs_server *se
 		fattr->valid = 0;
 		nfs4_setup_compound(&compound, ops, server, "getrootfh");
 		nfs4_setup_putrootfh(&compound);
-		nfs4_setup_getrootattr(&compound, fattr, &fsinfo);
+		nfs4_setup_getattr(&compound, fattr);
 		nfs4_setup_getfh(&compound, fhandle);
 		if ((status = nfs4_call_compound(&compound, NULL, 0)))
 			goto out_unlock;
@@ -785,7 +742,7 @@ nfs4_proc_get_root(struct nfs_server *se
 	nfs4_setup_compound(&compound, ops, server, "setclientid_confirm");
 	nfs4_setup_setclientid_confirm(&compound);
 	nfs4_setup_putrootfh(&compound);
-	nfs4_setup_getrootattr(&compound, fattr, &fsinfo);
+	nfs4_setup_getattr(&compound, fattr);
 	nfs4_setup_getfh(&compound, fhandle);
 	last_renewed = jiffies;
 	if ((status = nfs4_call_compound(&compound, NULL, 0)))
@@ -797,6 +754,8 @@ nfs4_proc_get_root(struct nfs_server *se
 	 * server.
 	 * FIXME: we only need one renewd daemon per server.
 	 */
+	if ((status = nfs4_proc_fsinfo(server, fhandle, &fsinfo)))
+		goto out_unlock;
 	clp->cl_lease_time = fsinfo.lease_time * HZ;
 	clp->cl_last_renewal = last_renewed;
 	nfs4_schedule_state_renewal(clp);
@@ -1434,14 +1393,14 @@ static int
 nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
 		 struct nfs_fsinfo *fsinfo)
 {
-	struct nfs4_compound compound;
-	struct nfs4_op ops[2];
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
+		.rpc_argp = fhandle,
+		.rpc_resp = fsinfo,
+	};
 
 	memset(fsinfo, 0, sizeof(*fsinfo));
-	nfs4_setup_compound(&compound, ops, server, "statfs");
-	nfs4_setup_putfh(&compound, fhandle);
-	nfs4_setup_fsinfo(&compound, fsinfo);
-	return nfs4_call_compound(&compound, NULL, 0);
+	return rpc_call_sync(server->client, &msg, 0);
 }
 
 static int
diff -puN fs/nfs/nfs4xdr.c~nfs-20-fsinfo_xdr fs/nfs/nfs4xdr.c
--- 25/fs/nfs/nfs4xdr.c~nfs-20-fsinfo_xdr	2004-01-09 22:16:20.000000000 -0800
+++ 25-akpm/fs/nfs/nfs4xdr.c	2004-01-09 22:16:20.000000000 -0800
@@ -90,6 +90,8 @@ extern int			nfs_stat_to_errno(int);
 #define decode_pre_write_getattr_maxsz	op_decode_hdr_maxsz + 5
 #define encode_post_write_getattr_maxsz	op_encode_hdr_maxsz + 2
 #define decode_post_write_getattr_maxsz	op_decode_hdr_maxsz + 13
+#define encode_fsinfo_maxsz	op_encode_hdr_maxsz + 2
+#define decode_fsinfo_maxsz	op_decode_hdr_maxsz + 11
 #define encode_renew_maxsz	op_encode_hdr_maxsz + 3
 #define decode_renew_maxsz	op_decode_hdr_maxsz
 
@@ -161,6 +163,12 @@ extern int			nfs_stat_to_errno(int);
 #define NFS4_dec_setattr_sz     compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
                                 op_decode_hdr_maxsz + 3
+#define NFS4_enc_fsinfo_sz	compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_fsinfo_maxsz
+#define NFS4_dec_fsinfo_sz	compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				decode_fsinfo_maxsz
 #define NFS4_enc_renew_sz	compound_encode_hdr_maxsz + \
 				encode_renew_maxsz
 #define NFS4_dec_renew_sz	compound_decode_hdr_maxsz + \
@@ -507,6 +515,15 @@ encode_post_write_getattr(struct xdr_str
 }
 
 static int
+encode_fsinfo(struct xdr_stream *xdr)
+{
+	return encode_getattr_one(xdr, FATTR4_WORD0_MAXFILESIZE
+			| FATTR4_WORD0_MAXREAD
+			| FATTR4_WORD0_MAXWRITE
+			| FATTR4_WORD0_LEASE_TIME);
+}
+
+static int
 encode_getfh(struct xdr_stream *xdr)
 {
 	uint32_t *p;
@@ -1135,6 +1152,26 @@ out:
 }
 
 /*
+ * FSINFO request
+ */
+static int
+nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops	= 2,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	status = encode_putfh(&xdr, fhandle);
+	if (!status)
+		status = encode_fsinfo(&xdr);
+	return status;
+}
+
+/*
  * a RENEW request
  */
 static int
@@ -1312,7 +1349,6 @@ decode_create(struct xdr_stream *xdr, st
 }
 
 extern uint32_t nfs4_fattr_bitmap[2];
-extern uint32_t nfs4_fsinfo_bitmap[2];
 extern uint32_t nfs4_fsstat_bitmap[2];
 extern uint32_t nfs4_pathconf_bitmap[2];
 
@@ -1322,7 +1358,6 @@ decode_getattr(struct xdr_stream *xdr, s
 {
 	struct nfs_fattr *nfp = getattr->gt_attrs;
 	struct nfs_fsstat *fsstat = getattr->gt_fsstat;
-	struct nfs_fsinfo *fsinfo = getattr->gt_fsinfo;
 	struct nfs_pathconf *pathconf = getattr->gt_pathconf;
 	uint32_t attrlen, dummy32, bmlen,
 		 bmval0 = 0,
@@ -1368,11 +1403,6 @@ decode_getattr(struct xdr_stream *xdr, s
 		nfp->nlink = 1;
 		nfp->timestamp = jiffies;
 	}
-	if (fsinfo) {
-		fsinfo->rtmult = fsinfo->wtmult = 512;  /* ??? */
-		fsinfo->lease_time = 60;
-	}
-
         if (bmval0 & FATTR4_WORD0_TYPE) {
                 READ_BUF(4);
                 len += 4;
@@ -1406,12 +1436,6 @@ decode_getattr(struct xdr_stream *xdr, s
 			(long long)nfp->fsid_u.nfs4.major,
 			(long long)nfp->fsid_u.nfs4.minor);
         }
-        if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
-                READ_BUF(4);
-                len += 4;
-                READ32(fsinfo->lease_time);
-                dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
-        }
         if (bmval0 & FATTR4_WORD0_FILEID) {
                 READ_BUF(8);
                 len += 8;
@@ -1436,12 +1460,6 @@ decode_getattr(struct xdr_stream *xdr, s
                 READ64(fsstat->tfiles);
                 dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
         }
-        if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsinfo->maxfilesize);
-                dprintk("read_attrs: maxfilesize=0x%Lx\n", (long long) fsinfo->maxfilesize);
-        }
 	if (bmval0 & FATTR4_WORD0_MAXLINK) {
 		READ_BUF(4);
 		len += 4;
@@ -1454,20 +1472,6 @@ decode_getattr(struct xdr_stream *xdr, s
                 READ32(pathconf->max_namelen);
                 dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
         }
-        if (bmval0 & FATTR4_WORD0_MAXREAD) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsinfo->rtmax);
-		fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
-                dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax);
-        }
-        if (bmval0 & FATTR4_WORD0_MAXWRITE) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsinfo->wtmax);
-		fsinfo->wtpref = fsinfo->wtmax;
-                dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax);
-        }
 	
         if (bmval1 & FATTR4_WORD1_MODE) {
                 READ_BUF(4);
@@ -1710,6 +1714,74 @@ out_bad_bitmap:
 
 
 static int
+decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
+{
+	uint32_t *p;
+	uint32_t len, attrlen, bmlen, bmval0 = 0, bmval1 = 0;
+	int status;
+
+	status = decode_op_hdr(xdr, OP_GETATTR);
+	if (status)
+		return status;
+	READ_BUF(4);
+	READ32(bmlen);
+	if (bmlen < 1)
+		return -EIO;
+	READ_BUF(bmlen << 2);
+	READ32(bmval0);
+	if (bmval0 & ~(FATTR4_WORD0_MAXFILESIZE|FATTR4_WORD0_MAXREAD|
+				FATTR4_WORD0_MAXWRITE|FATTR4_WORD0_LEASE_TIME))
+		goto out_bad_bitmap;
+	if (bmlen > 1) {
+		READ32(bmval1);
+		if (bmval1 != 0 || bmlen > 2)
+			goto out_bad_bitmap;
+	}
+	READ_BUF(4);
+	READ32(attrlen);
+	READ_BUF(attrlen);
+	fsinfo->rtmult = fsinfo->wtmult = 512;	/* ??? */
+	fsinfo->lease_time = 60;
+	len = attrlen;
+
+	if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
+		len -= 4;
+		READ32(fsinfo->lease_time);
+		dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
+		len -= 8;
+		READ64(fsinfo->maxfilesize);
+		dprintk("read_attrs: maxfilesize=0x%Lx\n", (long long) fsinfo->maxfilesize);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXREAD) {
+		len -= 8;
+		READ64(fsinfo->rtmax);
+		fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
+		dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXWRITE) {
+		len -= 8;
+		READ64(fsinfo->wtmax);
+		fsinfo->wtpref = fsinfo->wtmax;
+		dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax);
+	}
+	if (len != 0)
+		goto out_bad_attrlen;
+	return 0;
+out_bad_attrlen:
+	printk(KERN_NOTICE "%s: server attribute length %u does not match bitmap 0x%x/0x%x\n",
+			__FUNCTION__, (unsigned int)attrlen,
+			(unsigned int) bmval0, (unsigned int)bmval1);
+	return -EIO;
+out_bad_bitmap:
+	printk(KERN_NOTICE "%s: server returned bad attribute bitmap 0x%x/0x%x\n",
+			__FUNCTION__,
+			(unsigned int)bmval0, (unsigned int)bmval1);
+	return -EIO;
+}
+
+static int
 decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
 {
 	struct nfs_fh *fh = getfh->gf_fhandle;
@@ -2404,6 +2476,27 @@ out:
 }
 
 /*
+ * FSINFO request
+ */
+static int
+nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (!status)
+		status = decode_putfh(&xdr);
+	if (!status)
+		status = decode_fsinfo(&xdr, fsinfo);
+	if (!status)
+		status = -nfs_stat_to_errno(hdr.status);
+	return status;
+}
+
+/*
  * Decode RENEW response
  */
 static int
@@ -2476,6 +2569,7 @@ struct rpc_procinfo	nfs4_procedures[] = 
   PROC(OPEN_CONFIRM,	enc_open_confirm,	dec_open_confirm),
   PROC(CLOSE,		enc_close,	dec_close),
   PROC(SETATTR,		enc_setattr,	dec_setattr),
+  PROC(FSINFO,		enc_fsinfo,	dec_fsinfo),
   PROC(RENEW,		enc_renew,	dec_renew),
 };
 
diff -puN include/linux/nfs4.h~nfs-20-fsinfo_xdr include/linux/nfs4.h
--- 25/include/linux/nfs4.h~nfs-20-fsinfo_xdr	2004-01-09 22:16:20.000000000 -0800
+++ 25-akpm/include/linux/nfs4.h	2004-01-09 22:16:20.000000000 -0800
@@ -221,6 +221,7 @@ enum {
 	NFSPROC4_CLNT_OPEN_CONFIRM,
 	NFSPROC4_CLNT_CLOSE,
 	NFSPROC4_CLNT_SETATTR,
+	NFSPROC4_CLNT_FSINFO,
 	NFSPROC4_CLNT_RENEW,
 };
 
diff -puN include/linux/nfs_xdr.h~nfs-20-fsinfo_xdr include/linux/nfs_xdr.h
--- 25/include/linux/nfs_xdr.h~nfs-20-fsinfo_xdr	2004-01-09 22:16:20.000000000 -0800
+++ 25-akpm/include/linux/nfs_xdr.h	2004-01-09 22:16:20.000000000 -0800
@@ -449,7 +449,6 @@ struct nfs4_getattr {
         u32 *				gt_bmval;          /* request */
         struct nfs_fattr *		gt_attrs;          /* response */
 	struct nfs_fsstat *		gt_fsstat;         /* response */
-	struct nfs_fsinfo *		gt_fsinfo;         /* response */
 	struct nfs_pathconf *		gt_pathconf;       /* response */
 };
 

_