aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4callback.c60
-rw-r--r--fs/nfsd/state.h1
2 files changed, 25 insertions, 36 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 58277859a467..cd58b7cd3f1a 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
@@ -918,7 +899,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
918 899
919 if (clp->cl_minorversion) { 900 if (clp->cl_minorversion) {
920 /* No need for lock, access serialized in nfsd4_cb_prepare */ 901 /* No need for lock, access serialized in nfsd4_cb_prepare */
921 ++clp->cl_cb_session->se_cb_seq_nr; 902 if (!task->tk_status)
903 ++clp->cl_cb_session->se_cb_seq_nr;
922 clear_bit(0, &clp->cl_cb_slot_busy); 904 clear_bit(0, &clp->cl_cb_slot_busy);
923 rpc_wake_up_next(&clp->cl_cb_waitq); 905 rpc_wake_up_next(&clp->cl_cb_waitq);
924 dprintk("%s: freed slot, new seqid=%d\n", __func__, 906 dprintk("%s: freed slot, new seqid=%d\n", __func__,
@@ -935,6 +917,11 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
935 if (cb->cb_done) 917 if (cb->cb_done)
936 return; 918 return;
937 919
920 if (cb->cb_status) {
921 WARN_ON_ONCE(task->tk_status);
922 task->tk_status = cb->cb_status;
923 }
924
938 switch (cb->cb_ops->done(cb, task)) { 925 switch (cb->cb_ops->done(cb, task)) {
939 case 0: 926 case 0:
940 task->tk_status = 0; 927 task->tk_status = 0;
@@ -1099,6 +1086,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
1099 cb->cb_ops = ops; 1086 cb->cb_ops = ops;
1100 INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); 1087 INIT_WORK(&cb->cb_work, nfsd4_run_cb_work);
1101 INIT_LIST_HEAD(&cb->cb_per_client); 1088 INIT_LIST_HEAD(&cb->cb_per_client);
1089 cb->cb_status = 0;
1102 cb->cb_done = true; 1090 cb->cb_done = true;
1103} 1091}
1104 1092
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index bde45d90b746..e791985a7318 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -68,6 +68,7 @@ struct nfsd4_callback {
68 struct rpc_message cb_msg; 68 struct rpc_message cb_msg;
69 struct nfsd4_callback_ops *cb_ops; 69 struct nfsd4_callback_ops *cb_ops;
70 struct work_struct cb_work; 70 struct work_struct cb_work;
71 int cb_status;
71 bool cb_done; 72 bool cb_done;
72}; 73};
73 74