aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprtrdma
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2014-05-28 10:34:57 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2014-06-04 08:56:52 -0400
commite7ce710a8802351bd4118c5d6136c1d850f67cf9 (patch)
treef9c4a23768955b85ee7d6cf519906004c86aff61 /net/sunrpc/xprtrdma
parent4f4cf5ad6fc1b16dc8dc9d750bb80b35eba5e98d (diff)
xprtrdma: Avoid deadlock when credit window is reset
Update the cwnd while processing the server's reply. Otherwise the next task on the xprt_sending queue is still subject to the old credit window. Currently, no task is awoken if the old congestion window is still exceeded, even if the new window is larger, and a deadlock results. This is an issue during a transport reconnect. Servers don't normally shrink the credit window, but the client does reset it to 1 when reconnecting so the server can safely grow it again. As a minor optimization, remove the hack of grabbing the initial cwnd size (which happens to be RPC_CWNDSCALE) and using that value as the congestion scaling factor. The scaling value is invariant, and we are better off without the multiplication operation. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'net/sunrpc/xprtrdma')
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c6
-rw-r--r--net/sunrpc/xprtrdma/transport.c19
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h1
3 files changed, 7 insertions, 19 deletions
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index ac65b0cb66b2..77b84cfa5c77 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -716,6 +716,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
716 struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); 716 struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
717 __be32 *iptr; 717 __be32 *iptr;
718 int rdmalen, status; 718 int rdmalen, status;
719 unsigned long cwnd;
719 720
720 /* Check status. If bad, signal disconnect and return rep to pool */ 721 /* Check status. If bad, signal disconnect and return rep to pool */
721 if (rep->rr_len == ~0U) { 722 if (rep->rr_len == ~0U) {
@@ -845,6 +846,11 @@ badheader:
845 break; 846 break;
846 } 847 }
847 848
849 cwnd = xprt->cwnd;
850 xprt->cwnd = atomic_read(&r_xprt->rx_buf.rb_credits) << RPC_CWNDSHIFT;
851 if (xprt->cwnd > cwnd)
852 xprt_release_rqst_cong(rqst->rq_task);
853
848 dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n", 854 dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",
849 __func__, xprt, rqst, status); 855 __func__, xprt, rqst, status);
850 xprt_complete_rqst(rqst->rq_task, status); 856 xprt_complete_rqst(rqst->rq_task, status);
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 6b84d7d59e18..187894b4c33f 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -448,23 +448,6 @@ xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
448 } 448 }
449} 449}
450 450
451static int
452xprt_rdma_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
453{
454 struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
455 int credits = atomic_read(&r_xprt->rx_buf.rb_credits);
456
457 /* == RPC_CWNDSCALE @ init, but *after* setup */
458 if (r_xprt->rx_buf.rb_cwndscale == 0UL) {
459 r_xprt->rx_buf.rb_cwndscale = xprt->cwnd;
460 dprintk("RPC: %s: cwndscale %lu\n", __func__,
461 r_xprt->rx_buf.rb_cwndscale);
462 BUG_ON(r_xprt->rx_buf.rb_cwndscale <= 0);
463 }
464 xprt->cwnd = credits * r_xprt->rx_buf.rb_cwndscale;
465 return xprt_reserve_xprt_cong(xprt, task);
466}
467
468/* 451/*
469 * The RDMA allocate/free functions need the task structure as a place 452 * The RDMA allocate/free functions need the task structure as a place
470 * to hide the struct rpcrdma_req, which is necessary for the actual send/recv 453 * to hide the struct rpcrdma_req, which is necessary for the actual send/recv
@@ -686,7 +669,7 @@ static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
686 */ 669 */
687 670
688static struct rpc_xprt_ops xprt_rdma_procs = { 671static struct rpc_xprt_ops xprt_rdma_procs = {
689 .reserve_xprt = xprt_rdma_reserve_xprt, 672 .reserve_xprt = xprt_reserve_xprt_cong,
690 .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */ 673 .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */
691 .alloc_slot = xprt_alloc_slot, 674 .alloc_slot = xprt_alloc_slot,
692 .release_request = xprt_release_rqst_cong, /* ditto */ 675 .release_request = xprt_release_rqst_cong, /* ditto */
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index 0c3b88ea5edb..89e7cd479705 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -212,7 +212,6 @@ struct rpcrdma_req {
212struct rpcrdma_buffer { 212struct rpcrdma_buffer {
213 spinlock_t rb_lock; /* protects indexes */ 213 spinlock_t rb_lock; /* protects indexes */
214 atomic_t rb_credits; /* most recent server credits */ 214 atomic_t rb_credits; /* most recent server credits */
215 unsigned long rb_cwndscale; /* cached framework rpc_cwndscale */
216 int rb_max_requests;/* client max requests */ 215 int rb_max_requests;/* client max requests */
217 struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */ 216 struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */
218 int rb_send_index; 217 int rb_send_index;