
Create XDR and surrounding functions on the client for the CB_LAYOUTRECALL
command.

---

 linux-2.6.14-andros/fs/nfs/callback.h      |    9 +++++
 linux-2.6.14-andros/fs/nfs/callback_proc.c |   46 +++++++++++++++++++++++++++++
 linux-2.6.14-andros/fs/nfs/callback_xdr.c  |   29 +++++++++++++++++-
 3 files changed, 83 insertions(+), 1 deletion(-)

diff -puN fs/nfs/callback.h~client-layoutrecall fs/nfs/callback.h
--- linux-2.6.14/fs/nfs/callback.h~client-layoutrecall	2005-12-23 12:02:22.000000000 -0500
+++ linux-2.6.14-andros/fs/nfs/callback.h	2005-12-23 12:28:26.000000000 -0500
@@ -20,6 +20,7 @@ enum nfs4_callback_procnum {
 enum nfs4_callback_opnum {
 	OP_CB_GETATTR = 3,
 	OP_CB_RECALL  = 4,
+	OP_CB_LAYOUTRECALL  = 5,
 	OP_CB_ILLEGAL = 10044,
 };
 
@@ -59,8 +60,16 @@ struct cb_recallargs {
 	uint32_t truncate;
 };
 
+struct cb_pnfs_layoutrecallargs {
+	struct sockaddr_in *addr;
+	struct nfs_fh fh;
+	uint64_t offset;
+	uint64_t length;
+};
+
 extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
 extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
+extern unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args, void *dummy);
 
 extern int nfs_callback_up(void);
 extern int nfs_callback_down(void);
diff -puN fs/nfs/callback_proc.c~client-layoutrecall fs/nfs/callback_proc.c
--- linux-2.6.14/fs/nfs/callback_proc.c~client-layoutrecall	2005-12-23 12:02:22.000000000 -0500
+++ linux-2.6.14-andros/fs/nfs/callback_proc.c	2005-12-23 12:54:51.000000000 -0500
@@ -84,3 +84,49 @@ out:
 	dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
 	return res;
 }
+
+/*
+ * Layout is not actually returned until the client executes the
+ * LAYOUTRETURN operation.
+ * The general semantics are that once a layout has been recalled,
+ * all in flight I/O ops are completed and then LAYOUTRETURN is called.
+ *
+ * XXX The layout driver needs to choose to write all buffered I/O using:
+ * 	1) the layoutdriver if still available or
+ * 	2) the NFSv4 READ/WRITE ops after the layout is returned
+ */
+unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args, void *dummy)
+{
+	struct nfs4_client *clp;
+	struct inode *inode;
+	unsigned res;
+
+	res = htonl(NFS4ERR_BADHANDLE);
+	clp = nfs4_find_client(&args->addr->sin_addr);
+	if (clp == NULL)
+		goto out;
+
+	/* XXX Need to customize this lookup for a layout delegation */
+	inode = nfs_delegation_find_inode(clp, &args->fh);
+	if (inode == NULL)
+		goto out_putclient;
+	/* XXX Need to actually implement recall of layout */
+	/* Set up a helper thread to actually return the delegation
+	switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
+		case 0:
+			res = 0;
+			break;
+		case -ENOENT:
+			res = htonl(NFS4ERR_BAD_STATEID);
+			break;
+		default:
+			res = htonl(NFS4ERR_RESOURCE);
+	}
+	*/
+	iput(inode);
+out_putclient:
+	nfs4_put_client(clp);
+out:
+	dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
+	return res;
+}
diff -puN fs/nfs/callback_xdr.c~client-layoutrecall fs/nfs/callback_xdr.c
--- linux-2.6.14/fs/nfs/callback_xdr.c~client-layoutrecall	2005-12-23 12:02:22.000000000 -0500
+++ linux-2.6.14-andros/fs/nfs/callback_xdr.c	2005-12-23 12:56:40.000000000 -0500
@@ -20,6 +20,7 @@
 				CB_OP_GETATTR_BITMAP_MAXSZ + \
 				2 + 2 + 3 + 3)
 #define CB_OP_RECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
+#define CB_OP_LAYOUTRECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
 
@@ -205,6 +206,27 @@ out:
 	return 0;
 }
 
+static unsigned decode_pnfs_layoutrecall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_pnfs_layoutrecallargs *args)
+{
+	uint32_t *p;
+	unsigned status;
+
+	args->addr = &rqstp->rq_addr;
+	status = decode_fh(xdr, &args->fh);
+	if (unlikely(status != 0))
+		goto out;
+	p = read_buf(xdr, 16);
+	if (unlikely(p == NULL)) {
+		status = htonl(NFS4ERR_RESOURCE);
+		goto out;
+	}
+	p = xdr_decode_hyper(p, &args->offset);
+	p = xdr_decode_hyper(p, &args->length);
+out:
+	dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+	return 0;
+}
+
 static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
 	uint32_t *p;
@@ -369,7 +391,7 @@ static unsigned process_op(struct svc_rq
 	if (unlikely(status != 0)) {
 		op_nr = OP_CB_ILLEGAL;
 		op = &callback_ops[0];
-	} else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL)) {
+	} else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL && op_nr != OP_CB_LAYOUTRECALL)) {
 		op_nr = OP_CB_ILLEGAL;
 		op = &callback_ops[0];
 		status = htonl(NFS4ERR_OP_ILLEGAL);
@@ -449,6 +471,11 @@ static struct callback_op callback_ops[]
 		.process_op = (callback_process_op_t)nfs4_callback_recall,
 		.decode_args = (callback_decode_arg_t)decode_recall_args,
 		.res_maxsize = CB_OP_RECALL_RES_MAXSZ,
+	},
+	[OP_CB_LAYOUTRECALL] = {
+		.process_op = (callback_process_op_t)nfs4_callback_pnfs_layoutrecall,
+		.decode_args = (callback_decode_arg_t)decode_pnfs_layoutrecall_args,
+		.res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
 	}
 };
 
_
