[pnfs] [PATCH 3/5] cb_sequence: client implementation of cb_sequence

Benny Halevy bhalevy at panasas.com
Thu May 31 14:08:30 EDT 2007


Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/nfs/callback.h      |   32 +++++++++++
 fs/nfs/callback_proc.c |   17 ++++++
 fs/nfs/callback_xdr.c  |  146 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 193 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 263fc85..60c261b 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -70,8 +70,40 @@ struct cb_recallargs {
 	uint32_t truncate;
 };
 
+struct referring_call {
+	uint32_t			rc_sequenceid;
+	uint32_t			rc_slotid;
+};
+
+struct referring_call_list {
+	nfs41_sessionid			rcl_sessionid;
+	uint32_t			rcl_nrefcalls;
+	struct referring_call 		*rcl_refcalls;
+};
+
+struct cb_sequenceargs {
+	struct sockaddr_in		*cbs_addr;
+	nfs41_sessionid			cbs_sessionid;
+	uint32_t			cbs_sequenceid;
+	uint32_t			cbs_slotid;
+	uint32_t			cbs_highestslotid;
+	uint32_t			cbs_cachethis;
+	uint32_t			cbs_nrclists;
+	struct referring_call_list	*cbs_rclists;
+};
+
+struct cb_sequenceres {
+	uint32_t			cbsr_status;
+	nfs41_sessionid			cbsr_sessionid;
+	uint32_t			cbsr_sequenceid;
+	uint32_t			cbsr_slotid;
+	uint32_t			cbsr_highestslotid;
+	uint32_t			cbsr_target_highestslotid;
+};
+
 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_sequence(struct cb_sequenceargs *args, struct cb_sequenceres *res);
 
 extern int nfs_callback_up(int, void *);
 extern int nfs_callback_down(int, void *);
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 7719483..a22c474 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -85,3 +85,20 @@ out:
 	dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
 	return res;
 }
+
+unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
+                                struct cb_sequenceres *res)
+{
+	int i;
+	unsigned status = 0;
+
+	/* FIXME: these should be processed */
+	for (i = 0; i < args->cbs_nrclists; i++) {
+		kfree(args->cbs_rclists[i].rcl_refcalls);
+	}
+	kfree(args->cbs_rclists);
+
+	dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
+	res->cbsr_status = status;
+	return status;
+}
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 9b2fbde..2489bee 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -19,9 +19,22 @@
 				CB_OP_GETATTR_BITMAP_MAXSZ + \
 				2 + 2 + 3 + 3)
 #define CB_OP_RECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
+#define CB_OP_SEQUENCE_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ + \
+					4 + 1 + 3)
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
 
+#define READMEM(x,nbytes) do {			\
+	x = (char *)p;				\
+	p += XDR_QUADLEN(nbytes);		\
+} while (0)
+
+#define COPYMEM(x,nbytes) do {			\
+	memcpy((x), p, nbytes);			\
+	p += XDR_QUADLEN(nbytes);		\
+} while (0)
+
+
 typedef unsigned (*callback_process_op_t)(void *, void *);
 typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
 typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
@@ -204,6 +217,99 @@ out:
 	return status;
 }
 
