
Create XDR and surrounding functions in the client for the LAYOUTGET command.

---

 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/nfs4proc.c        |   13 +
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/nfs4xdr.c         |  101 ++++++++++++
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.c            |   52 ++++++
 linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs4.h     |    1 
 linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs_xdr.h  |    2 
 linux-2.6.14-pnfs-current-dhildebz/include/linux/pnfs_xdr.h |   49 +++++
 6 files changed, 218 insertions(+)

diff -puN fs/nfs/nfs4proc.c~client-layoutget fs/nfs/nfs4proc.c
--- linux-2.6.14-pnfs-current/fs/nfs/nfs4proc.c~client-layoutget	2006-01-13 17:27:59.861743000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/nfs4proc.c	2006-01-13 17:27:59.911743000 -0500
@@ -48,6 +48,7 @@
 #include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/pnfs_xdr.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -1477,6 +1478,17 @@ static int _nfs4_proc_read(struct nfs_re
 	return status;
 }
 
+static int nfs4_proc_pnfs_layoutget(struct nfs4_pnfs_layoutget* layout)
+{
+	struct inode* ino = layout->args->inode;
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PNFS_LAYOUTGET],
+		.rpc_argp = layout->args,
+		.rpc_resp = layout->res,
+	};
+	return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(ino), &msg, 0));
+}
+
 static int nfs4_proc_read(struct nfs_read_data *rdata)
 {
 	struct nfs4_exception exception = { };
@@ -3261,6 +3273,7 @@ struct nfs_rpc_ops	nfs_v4_clientops = {
 	.file_release   = nfs_release,
 	.lock		= nfs4_proc_lock,
 	.clear_acl_cache = nfs4_zap_acl_attr,
+	.pnfs_layoutget      = nfs4_proc_pnfs_layoutget,
 };
 
 /*
diff -puN fs/nfs/nfs4xdr.c~client-layoutget fs/nfs/nfs4xdr.c
--- linux-2.6.14-pnfs-current/fs/nfs/nfs4xdr.c~client-layoutget	2006-01-13 17:27:59.876743000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/nfs4xdr.c	2006-01-13 17:29:45.616938000 -0500
@@ -51,6 +51,7 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_idmap.h>
+#include <linux/pnfs_xdr.h>
 #include "nfs4_fs.h"
 #include "pnfs.h"
 
@@ -410,6 +411,14 @@ static int nfs_stat_to_errno(int);
 #define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+#define encode_pnfs_layoutget_sz (11 + op_encode_hdr_maxsz)
+#define decode_pnfs_layoutget_maxsz (6 + PNFS_LAYOUT_MAXSIZE + \
+			        op_decode_hdr_maxsz)
+#define NFS4_enc_pnfs_layoutget_sz (compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_pnfs_layoutget_sz)
+#define NFS4_dec_pnfs_layoutget_sz (compound_decode_hdr_maxsz + \
+ 				decode_pnfs_layoutget_maxsz)
 
 static struct {
 	unsigned int	mode;
@@ -4229,6 +4238,97 @@ static int nfs4_xdr_dec_delegreturn(stru
 	return status;
 }
 
+static int encode_pnfs_layoutget(struct xdr_stream *xdr, const struct nfs4_pnfs_layoutget_arg *args)
+{
+	uint32_t *p;
+
+	RESERVE_SPACE(44);
+	WRITE32(OP_LAYOUTGET);
+	WRITE64(args->clientid);
+	WRITE32(args->type);
+	WRITE32(args->iomode);
+	WRITE64(args->offset);
+	WRITE64(args->length);
+	WRITE64(args->minlength);
+	WRITE32(args->maxcount);
+
+	dprintk("%s: 1st type:%d iomode:%d off:%lu len:%lu mc:%d\n",
+	       __FUNCTION__,
+	       args->type,
+	       args->iomode,
+	       (unsigned long)args->offset,
+	       (unsigned long)args->length,
+	       args->maxcount);
+        return 0;
+}
+
+static int decode_pnfs_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_pnfs_layoutget_res *res)
+{
+	uint32_t *p;
+	int status;
+
+	status = decode_op_hdr(xdr, OP_LAYOUTGET);
+	if (status)
+		return status;
+	READ_BUF(28);
+	READ64(res->offset);
+	READ64(res->length);
+	READ32(res->iomode);
+	READ32(res->type);
+	READ_BUF(res->layout.len);
+	if (res->layout.len > PNFS_LAYOUT_MAXSIZE)
+		return -EINVAL;
+	COPYMEM(res->layout.buf, res->layout.len);
+
+	dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:%d, lo.len:%d\n",
+		 __FUNCTION__,
+		 (unsigned long)res->offset,
+		 (unsigned long)res->length,
+		 res->iomode,
+		 res->type,
+		 res->layout.len);
+	return 0;
+}
+
+/*
+ *  Encode LAYOUTGET request
+ */
+static int nfs4_xdr_enc_pnfs_layoutget(struct rpc_rqst *req, uint32_t *p, struct nfs4_pnfs_layoutget_arg *args)
+{
+	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);
+	if ((status = encode_putfh(&xdr, NFS_FH(args->inode))) == 0)
+		status = encode_pnfs_layoutget(&xdr, args);
+	return status;
+}
+
+/*
+ * Decode LAYOUTGET response
+ */
+static int nfs4_xdr_dec_pnfs_layoutget(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_pnfs_layoutget_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (status)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	status = decode_pnfs_layoutget(&xdr,rqstp,res);
+out:
+	return status;
+
+}
+
 uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
 {
 	uint32_t bitmap[2] = {0};
@@ -4398,6 +4498,7 @@ struct rpc_procinfo	nfs4_procedures[] = 
   PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
   PROC(GETACL,		enc_getacl,	dec_getacl),
   PROC(SETACL,		enc_setacl,	dec_setacl),
+  PROC(PNFS_LAYOUTGET,	enc_pnfs_layoutget,	dec_pnfs_layoutget),
 };
 
 struct rpc_version		nfs_version4 = {
diff -puN fs/nfs/pnfs.c~client-layoutget fs/nfs/pnfs.c
--- linux-2.6.14-pnfs-current/fs/nfs/pnfs.c~client-layoutget	2006-01-13 17:27:59.882743000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.c	2006-01-13 17:27:59.933743000 -0500
@@ -189,5 +189,57 @@ pnfs_unregister_layoutdriver(struct pnfs
 	}
 }
 
