diff options
author | Ricardo Labiaga <Ricardo.Labiaga@netapp.com> | 2009-09-10 05:27:04 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-09-15 20:52:12 -0400 |
commit | 0421b5c55acd0e88920cb9a5bcea6ed738186853 (patch) | |
tree | d19e8b22635ba8caa36d9ac1cddf6ab3176c7fb7 /fs/nfsd | |
parent | 2af73580b7d7b687175f47ba092640761602b221 (diff) |
nfsd41: Backchannel: Implement cb_recall over NFSv4.1
Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com>
[nfsd41: cb_recall callback]
[Share v4.0 and v4.1 back channel xdr]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Ricardo Labiaga <ricardo.labiaga@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[Share v4.0 and v4.1 back channel xdr]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: use nfsd4_cb_sequence for callback minorversion]
[nfsd41: conditionally decode_sequence in nfs4_xdr_dec_cb_recall]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: Backchannel: Add sequence arguments to callback RPC arguments]
Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com>
[pulled-in definition of nfsd4_cb_done]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4callback.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index d37707d26dee..89f23eddb8f6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -288,15 +288,19 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | |||
288 | } | 288 | } |
289 | 289 | ||
290 | static int | 290 | static int |
291 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args) | 291 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, |
292 | struct nfs4_rpc_args *rpc_args) | ||
292 | { | 293 | { |
293 | struct xdr_stream xdr; | 294 | struct xdr_stream xdr; |
295 | struct nfs4_delegation *args = rpc_args->args_op; | ||
294 | struct nfs4_cb_compound_hdr hdr = { | 296 | struct nfs4_cb_compound_hdr hdr = { |
295 | .ident = args->dl_ident, | 297 | .ident = args->dl_ident, |
298 | .minorversion = rpc_args->args_seq.cbs_minorversion, | ||
296 | }; | 299 | }; |
297 | 300 | ||
298 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 301 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
299 | encode_cb_compound_hdr(&xdr, &hdr); | 302 | encode_cb_compound_hdr(&xdr, &hdr); |
303 | encode_cb_sequence(&xdr, &rpc_args->args_seq, &hdr); | ||
300 | encode_cb_recall(&xdr, args, &hdr); | 304 | encode_cb_recall(&xdr, args, &hdr); |
301 | encode_cb_nops(&hdr); | 305 | encode_cb_nops(&hdr); |
302 | return 0; | 306 | return 0; |
@@ -396,7 +400,8 @@ nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) | |||
396 | } | 400 | } |
397 | 401 | ||
398 | static int | 402 | static int |
399 | nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p) | 403 | nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p, |
404 | struct nfsd4_cb_sequence *seq) | ||
400 | { | 405 | { |
401 | struct xdr_stream xdr; | 406 | struct xdr_stream xdr; |
402 | struct nfs4_cb_compound_hdr hdr; | 407 | struct nfs4_cb_compound_hdr hdr; |
@@ -406,6 +411,11 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p) | |||
406 | status = decode_cb_compound_hdr(&xdr, &hdr); | 411 | status = decode_cb_compound_hdr(&xdr, &hdr); |
407 | if (status) | 412 | if (status) |
408 | goto out; | 413 | goto out; |
414 | if (seq) { | ||
415 | status = decode_cb_sequence(&xdr, seq, rqstp); | ||
416 | if (status) | ||
417 | goto out; | ||
418 | } | ||
409 | status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); | 419 | status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); |
410 | out: | 420 | out: |
411 | return status; | 421 | return status; |
@@ -634,11 +644,34 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | |||
634 | rpc_call_start(task); | 644 | rpc_call_start(task); |
635 | } | 645 | } |
636 | 646 | ||
647 | static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | ||
648 | { | ||
649 | struct nfs4_delegation *dp = calldata; | ||
650 | struct nfs4_client *clp = dp->dl_client; | ||
651 | |||
652 | dprintk("%s: minorversion=%d\n", __func__, | ||
653 | clp->cl_cb_conn.cb_minorversion); | ||
654 | |||
655 | if (clp->cl_cb_conn.cb_minorversion) { | ||
656 | /* No need for lock, access serialized in nfsd4_cb_prepare */ | ||
657 | ++clp->cl_cb_seq_nr; | ||
658 | clear_bit(0, &clp->cl_cb_slot_busy); | ||
659 | rpc_wake_up_next(&clp->cl_cb_waitq); | ||
660 | dprintk("%s: freed slot, new seqid=%d\n", __func__, | ||
661 | clp->cl_cb_seq_nr); | ||
662 | |||
663 | /* We're done looking into the sequence information */ | ||
664 | task->tk_msg.rpc_resp = NULL; | ||
665 | } | ||
666 | } | ||
667 | |||
637 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | 668 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
638 | { | 669 | { |
639 | struct nfs4_delegation *dp = calldata; | 670 | struct nfs4_delegation *dp = calldata; |
640 | struct nfs4_client *clp = dp->dl_client; | 671 | struct nfs4_client *clp = dp->dl_client; |
641 | 672 | ||
673 | nfsd4_cb_done(task, calldata); | ||
674 | |||
642 | switch (task->tk_status) { | 675 | switch (task->tk_status) { |
643 | case -EIO: | 676 | case -EIO: |
644 | /* Network partition? */ | 677 | /* Network partition? */ |
@@ -651,16 +684,19 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
651 | break; | 684 | break; |
652 | default: | 685 | default: |
653 | /* success, or error we can't handle */ | 686 | /* success, or error we can't handle */ |
654 | return; | 687 | goto done; |
655 | } | 688 | } |
656 | if (dp->dl_retries--) { | 689 | if (dp->dl_retries--) { |
657 | rpc_delay(task, 2*HZ); | 690 | rpc_delay(task, 2*HZ); |
658 | task->tk_status = 0; | 691 | task->tk_status = 0; |
659 | rpc_restart_call(task); | 692 | rpc_restart_call(task); |
693 | return; | ||
660 | } else { | 694 | } else { |
661 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | 695 | atomic_set(&clp->cl_cb_conn.cb_set, 0); |
662 | warn_no_callback_path(clp, task->tk_status); | 696 | warn_no_callback_path(clp, task->tk_status); |
663 | } | 697 | } |
698 | done: | ||
699 | kfree(task->tk_msg.rpc_argp); | ||
664 | } | 700 | } |
665 | 701 | ||
666 | static void nfsd4_cb_recall_release(void *calldata) | 702 | static void nfsd4_cb_recall_release(void *calldata) |
@@ -686,17 +722,24 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
686 | { | 722 | { |
687 | struct nfs4_client *clp = dp->dl_client; | 723 | struct nfs4_client *clp = dp->dl_client; |
688 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; | 724 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
725 | struct nfs4_rpc_args *args; | ||
689 | struct rpc_message msg = { | 726 | struct rpc_message msg = { |
690 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 727 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
691 | .rpc_argp = dp, | ||
692 | .rpc_cred = callback_cred | 728 | .rpc_cred = callback_cred |
693 | }; | 729 | }; |
694 | int status; | 730 | int status = -ENOMEM; |
695 | 731 | ||
732 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
733 | if (!args) | ||
734 | goto out; | ||
735 | args->args_op = dp; | ||
736 | msg.rpc_argp = args; | ||
696 | dp->dl_retries = 1; | 737 | dp->dl_retries = 1; |
697 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, | 738 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, |
698 | &nfsd4_cb_recall_ops, dp); | 739 | &nfsd4_cb_recall_ops, dp); |
740 | out: | ||
699 | if (status) { | 741 | if (status) { |
742 | kfree(args); | ||
700 | put_nfs4_client(clp); | 743 | put_nfs4_client(clp); |
701 | nfs4_put_delegation(dp); | 744 | nfs4_put_delegation(dp); |
702 | } | 745 | } |