[pnfs] [PATCH 2/4] cb_sequence: client implementation of cb_sequence
Benny Halevy
bhalevy at panasas.com
Tue May 29 14:19:11 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 3bc2383..2311352 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -82,9 +82,41 @@ struct cb_pnfs_layoutrecallargs {
uint32_t cbl_layoutchanged;
};
+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_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *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 4b3fcba..c149f3b 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -131,3 +131,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 f5c25ca..3780131 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -20,6 +20,8 @@
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 CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
+ 4 + 1 + 3)
#define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -28,6 +30,17 @@
(x) |= ntohl(*p++); \
} while (0)
+#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 *);
@@ -250,6 +263,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;
@@ -399,6 +505,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,
@@ -417,10 +544,20 @@ 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_LAYOUTRECALL:
+ case OP_CB_SEQUENCE:
op = &callback_ops[op_nr];
break;
case OP_CB_NOTIFY:
@@ -428,7 +565,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];
@@ -540,7 +676,13 @@ static struct callback_op callback_ops[] = {
.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,
- }
+ },
+ [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