aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-04-30 05:49:23 -0400
committerJ. Bruce Fields <bfields@redhat.com>2015-05-04 12:02:40 -0400
commitef2a1b3e1067195f1d6b89d8329454775c87f033 (patch)
tree3b6f3b6ba97ceabf6c7bccfae22c6f2a8229ff5d /fs
parent9507271d960a1911a51683888837d75c171cd91f (diff)
nfsd: split transport vs operation errors for callbacks
We must only increment the sequence id if the client has seen and responded to a request. If we failed to deliver it to the client we must resend with the same sequence id. So just like the client track errors at the transport level differently from those returned in the XDR. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-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