[PATCH 4/4] cb_sequence: nfsd callback initial implementation
Benny Halevy
bhalevy at panasas.com
Tue May 29 11:23:41 EDT 2007
Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
fs/nfsd/nfs4callback.c | 139 ++++++++++++++++++++++++++++++++++++++++----
fs/nfsd/nfs4state.c | 6 ++
include/linux/nfsd/state.h | 13 ++++
3 files changed, 146 insertions(+), 12 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 2438308..73b818d 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -63,14 +63,16 @@ static const struct rpc_call_ops nfs4_cb_null_ops;
/* Index of predefined Linux callback client operations */
enum {
- NFSPROC4_CLNT_CB_NULL = 0,
+ NFSPROC4_CLNT_CB_NULL = 0,
NFSPROC4_CLNT_CB_RECALL,
NFSPROC4_CLNT_CB_LAYOUT,
+ NFSPROC4_CLNT_CB_SEQUENCE,
};
enum nfs_cb_opnum4 {
OP_CB_RECALL = 4,
OP_CB_LAYOUT = 5,
+ OP_CB_SEQUENCE = 11,
};
#define NFS4_MAXTAGLEN 20
@@ -94,16 +96,36 @@ enum nfs_cb_opnum4 {
#define NFS41_dec_cb_null_sz 0
#define cb_compound41_enc_hdr_sz 3
#define cb_compound41_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2))
+#define sessionid_sz (NFS4_MAX_SESSIONID_LEN >> 2)
+#define cb_sequence41_enc_sz (sessionid_sz + 4 + \
+ 1 /* no referring calls list yet */)
+#define cb_sequence41_dec_sz (op_dec_sz + sessionid_sz + 4)
#define NFS41_enc_cb_recall_sz (cb_compound41_enc_hdr_sz + \
+ cb_sequence41_enc_sz + \
1 + enc_stateid_sz + \
enc_nfs4_fh_sz)
#define NFS41_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \
+ cb_sequence41_dec_sz + \
op_dec_sz)
#define NFS41_enc_cb_layout_sz (cb_compound_enc_hdr_sz + \
+ cb_sequence41_enc_sz + \
1 + 3 + \
enc_nfs4_fh_sz + 4)
#define NFS41_dec_cb_layout_sz (cb_compound_dec_hdr_sz + \
+ cb_sequence41_dec_sz + \
op_dec_sz)
+
+struct nfs41_rpc_args {
+ struct nfs4_callback *args_callback;
+ void *args_op;
+ struct nfs41_cb_sequence *args_seq;
+};
+
+struct nfs41_rpc_res {
+ struct nfs4_callback *res_callback;
+ void *res_op;
+ struct nfs41_cb_sequence *res_seq;
+};
#endif /* defined(CONFIG_NFSD_V4_1) */
/*
@@ -164,6 +186,10 @@ xdr_error: \
return -EIO; \
} \
} while (0)
+#define COPYMEM(x,nbytes) do { \
+ memcpy((x), p, nbytes); \
+ p += XDR_QUADLEN(nbytes); \
+} while (0)
struct nfs4_cb_compound_hdr {
/* args */
@@ -302,6 +328,25 @@ encode_cb_layout(struct xdr_stream *xdr, struct nfs4_layoutrecall *clr)
}
#endif /* CONFIG_PNFS */
+#if defined(CONFIG_NFSD_V4_1)
+static int
+encode_cb_sequence(struct xdr_stream *xdr, struct nfs41_cb_sequence *args)
+{
+ u32 *p;
+
+ RESERVE_SPACE(1 + NFS4_MAX_SESSIONID_LEN + 20);
+
+ WRITE32(OP_CB_SEQUENCE);
+ WRITEMEM(args->cbs_sessionid, NFS4_MAX_SESSIONID_LEN);
+ WRITE32(args->cbs_seqid);
+ WRITE32(args->cbs_slotid);
+ WRITE32(args->cbs_highest_slotid);
+ WRITE32(args->cbsa_cachethis);
+ WRITE32(0); /* FIXME: support referring_call_lists */
+ return 0;
+}
+#endif /* defined(CONFIG_NFSD_V4_1) */
+
static int
nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p)
{
@@ -341,9 +386,10 @@ encode_cb_compound41_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hd
static int
nfs41_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p,
- struct nfs4_cb_recall *args)
+ struct nfs41_rpc_args *rpc_args)
{
struct xdr_stream xdr;
+ struct nfs4_cb_recall *args = rpc_args->args_op;
struct nfs4_cb_compound_hdr hdr = {
.ident = args->cbr_ident,
.nops = 1,
@@ -351,15 +397,17 @@ nfs41_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p,
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_cb_compound41_hdr(&xdr, &hdr);
+ encode_cb_sequence(&xdr, rpc_args->args_seq);
return (encode_cb_recall(&xdr, args));
}
#ifdef CONFIG_PNFS
static int
nfs41_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p,
- struct nfs4_layoutrecall *args)
+ struct nfs41_rpc_args *rpc_args)
{
struct xdr_stream xdr;
+ struct nfs4_layoutrecall *args = rpc_args->args_op;
struct nfs4_cb_compound_hdr hdr = {
.ident = 0,
.nops = 1,
@@ -367,6 +415,7 @@ nfs41_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p,
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_cb_compound41_hdr(&xdr, &hdr);
+ encode_cb_sequence(&xdr, rpc_args->args_seq);
return (encode_cb_layout(&xdr, args));
}
#endif /* CONFIG_PNFS */
@@ -431,7 +480,22 @@ out:
#if defined(CONFIG_NFSD_V4_1)
static int
-nfs41_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
+decode_cb_sequence(struct xdr_stream *xdr, struct nfs41_cb_sequence *res)
+{
+ u32 *p;
+
+ READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
+ COPYMEM(res->cbs_sessionid, NFS4_MAX_SESSIONID_LEN);
+ READ32(res->cbs_seqid);
+ READ32(res->cbs_slotid);
+ READ32(res->cbs_highest_slotid);
+ READ32(res->cbsr_target_highest_slotid);
+ return 0;
+}
+
+static int
+nfs41_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p,
+ struct nfs41_rpc_res *rpc_res)
{
struct xdr_stream xdr;
struct nfs4_cb_compound_hdr hdr;
@@ -441,6 +505,9 @@ nfs41_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
status = decode_cb_compound_hdr(&xdr, &hdr);
if (status)
goto out;
+ status = decode_cb_sequence(&xdr, rpc_res->res_seq);
+ if (status)
+ goto out;
status = decode_cb_op_hdr(&xdr, OP_CB_RECALL);
out:
return status;
@@ -448,7 +515,8 @@ out:
#ifdef CONFIG_PNFS
static int
-nfs41_xdr_dec_cb_layout(struct rpc_rqst *rqstp, u32 *p)
+nfs41_xdr_dec_cb_layout(struct rpc_rqst *rqstp, u32 *p,
+ struct nfs41_rpc_res *rpc_res)
{
struct xdr_stream xdr;
struct nfs4_cb_compound_hdr hdr;
@@ -458,6 +526,9 @@ nfs41_xdr_dec_cb_layout(struct rpc_rqst *rqstp, u32 *p)
status = decode_cb_compound_hdr(&xdr, &hdr);
if (status)
goto out;
+ status = decode_cb_sequence(&xdr, rpc_res->res_seq);
+ if (status)
+ goto out;
status = decode_cb_op_hdr(&xdr, OP_CB_LAYOUT);
out:
return status;
@@ -739,6 +810,32 @@ out_err:
dprintk("NFSD: warning: no callback path to client %.*s\n",
(int)clp->cl_name.len, clp->cl_name.data);
}
+
+/* FIXME: cb_sequence should support referring call lists, cachethis, and multiple slots */
+static int
+nfs41_cb_sequence_setup(struct nfs4_client *clp, struct nfs41_cb_sequence *args)
+{
+ u32 *ptr = (u32 *)clp->cl_sessionid;
+ dprintk("%s: %u:%u:%u:%u\n", __FUNCTION__, ptr[0], ptr[1], ptr[2], ptr[3]);
+
+ mutex_lock(&clp->cl_cb_mutex);
+ memcpy(args->cbs_sessionid, clp->cl_sessionid, NFS4_MAX_SESSIONID_LEN);
+ args->cbs_seqid = ++clp->cl_cb_seq_nr;
+ args->cbs_slotid = 0;
+ args->cbs_highest_slotid = 0;
+ args->cbsa_cachethis = 0;
+ return 0;
+}
+
+static void
+nfs41_cb_sequence_done(struct nfs4_client *clp, struct nfs41_cb_sequence *res)
+{
+ u32 *ptr = (u32 *)res->cbs_sessionid;
+ dprintk("%s: %u:%u:%u:%u\n", __FUNCTION__, ptr[0], ptr[1], ptr[2], ptr[3]);
+
+ /* FIXME: support multiple callback slots */
+ mutex_unlock(&clp->cl_cb_mutex);
+}
#endif
static void
@@ -802,12 +899,23 @@ _nfsd41_cb_recall(struct nfs4_delegation *dp, struct rpc_message *msg)
struct nfs4_client *clp = dp->dl_client;
struct rpc_clnt *clnt = clp->cl_callback.cb_client;
struct nfs4_cb_recall *cbr = &dp->dl_recall;
+ struct nfs41_cb_sequence seq;
+ struct nfs41_rpc_args args = {
+ .args_op = cbr,
+ .args_seq = &seq
+ };
+ struct nfs41_rpc_res res = {
+ .res_seq = &seq
+ };
int status;
+ nfs41_cb_sequence_setup(clp, &seq);
msg->rpc_proc = &nfs41_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
- msg->rpc_argp = cbr;
+ msg->rpc_argp = &args;
+ msg->rpc_resp = &res;
status = rpc_call_sync(clnt, msg, RPC_TASK_SOFT);
+ nfs41_cb_sequence_done(clp, &seq);
return status;
}
@@ -823,11 +931,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
struct nfs4_client *clp = dp->dl_client;
struct rpc_clnt *clnt = clp->cl_callback.cb_client;
struct nfs4_cb_recall *cbr = &dp->dl_recall;
- struct rpc_message msg = {
- .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
- .rpc_argp = cbr,
- };
- int retries = 1;
+ struct rpc_message msg;
int status = 0;
if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
@@ -874,9 +978,18 @@ nfsd4_cb_layout(struct nfs4_layoutrecall *clr)
{
struct nfs4_client *clp = clr->clr_client;
struct rpc_clnt *clnt = NULL;
+ struct nfs41_cb_sequence seq;
+ struct nfs41_rpc_args args = {
+ .args_op = clr,
+ .args_seq = &seq
+ };
+ struct nfs41_rpc_res res = {
+ .res_seq = &seq
+ };
struct rpc_message msg = {
.rpc_proc = &nfs41_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
- .rpc_argp = clr,
+ .rpc_argp = &args,
+ .rpc_resp = &res
};
if (clp)
@@ -892,7 +1005,9 @@ nfsd4_cb_layout(struct nfs4_layoutrecall *clr)
goto out;
}
+ nfs41_cb_sequence_setup(clp, &seq);
clr->clr_status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+ nfs41_cb_sequence_done(clp, &seq);
put_rpccred(msg.rpc_cred);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 12a89d6..e7b71dd 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -521,6 +521,9 @@ alloc_client(struct xdr_netobj name)
if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
memcpy(clp->cl_name.data, name.data, name.len);
clp->cl_name.len = name.len;
+#if defined(CONFIG_NFSD_V4_1)
+ mutex_init(&clp->cl_cb_mutex);
+#endif
}
else {
kfree(clp);
@@ -540,6 +543,9 @@ free_client(struct nfs4_client *clp)
BUG_ON(!list_empty(&clp->cl_openowners));
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
+#if defined(CONFIG_NFSD_V4_1)
+ mutex_destroy(&clp->cl_cb_mutex);
+#endif
kfree(clp->cl_name.data);
kfree(clp);
}
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index f15a975..7ed3863 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -182,6 +182,16 @@ struct current_session {
nfsd_sessionid_t cs_sid;
struct nfs41_slot *cs_slot;
};
+
+struct nfs41_cb_sequence {
+ /* args/res */
+ char cbs_sessionid[NFS4_MAX_SESSIONID_LEN];
+ u32 cbs_seqid;
+ u32 cbs_slotid;
+ u32 cbs_highest_slotid;
+ u32 cbsa_cachethis; /* args only */
+ u32 cbsr_target_highest_slotid; /* res only */
+};
#endif
#define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */
@@ -227,6 +237,9 @@ struct nfs4_client {
* For the v4.1 callback path setup
*/
struct svc_sock * svsk;
+ /* FIXME: support multiple callback slots */
+ struct mutex cl_cb_mutex;
+ u32 cl_cb_seq_nr;
#endif
};
--
1.5.2.86.g99b5
--------------060104090809030008020508
Content-Type: text/plain;
name*0="0001-check-read_buf-result-in-decode_pnfs_layoutrecall_ar.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename*0="0001-check-read_buf-result-in-decode_pnfs_layoutrecall_ar.pa";
filename*1="tch"
More information about the pNFS
mailing list