+static unsigned decode_rc_list(struct xdr_stream *xdr,
+                               struct referring_call_list *rc_list)
+{
+	uint32_t *p;
+	int i;
+	unsigned status = htonl(NFS4ERR_RESOURCE);
+
+	p = read_buf(xdr, 5 * sizeof(uint32_t));
+	if (unlikely(p == NULL))
+		goto out;
+
+	COPYMEM(&rc_list->rcl_sessionid, 16);
+	rc_list->rcl_nrefcalls = ntohl(*p++);
+	if (rc_list->rcl_nrefcalls) {
+		p = read_buf(xdr, rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
+		if (unlikely(p == NULL))
+			goto out;
+		rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls *
+		                                sizeof(*rc_list->rcl_refcalls),
+		                                GFP_KERNEL);
+		if (unlikely(rc_list->rcl_refcalls == NULL))
+			goto out;
+		for (i = 0; i < rc_list->rcl_nrefcalls; i++) {
+			rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++);
+			rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++);
+		}
+	}
+
+out:
+	return status;
+}
+
+static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp,
+                                        struct xdr_stream *xdr,
+                                        struct cb_sequenceargs *args)
+{
+	uint32_t *p;
+	int i;
+	unsigned status = 0;
+
+	args->cbs_addr = &rqstp->rq_addr;
+	p = read_buf(xdr, 9 * sizeof(uint32_t));
+	if (unlikely(p == NULL)) {
+		status = htonl(NFS4ERR_RESOURCE);
+		goto out;
+	}
+
+	COPYMEM(&args->cbs_sessionid, 16);
+	args->cbs_sequenceid = ntohl(*p++);
+	args->cbs_slotid = ntohl(*p++);
+	args->cbs_highestslotid = ntohl(*p++);
+	args->cbs_cachethis = ntohl(*p++);
+	args->cbs_nrclists = ntohl(*p++);
+	args->cbs_rclists = NULL;
+	if (args->cbs_nrclists) {
+		args->cbs_rclists = kmalloc(args->cbs_nrclists *
+		                            sizeof(*args->cbs_rclists),
+		                            GFP_KERNEL);
+		if (unlikely(args->cbs_rclists == NULL)) {
+			status = htonl(NFS4ERR_RESOURCE);
+			goto out;
+		}
+
+		for (i = 0; i < args->cbs_nrclists; i++) {
+			status = decode_rc_list(xdr, &args->cbs_rclists[i]);
+			if (status)
+				goto out_free;
+		}
+		args->cbs_rclists = (struct referring_call_list *)p;
+		p += 4;    /* digest rcl_sessionid */
+		args->cbs_rclists->rcl_nrefcalls = ntohl(*p++);
+	}
+
+	dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u "
+	        "highestslotid %u cachethis %d nrclists %u\n",
+		__FUNCTION__,
+		((u32*)&args->cbs_sessionid)[0], ((u32*)&args->cbs_sessionid)[1],
+		((u32*)&args->cbs_sessionid)[2], ((u32*)&args->cbs_sessionid)[3],
+		args->cbs_sequenceid, args->cbs_slotid,
+		args->cbs_highestslotid, args->cbs_cachethis,
+		args->cbs_nrclists);
+out:
+	dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+	return status;
+
+out_free:
+	for (i = 0; i < args->cbs_nrclists; i++) {
+		kfree(args->cbs_rclists[i].rcl_refcalls);
+	}
+	kfree(args->cbs_rclists);
+	goto out;
+}
+
 static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
 	uint32_t *p;
@@ -353,6 +459,27 @@ out:
 	return status;
 }
 
+static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp,
+                                       struct xdr_stream *xdr,
+                                       const struct cb_sequenceres *res)
+{
+	uint32_t *p;
+	unsigned status = res->cbsr_status;
+
+	if (unlikely(status != 0))
+		goto out;
+
+	p = xdr_reserve_space(xdr, 8 * sizeof(uint32_t));
+	if (unlikely(p == NULL))
+		return htonl(NFS4ERR_RESOURCE);
+
+	/* FIXME: implement cb_sequenceres */
+	memset(p, 0, 8 * sizeof(uint32_t));
+out:
+	dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+	return status;
+}
+
 static unsigned process_op(uint32_t minorversion, int nop,
 		struct svc_rqst *rqstp,
 		struct xdr_stream *xdr_in, void *argp,
@@ -371,9 +498,19 @@ static unsigned process_op(uint32_t minorversion, int nop,
 
 #if defined(CONFIG_NFS_V4_1)
 	if (minorversion == 1) {
+		if (op_nr == OP_CB_SEQUENCE) {
+			if (nop != 1) {
+				status = htonl(NFS4ERR_SEQUENCE_POS);
+				goto out;
+			}
+		} else if (nop == 1) {
+			status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
+			goto out;
+		}
 		switch (op_nr) {
 			case OP_CB_GETATTR:
 			case OP_CB_RECALL:
+			case OP_CB_SEQUENCE:
 				op = &callback_ops[op_nr];
 				break;
 			case OP_CB_LAYOUTRECALL:
@@ -382,7 +519,6 @@ static unsigned process_op(uint32_t minorversion, int nop,
 			case OP_CB_RECALL_ANY:
 			case OP_CB_RECALLABLE_OBJ_AVAIL:
 			case OP_CB_RECALL_SLOT:
-			case OP_CB_SEQUENCE:
 			case OP_CB_WANTS_CANCELLED:
 			case OP_CB_NOTIFY_LOCK:
 				op = &callback_ops[0];
@@ -487,7 +623,13 @@ 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_SEQUENCE] = {
+		.process_op = (callback_process_op_t)nfs4_callback_sequence,
+		.decode_args = (callback_decode_arg_t)decode_cb_sequence_args,
+		.encode_res = (callback_encode_res_t)encode_cb_sequence_res,
+		.res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ,
+	},
 };
 
 /*
-- 
1.5.2.86.g99b5



More information about the pNFS mailing list