aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-07 11:08:50 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-07 11:43:49 -0400
commitf39c1bfb5a03e2d255451bff05be0d7255298fa4 (patch)
treec4f7c970840e7803e22ce10809746272d23f6fde
parent01913b49cf1dc6409a07dd2a4cc6af2e77f3c410 (diff)
SUNRPC: Fix a UDP transport regression
Commit 43cedbf0e8dfb9c5610eb7985d5f21263e313802 (SUNRPC: Ensure that we grab the XPRT_LOCK before calling xprt_alloc_slot) is causing hangs in the case of NFS over UDP mounts. Since neither the UDP or the RDMA transport mechanism use dynamic slot allocation, we can skip grabbing the socket lock for those transports. Add a new rpc_xprt_op to allow switching between the TCP and UDP/RDMA case. Note that the NFSv4.1 back channel assigns the slot directly through rpc_run_bc_task, so we can ignore that case. Reported-by: Dick Streefland <dick.streefland@altium.nl> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@vger.kernel.org [>= 3.1]
-rw-r--r--include/linux/sunrpc/xprt.h3
-rw-r--r--net/sunrpc/xprt.c34
-rw-r--r--net/sunrpc/xprtrdma/transport.c1
-rw-r--r--net/sunrpc/xprtsock.c3
4 files changed, 27 insertions, 14 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index cff40aa7db6..bf8c49ff753 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -114,6 +114,7 @@ struct rpc_xprt_ops {
114 void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); 114 void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
115 int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); 115 int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
116 void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); 116 void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
117 void (*alloc_slot)(struct rpc_xprt *xprt, struct rpc_task *task);
117 void (*rpcbind)(struct rpc_task *task); 118 void (*rpcbind)(struct rpc_task *task);
118 void (*set_port)(struct rpc_xprt *xprt, unsigned short port); 119 void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
119 void (*connect)(struct rpc_task *task); 120 void (*connect)(struct rpc_task *task);
@@ -281,6 +282,8 @@ void xprt_connect(struct rpc_task *task);
281void xprt_reserve(struct rpc_task *task); 282void xprt_reserve(struct rpc_task *task);
282int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); 283int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
283int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); 284int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
285void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
286void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
284int xprt_prepare_transmit(struct rpc_task *task); 287int xprt_prepare_transmit(struct rpc_task *task);
285void xprt_transmit(struct rpc_task *task); 288void xprt_transmit(struct rpc_task *task);
286void xprt_end_transmit(struct rpc_task *task); 289void xprt_end_transmit(struct rpc_task *task);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index a5a402a7d21..5d7f61d7559 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -969,11 +969,11 @@ static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
969 return false; 969 return false;
970} 970}
971 971
972static void xprt_alloc_slot(struct rpc_task *task) 972void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
973{ 973{
974 struct rpc_xprt *xprt = task->tk_xprt;
975 struct rpc_rqst *req; 974 struct rpc_rqst *req;
976 975
976 spin_lock(&xprt->reserve_lock);
977 if (!list_empty(&xprt->free)) { 977 if (!list_empty(&xprt->free)) {
978 req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); 978 req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
979 list_del(&req->rq_list); 979 list_del(&req->rq_list);
@@ -994,12 +994,29 @@ static void xprt_alloc_slot(struct rpc_task *task)
994 default: 994 default:
995 task->tk_status = -EAGAIN; 995 task->tk_status = -EAGAIN;
996 } 996 }
997 spin_unlock(&xprt->reserve_lock);
997 return; 998 return;
998out_init_req: 999out_init_req:
999 task->tk_status = 0; 1000 task->tk_status = 0;
1000 task->tk_rqstp = req; 1001 task->tk_rqstp = req;
1001 xprt_request_init(task, xprt); 1002 xprt_request_init(task, xprt);
1003 spin_unlock(&xprt->reserve_lock);
1004}
1005EXPORT_SYMBOL_GPL(xprt_alloc_slot);
1006
1007void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
1008{
1009 /* Note: grabbing the xprt_lock_write() ensures that we throttle
1010 * new slot allocation if the transport is congested (i.e. when
1011 * reconnecting a stream transport or when out of socket write
1012 * buffer space).
1013 */
1014 if (xprt_lock_write(xprt, task)) {
1015 xprt_alloc_slot(xprt, task);
1016 xprt_release_write(xprt, task);
1017 }
1002} 1018}
1019EXPORT_SYMBOL_GPL(xprt_lock_and_alloc_slot);
1003 1020
1004static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) 1021static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
1005{ 1022{
@@ -1083,20 +1100,9 @@ void xprt_reserve(struct rpc_task *task)
1083 if (task->tk_rqstp != NULL) 1100 if (task->tk_rqstp != NULL)
1084 return; 1101 return;
1085 1102
1086 /* Note: grabbing the xprt_lock_write() here is not strictly needed,
1087 * but ensures that we throttle new slot allocation if the transport
1088 * is congested (e.g. if reconnecting or if we're out of socket
1089 * write buffer space).
1090 */
1091 task->tk_timeout = 0; 1103 task->tk_timeout = 0;
1092 task->tk_status = -EAGAIN; 1104 task->tk_status = -EAGAIN;
1093 if (!xprt_lock_write(xprt, task)) 1105 xprt->ops->alloc_slot(xprt, task);
1094 return;
1095
1096 spin_lock(&xprt->reserve_lock);
1097 xprt_alloc_slot(task);
1098 spin_unlock(&xprt->reserve_lock);
1099 xprt_release_write(xprt, task);
1100} 1106}
1101 1107
1102static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) 1108static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 06cdbff79e4..5d9202dc7cb 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -713,6 +713,7 @@ static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
713static struct rpc_xprt_ops xprt_rdma_procs = { 713static struct rpc_xprt_ops xprt_rdma_procs = {
714 .reserve_xprt = xprt_rdma_reserve_xprt, 714 .reserve_xprt = xprt_rdma_reserve_xprt,
715 .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */ 715 .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */
716 .alloc_slot = xprt_alloc_slot,
716 .release_request = xprt_release_rqst_cong, /* ditto */ 717 .release_request = xprt_release_rqst_cong, /* ditto */
717 .set_retrans_timeout = xprt_set_retrans_timeout_def, /* ditto */ 718 .set_retrans_timeout = xprt_set_retrans_timeout_def, /* ditto */
718 .rpcbind = rpcb_getport_async, /* sunrpc/rpcb_clnt.c */ 719 .rpcbind = rpcb_getport_async, /* sunrpc/rpcb_clnt.c */
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 400567243f8..a35b8e52e55 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2473,6 +2473,7 @@ static void bc_destroy(struct rpc_xprt *xprt)
2473static struct rpc_xprt_ops xs_local_ops = { 2473static struct rpc_xprt_ops xs_local_ops = {
2474 .reserve_xprt = xprt_reserve_xprt, 2474 .reserve_xprt = xprt_reserve_xprt,
2475 .release_xprt = xs_tcp_release_xprt, 2475 .release_xprt = xs_tcp_release_xprt,
2476 .alloc_slot = xprt_alloc_slot,
2476 .rpcbind = xs_local_rpcbind, 2477 .rpcbind = xs_local_rpcbind,
2477 .set_port = xs_local_set_port, 2478 .set_port = xs_local_set_port,
2478 .connect = xs_connect, 2479 .connect = xs_connect,
@@ -2489,6 +2490,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
2489 .set_buffer_size = xs_udp_set_buffer_size, 2490 .set_buffer_size = xs_udp_set_buffer_size,
2490 .reserve_xprt = xprt_reserve_xprt_cong, 2491 .reserve_xprt = xprt_reserve_xprt_cong,
2491 .release_xprt = xprt_release_xprt_cong, 2492 .release_xprt = xprt_release_xprt_cong,
2493 .alloc_slot = xprt_alloc_slot,
2492 .rpcbind = rpcb_getport_async, 2494 .rpcbind = rpcb_getport_async,
2493 .set_port = xs_set_port, 2495 .set_port = xs_set_port,
2494 .connect = xs_connect, 2496 .connect = xs_connect,
@@ -2506,6 +2508,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
2506static struct rpc_xprt_ops xs_tcp_ops = { 2508static struct rpc_xprt_ops xs_tcp_ops = {
2507 .reserve_xprt = xprt_reserve_xprt, 2509 .reserve_xprt = xprt_reserve_xprt,
2508 .release_xprt = xs_tcp_release_xprt, 2510 .release_xprt = xs_tcp_release_xprt,
2511 .alloc_slot = xprt_lock_and_alloc_slot,
2509 .rpcbind = rpcb_getport_async, 2512 .rpcbind = rpcb_getport_async,
2510 .set_port = xs_set_port, 2513 .set_port = xs_set_port,
2511 .connect = xs_connect, 2514 .connect = xs_connect,