summaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
authorKinglong Mee <kinglongmee@gmail.com>2015-06-24 04:33:37 -0400
committerJ. Bruce Fields <bfields@redhat.com>2015-08-13 08:57:06 -0400
commit7ba6cad6c88f1bf0b7d66d9628d7c3f36ecb4bfe (patch)
tree3e91b215d475be27a46c81c14cafd09307a410da /fs/nfsd/nfs4callback.c
parent9056fff3d5190617a93a4ae658a2ea7b96772834 (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.c122
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;
437out: 437out:
438 if (status) 438 cb->cb_seq_status = status;
439 nfsd4_mark_cb_fault(cb->cb_clp, status);
440 return status; 439 return status;
441out_overflow: 440out_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
446static int decode_cb_sequence4res(struct xdr_stream *xdr, 446static 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
888static void nfsd4_cb_done(struct rpc_task *task, void *calldata) 891static 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. 957out:
921 */ 958 return ret;
922 if (task->tk_flags & RPC_TASK_KILLED) { 959retry_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;
963need_restart:
964 task->tk_status = 0;
965 cb->cb_need_restart = true;
966 return false;
967}
968
969static 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