aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c119
1 files changed, 55 insertions, 64 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 58277859a467..5694cfb7a47b 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -224,7 +224,7 @@ static int nfs_cb_stat_to_errno(int status)
224} 224}
225 225
226static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, 226static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
227 enum nfsstat4 *status) 227 int *status)
228{ 228{
229 __be32 *p; 229 __be32 *p;
230 u32 op; 230 u32 op;
@@ -235,7 +235,7 @@ static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
235 op = be32_to_cpup(p++); 235 op = be32_to_cpup(p++);
236 if (unlikely(op != expected)) 236 if (unlikely(op != expected))
237 goto out_unexpected; 237 goto out_unexpected;
238 *status = be32_to_cpup(p); 238 *status = nfs_cb_stat_to_errno(be32_to_cpup(p));
239 return 0; 239 return 0;
240out_overflow: 240out_overflow:
241 print_overflow_msg(__func__, xdr); 241 print_overflow_msg(__func__, xdr);
@@ -446,22 +446,16 @@ out_overflow:
446static int decode_cb_sequence4res(struct xdr_stream *xdr, 446static int decode_cb_sequence4res(struct xdr_stream *xdr,
447 struct nfsd4_callback *cb) 447 struct nfsd4_callback *cb)
448{ 448{
449 enum nfsstat4 nfserr;
450 int status; 449 int status;
451 450
452 if (cb->cb_minorversion == 0) 451 if (cb->cb_minorversion == 0)
453 return 0; 452 return 0;
454 453
455 status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr); 454 status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &cb->cb_status);
456 if (unlikely(status)) 455 if (unlikely(status || cb->cb_status))
457 goto out; 456 return status;
458 if (unlikely(nfserr != NFS4_OK)) 457
459 goto out_default; 458 return decode_cb_sequence4resok(xdr, cb);
460 status = decode_cb_sequence4resok(xdr, cb);
461out:
462 return status;
463out_default:
464 return nfs_cb_stat_to_errno(nfserr);
465} 459}
466 460
467/* 461/*
@@ -524,26 +518,19 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
524 struct nfsd4_callback *cb) 518 struct nfsd4_callback *cb)
525{ 519{
526 struct nfs4_cb_compound_hdr hdr; 520 struct nfs4_cb_compound_hdr hdr;
527 enum nfsstat4 nfserr;
528 int status; 521 int status;
529 522
530 status = decode_cb_compound4res(xdr, &hdr); 523 status = decode_cb_compound4res(xdr, &hdr);
531 if (unlikely(status)) 524 if (unlikely(status))
532 goto out; 525 return status;
533 526
534 if (cb != NULL) { 527 if (cb != NULL) {
535 status = decode_cb_sequence4res(xdr, cb); 528 status = decode_cb_sequence4res(xdr, cb);
536 if (unlikely(status)) 529 if (unlikely(status || cb->cb_status))
537 goto out; 530 return status;
538 } 531 }
539 532
540 status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr); 533 return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status);
541 if (unlikely(status))
542 goto out;
543 if (unlikely(nfserr != NFS4_OK))
544 status = nfs_cb_stat_to_errno(nfserr);
545out:
546 return status;
547} 534}
548 535
549#ifdef CONFIG_NFSD_PNFS 536#ifdef CONFIG_NFSD_PNFS
@@ -621,24 +608,18 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp,
621 struct nfsd4_callback *cb) 608 struct nfsd4_callback *cb)
622{ 609{
623 struct nfs4_cb_compound_hdr hdr; 610 struct nfs4_cb_compound_hdr hdr;
624 enum nfsstat4 nfserr;
625 int status; 611 int status;
626 612
627 status = decode_cb_compound4res(xdr, &hdr); 613 status = decode_cb_compound4res(xdr, &hdr);
628 if (unlikely(status)) 614 if (unlikely(status))
629 goto out; 615 return status;
616
630 if (cb) { 617 if (cb) {
631 status = decode_cb_sequence4res(xdr, cb); 618 status = decode_cb_sequence4res(xdr, cb);
632 if (unlikely(status)) 619 if (unlikely(status || cb->cb_status))
633 goto out; 620 return status;
634 } 621 }
635 status = decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &nfserr); 622 return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status);
636 if (unlikely(status))
637 goto out;
638 if (unlikely(nfserr != NFS4_OK))
639 status = nfs_cb_stat_to_errno(nfserr);
640out:
641 return status;
642} 623}
643#endif /* CONFIG_NFSD_PNFS */ 624#endif /* CONFIG_NFSD_PNFS */
644 625
@@ -898,13 +879,6 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
898 if (!nfsd41_cb_get_slot(clp, task)) 879 if (!nfsd41_cb_get_slot(clp, task))
899 return; 880 return;
900 } 881 }
901 spin_lock(&clp->cl_lock);
902 if (list_empty(&cb->cb_per_client)) {
903 /* This is the first call, not a restart */
904 cb->cb_done = false;
905 list_add(&cb->cb_per_client, &clp->cl_callbacks);
906 }
907 spin_unlock(&clp->cl_lock);
908 rpc_call_start(task); 882 rpc_call_start(task);
909} 883}
910 884
@@ -918,22 +892,33 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
918 892
919 if (clp->cl_minorversion) { 893 if (clp->cl_minorversion) {
920 /* No need for lock, access serialized in nfsd4_cb_prepare */ 894 /* No need for lock, access serialized in nfsd4_cb_prepare */
921 ++clp->cl_cb_session->se_cb_seq_nr; 895 if (!task->tk_status)
896 ++clp->cl_cb_session->se_cb_seq_nr;
922 clear_bit(0, &clp->cl_cb_slot_busy); 897 clear_bit(0, &clp->cl_cb_slot_busy);
923 rpc_wake_up_next(&clp->cl_cb_waitq); 898 rpc_wake_up_next(&clp->cl_cb_waitq);
924 dprintk("%s: freed slot, new seqid=%d\n", __func__, 899 dprintk("%s: freed slot, new seqid=%d\n", __func__,
925 clp->cl_cb_session->se_cb_seq_nr); 900 clp->cl_cb_session->se_cb_seq_nr);
926 } 901 }
927 902
928 if (clp->cl_cb_client != task->tk_client) { 903 /*
929 /* We're shutting down or changing cl_cb_client; leave 904 * If the backchannel connection was shut down while this
930 * it to nfsd4_process_cb_update to restart the call if 905 * task was queued, we need to resubmit it after setting up
931 * necessary. */ 906 * a new backchannel connection.
907 *
908 * Note that if we lost our callback connection permanently
909 * the submission code will error out, so we don't need to
910 * handle that case here.
911 */
912 if (task->tk_flags & RPC_TASK_KILLED) {
913 task->tk_status = 0;
914 cb->cb_need_restart = true;
932 return; 915 return;
933 } 916 }
934 917
935 if (cb->cb_done) 918 if (cb->cb_status) {
936 return; 919 WARN_ON_ONCE(task->tk_status);
920 task->tk_status = cb->cb_status;
921 }
937 922
938 switch (cb->cb_ops->done(cb, task)) { 923 switch (cb->cb_ops->done(cb, task)) {
939 case 0: 924 case 0:
@@ -949,21 +934,17 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
949 default: 934 default:
950 BUG(); 935 BUG();
951 } 936 }
952 cb->cb_done = true;
953} 937}
954 938
955static void nfsd4_cb_release(void *calldata) 939static void nfsd4_cb_release(void *calldata)
956{ 940{
957 struct nfsd4_callback *cb = calldata; 941 struct nfsd4_callback *cb = calldata;
958 struct nfs4_client *clp = cb->cb_clp;
959
960 if (cb->cb_done) {
961 spin_lock(&clp->cl_lock);
962 list_del(&cb->cb_per_client);
963 spin_unlock(&clp->cl_lock);
964 942
943 if (cb->cb_need_restart)
944 nfsd4_run_cb(cb);
945 else
965 cb->cb_ops->release(cb); 946 cb->cb_ops->release(cb);
966 } 947
967} 948}
968 949
969static const struct rpc_call_ops nfsd4_cb_ops = { 950static const struct rpc_call_ops nfsd4_cb_ops = {
@@ -1058,9 +1039,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
1058 nfsd4_mark_cb_down(clp, err); 1039 nfsd4_mark_cb_down(clp, err);
1059 return; 1040 return;
1060 } 1041 }
1061 /* Yay, the callback channel's back! Restart any callbacks: */
1062 list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
1063 queue_work(callback_wq, &cb->cb_work);
1064} 1042}
1065 1043
1066static void 1044static void
@@ -1071,8 +1049,12 @@ nfsd4_run_cb_work(struct work_struct *work)
1071 struct nfs4_client *clp = cb->cb_clp; 1049 struct nfs4_client *clp = cb->cb_clp;
1072 struct rpc_clnt *clnt; 1050 struct rpc_clnt *clnt;
1073 1051
1074 if (cb->cb_ops && cb->cb_ops->prepare) 1052 if (cb->cb_need_restart) {
1075 cb->cb_ops->prepare(cb); 1053 cb->cb_need_restart = false;
1054 } else {
1055 if (cb->cb_ops && cb->cb_ops->prepare)
1056 cb->cb_ops->prepare(cb);
1057 }
1076 1058
1077 if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK) 1059 if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK)
1078 nfsd4_process_cb_update(cb); 1060 nfsd4_process_cb_update(cb);
@@ -1084,6 +1066,15 @@ nfsd4_run_cb_work(struct work_struct *work)
1084 cb->cb_ops->release(cb); 1066 cb->cb_ops->release(cb);
1085 return; 1067 return;
1086 } 1068 }
1069
1070 /*
1071 * Don't send probe messages for 4.1 or later.
1072 */
1073 if (!cb->cb_ops && clp->cl_minorversion) {
1074 clp->cl_cb_state = NFSD4_CB_UP;
1075 return;
1076 }
1077
1087 cb->cb_msg.rpc_cred = clp->cl_cb_cred; 1078 cb->cb_msg.rpc_cred = clp->cl_cb_cred;
1088 rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, 1079 rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
1089 cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb); 1080 cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb);
@@ -1098,8 +1089,8 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
1098 cb->cb_msg.rpc_resp = cb; 1089 cb->cb_msg.rpc_resp = cb;
1099 cb->cb_ops = ops; 1090 cb->cb_ops = ops;
1100 INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); 1091 INIT_WORK(&cb->cb_work, nfsd4_run_cb_work);
1101 INIT_LIST_HEAD(&cb->cb_per_client); 1092 cb->cb_status = 0;
1102 cb->cb_done = true; 1093 cb->cb_need_restart = false;
1103} 1094}
1104 1095
1105void nfsd4_run_cb(struct nfsd4_callback *cb) 1096void nfsd4_run_cb(struct nfsd4_callback *cb)