diff options
| -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 | } |