+/*
+* Get layout from server.
+*    for now, assume that whole file layouts are requested.
+*    arg->offset: 0
+*    arg->length: all ones
+*
+*    for now, assume the LAYOUTGET operation is triggered by an I/O request.
+*    the count field is the count in the I/O request, and will be used
+*    as the minlength. for the file operation that piggy-backs
+*    the LAYOUTGET operation with an OPEN, s
+*    arg->minlength = count.
+*/
+static int
+get_layout(struct inode* ino, struct nfs_open_context* ctx, size_t count, loff_t pos, int access_type, struct nfs4_pnfs_layoutget_arg* arg, struct nfs4_pnfs_layoutget_res* res)
+{
+	int status;
+	struct nfs_server *server = NFS_SERVER(ino);
+	struct nfs4_pnfs_layoutget gdata = {
+		.args = arg,
+		.res = res,
+	};
+/*
+	struct timeval begin = { 0, 0 }, end = { 0, 0 };
+	do_gettimeofday(&begin);
+*/
+	dprintk("%s:Begin\n",__FUNCTION__);
+
+	arg->clientid = ctx->state->owner->so_client->cl_clientid;
+	arg->type = server->pnfs_curr_ld->id;
+	/* FMODE_WRITE =2= LAYOUTMODE_RW,  FMODE_READ =1= LAYOUTMODE_READ */
+	arg->iomode = access_type;
+	arg->offset = 0;
+	arg->length = 0xFFFFFFFF;
+	arg->minlength = count;
+	arg->maxcount = PNFS_LAYOUT_MAXSIZE;
+	arg->inode = ino;
+	arg->ctx = ctx;
+
+	/* Retrieve layout information from server */
+	status = NFS_PROTO(ino)->pnfs_layoutget(&gdata);
+/*
+	do_gettimeofday(&end);
+	if (end.tv_usec < begin.tv_usec) {
+		end.tv_usec = 1000000; end.tv_sec--;
+	}
+	end.tv_sec  -= begin.tv_sec;
+	end.tv_usec -= begin.tv_usec;
+	printk("Sec:%ld usec: %ld\n",end.tv_sec,end.tv_usec);
+*/
+	return status;
+}
+
 EXPORT_SYMBOL(pnfs_unregister_layoutdriver);
 EXPORT_SYMBOL(pnfs_register_layoutdriver);
