diff options
author | Kinglong Mee <kinglongmee@gmail.com> | 2015-06-24 04:33:37 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2015-08-13 08:57:06 -0400 |
commit | 7ba6cad6c88f1bf0b7d66d9628d7c3f36ecb4bfe (patch) | |
tree | 3e91b215d475be27a46c81c14cafd09307a410da /fs/nfsd/nfs4callback.c | |
parent | 9056fff3d5190617a93a4ae658a2ea7b96772834 (diff) |
nfsd: New helper nfsd4_cb_sequence_done() for processing more cb errors
According to Christoph's advice, this patch introduce a new helper
nfsd4_cb_sequence_done() for processing more callback errors, following
the example of the client's nfs41_sequence_done().
Signed-off-by: Kinglong Mee <kinglongmee@gmail.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r-- | fs/nfsd/nfs4callback.c | 122 |
1 files changed, 87 insertions, 35 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index a49201835a97..e7f50c4081d6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -435,12 +435,12 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr, | |||
435 | */ | 435 | */ |
436 | status = 0; | 436 | status = 0; |
437 | out: | 437 | out: |
438 | if (status) | 438 | cb->cb_seq_status = status; |
439 | nfsd4_mark_cb_fault(cb->cb_clp, status); | ||
440 | return status; | 439 | return status; |
441 | out_overflow: | 440 | out_overflow: |
442 | print_overflow_msg(__func__, xdr); | 441 | print_overflow_msg(__func__, xdr); |
443 | return -EIO; | 442 | status = -EIO; |
443 | goto out; | ||
444 | } | 444 | } |
445 | 445 | ||
446 | static int decode_cb_sequence4res(struct xdr_stream *xdr, | 446 | static int decode_cb_sequence4res(struct xdr_stream *xdr, |
@@ -451,11 +451,10 @@ static int decode_cb_sequence4res(struct xdr_stream *xdr, | |||
451 | if (cb->cb_minorversion == 0) | 451 | if (cb->cb_minorversion == 0) |
452 | return 0; | 452 | return 0; |
453 | 453 | ||
454 | status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &cb->cb_status); | 454 | status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &cb->cb_seq_status); |
455 | if (unlikely(status || cb->cb_status)) | 455 | if (unlikely(status || cb->cb_seq_status)) |
456 | return status; | 456 | return status; |
457 | 457 | ||
458 | cb->cb_update_seq_nr = true; | ||
459 | return decode_cb_sequence4resok(xdr, cb); | 458 | return decode_cb_sequence4resok(xdr, cb); |
460 | } | 459 | } |
461 | 460 | ||
@@ -527,7 +526,7 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, | |||
527 | 526 | ||
528 | if (cb != NULL) { | 527 | if (cb != NULL) { |
529 | status = decode_cb_sequence4res(xdr, cb); | 528 | status = decode_cb_sequence4res(xdr, cb); |
530 | if (unlikely(status || cb->cb_status)) | 529 | if (unlikely(status || cb->cb_seq_status)) |
531 | return status; | 530 | return status; |
532 | } | 531 | } |
533 | 532 | ||
@@ -617,7 +616,7 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp, | |||
617 | 616 | ||
618 | if (cb) { | 617 | if (cb) { |
619 | status = decode_cb_sequence4res(xdr, cb); | 618 | status = decode_cb_sequence4res(xdr, cb); |
620 | if (unlikely(status || cb->cb_status)) | 619 | if (unlikely(status || cb->cb_seq_status)) |
621 | return status; | 620 | return status; |
622 | } | 621 | } |
623 | return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status); | 622 | return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status); |
@@ -876,7 +875,11 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | |||
876 | u32 minorversion = clp->cl_minorversion; | 875 | u32 minorversion = clp->cl_minorversion; |
877 | 876 | ||
878 | cb->cb_minorversion = minorversion; | 877 | cb->cb_minorversion = minorversion; |
879 | cb->cb_update_seq_nr = false; | 878 | /* |
879 | * cb_seq_status is only set in decode_cb_sequence4res, | ||
880 | * and so will remain 1 if an rpc level failure occurs. | ||
881 | */ | ||
882 | cb->cb_seq_status = 1; | ||
880 | cb->cb_status = 0; | 883 | cb->cb_status = 0; |
881 | if (minorversion) { | 884 | if (minorversion) { |
882 | if (!nfsd41_cb_get_slot(clp, task)) | 885 | if (!nfsd41_cb_get_slot(clp, task)) |
@@ -885,15 +888,30 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | |||
885 | rpc_call_start(task); | 888 | rpc_call_start(task); |
886 | } | 889 | } |
887 | 890 | ||
888 | static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | 891 | static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback *cb) |
889 | { | 892 | { |
890 | struct nfsd4_callback *cb = calldata; | ||
891 | struct nfs4_client *clp = cb->cb_clp; | 893 | struct nfs4_client *clp = cb->cb_clp; |
894 | struct nfsd4_session *session = clp->cl_cb_session; | ||
895 | bool ret = true; | ||
892 | 896 | ||
893 | dprintk("%s: minorversion=%d\n", __func__, | 897 | if (!clp->cl_minorversion) { |
894 | clp->cl_minorversion); | 898 | /* |
899 | * If the backchannel connection was shut down while this | ||
900 | * task was queued, we need to resubmit it after setting up | ||
901 | * a new backchannel connection. | ||
902 | * | ||
903 | * Note that if we lost our callback connection permanently | ||
904 | * the submission code will error out, so we don't need to | ||
905 | * handle that case here. | ||
906 | */ | ||
907 | if (task->tk_flags & RPC_TASK_KILLED) | ||
908 | goto need_restart; | ||
909 | |||
910 | return true; | ||
911 | } | ||
895 | 912 | ||
896 | if (clp->cl_minorversion) { | 913 | switch (cb->cb_seq_status) { |
914 | case 0: | ||
897 | /* | 915 | /* |
898 | * No need for lock, access serialized in nfsd4_cb_prepare | 916 | * No need for lock, access serialized in nfsd4_cb_prepare |
899 | * | 917 | * |
@@ -901,29 +919,63 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | |||
901 | * If CB_SEQUENCE returns an error, then the state of the slot | 919 | * If CB_SEQUENCE returns an error, then the state of the slot |
902 | * (sequence ID, cached reply) MUST NOT change. | 920 | * (sequence ID, cached reply) MUST NOT change. |
903 | */ | 921 | */ |
904 | if (cb->cb_update_seq_nr) | 922 | ++session->se_cb_seq_nr; |
905 | ++clp->cl_cb_session->se_cb_seq_nr; | 923 | break; |
906 | 924 | case -ESERVERFAULT: | |
907 | clear_bit(0, &clp->cl_cb_slot_busy); | 925 | ++session->se_cb_seq_nr; |
908 | rpc_wake_up_next(&clp->cl_cb_waitq); | 926 | case 1: |
909 | dprintk("%s: freed slot, new seqid=%d\n", __func__, | 927 | case -NFS4ERR_BADSESSION: |
910 | clp->cl_cb_session->se_cb_seq_nr); | 928 | nfsd4_mark_cb_fault(cb->cb_clp, cb->cb_seq_status); |
929 | ret = false; | ||
930 | break; | ||
931 | case -NFS4ERR_DELAY: | ||
932 | if (!rpc_restart_call(task)) | ||
933 | goto out; | ||
934 | |||
935 | rpc_delay(task, 2 * HZ); | ||
936 | return false; | ||
937 | case -NFS4ERR_BADSLOT: | ||
938 | goto retry_nowait; | ||
939 | case -NFS4ERR_SEQ_MISORDERED: | ||
940 | if (session->se_cb_seq_nr != 1) { | ||
941 | session->se_cb_seq_nr = 1; | ||
942 | goto retry_nowait; | ||
943 | } | ||
944 | break; | ||
945 | default: | ||
946 | dprintk("%s: unprocessed error %d\n", __func__, | ||
947 | cb->cb_seq_status); | ||
911 | } | 948 | } |
912 | 949 | ||
913 | /* | 950 | clear_bit(0, &clp->cl_cb_slot_busy); |
914 | * If the backchannel connection was shut down while this | 951 | rpc_wake_up_next(&clp->cl_cb_waitq); |
915 | * task was queued, we need to resubmit it after setting up | 952 | dprintk("%s: freed slot, new seqid=%d\n", __func__, |
916 | * a new backchannel connection. | 953 | clp->cl_cb_session->se_cb_seq_nr); |
917 | * | 954 | |
918 | * Note that if we lost our callback connection permanently | 955 | if (task->tk_flags & RPC_TASK_KILLED) |
919 | * the submission code will error out, so we don't need to | 956 | goto need_restart; |
920 | * handle that case here. | 957 | out: |
921 | */ | 958 | return ret; |
922 | if (task->tk_flags & RPC_TASK_KILLED) { | 959 | retry_nowait: |
923 | task->tk_status = 0; | 960 | if (rpc_restart_call_prepare(task)) |
924 | cb->cb_need_restart = true; | 961 | ret = false; |
962 | goto out; | ||
963 | need_restart: | ||
964 | task->tk_status = 0; | ||
965 | cb->cb_need_restart = true; | ||
966 | return false; | ||
967 | } | ||
968 | |||
969 | static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | ||
970 | { | ||
971 | struct nfsd4_callback *cb = calldata; | ||
972 | struct nfs4_client *clp = cb->cb_clp; | ||
973 | |||
974 | dprintk("%s: minorversion=%d\n", __func__, | ||
975 | clp->cl_minorversion); | ||
976 | |||
977 | if (!nfsd4_cb_sequence_done(task, cb)) | ||
925 | return; | 978 | return; |
926 | } | ||
927 | 979 | ||
928 | if (cb->cb_status) { | 980 | if (cb->cb_status) { |
929 | WARN_ON_ONCE(task->tk_status); | 981 | WARN_ON_ONCE(task->tk_status); |
@@ -1099,8 +1151,8 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, | |||
1099 | cb->cb_msg.rpc_resp = cb; | 1151 | cb->cb_msg.rpc_resp = cb; |
1100 | cb->cb_ops = ops; | 1152 | cb->cb_ops = ops; |
1101 | INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); | 1153 | INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); |
1154 | cb->cb_seq_status = 1; | ||
1102 | cb->cb_status = 0; | 1155 | cb->cb_status = 0; |
1103 | cb->cb_update_seq_nr = false; | ||
1104 | cb->cb_need_restart = false; | 1156 | cb->cb_need_restart = false; |
1105 | } | 1157 | } |
1106 | 1158 | ||