diff -puN include/linux/nfs4.h~client-layoutget include/linux/nfs4.h
--- linux-2.6.14-pnfs-current/include/linux/nfs4.h~client-layoutget	2006-01-13 17:27:59.886743000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs4.h	2006-01-13 17:27:59.939738000 -0500
@@ -390,6 +390,7 @@ enum {
 	NFSPROC4_CLNT_DELEGRETURN,
 	NFSPROC4_CLNT_GETACL,
 	NFSPROC4_CLNT_SETACL,
+	NFSPROC4_CLNT_PNFS_LAYOUTGET,
 };
 
 #endif
diff -puN include/linux/nfs_xdr.h~client-layoutget include/linux/nfs_xdr.h
--- linux-2.6.14-pnfs-current/include/linux/nfs_xdr.h~client-layoutget	2006-01-13 17:27:59.893743000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs_xdr.h	2006-01-13 17:27:59.945732000 -0500
@@ -2,6 +2,7 @@
 #define _LINUX_NFS_XDR_H
 
 #include <linux/sunrpc/xprt.h>
+#include <linux/pnfs_xdr.h>
 #include <linux/nfsacl.h>
 
 struct nfs4_fsid {
@@ -771,6 +772,7 @@ struct nfs_rpc_ops {
 	int	(*file_release) (struct inode *, struct file *);
 	int	(*lock)(struct file *, int, struct file_lock *);
 	void	(*clear_acl_cache)(struct inode *);
+	int	(*pnfs_layoutget)(struct nfs4_pnfs_layoutget* layout);
 };
 
 /*
diff -puN /dev/null include/linux/pnfs_xdr.h
--- /dev/null	2006-01-09 05:56:56.224752500 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/include/linux/pnfs_xdr.h	2006-01-13 17:27:59.952725000 -0500
@@ -0,0 +1,49 @@
+/*
+ *  include/linux/pnfs_xdr.h
+ *
+ *  Common xdr data structures needed by pnfs client and server.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ * Dean Hildebrand   <dhildebz@eecs.umich.edu>
+ */
+
+#ifndef LINUX_PNFS_XDR_H
+#define LINUX_PNFS_XDR_H
+
+#include <linux/nfs4.h>
+
+#define PNFS_LAYOUT_MAXSIZE 1024
+#define PNFS_MAX_NUM_LAYOUT_TYPES 2
+
+struct nfs4_pnfs_layout {
+	__u32 len;
+	char *buf;
+};
+
+struct nfs4_pnfs_layoutget_arg {
+	__u64 clientid;
+	__u32 type;
+	__u32 iomode;
+	__u64 offset;
+	__u64 length;
+	__u64 minlength;
+	__u32 maxcount;
+	struct nfs_open_context* ctx;
+	struct inode* inode;
+};
+
+struct nfs4_pnfs_layoutget_res {
+	__u64 offset;
+	__u64 length;
+	__u32 iomode;
+	__u32 type;
+	struct nfs4_pnfs_layout layout;
+};
+
+struct nfs4_pnfs_layoutget {
+	struct nfs4_pnfs_layoutget_arg* args;
+	struct nfs4_pnfs_layoutget_res* res;
+};
+#endif /* LINUX_PNFS_XDR_H */
_
