Skip to content

Commit f39c1bf

Browse files
Trond MyklebustTrond Myklebust
authored andcommitted
SUNRPC: Fix a UDP transport regression
Commit 43cedbf (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 <[email protected]> Signed-off-by: Trond Myklebust <[email protected]> Cc: [email protected] [>= 3.1]
1 parent 01913b4 commit f39c1bf

4 files changed

Lines changed: 27 additions & 14 deletions

File tree

include/linux/sunrpc/xprt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ struct rpc_xprt_ops {
114114
void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
115115
int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
116116
void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
117+
void (*alloc_slot)(struct rpc_xprt *xprt, struct rpc_task *task);
117118
void (*rpcbind)(struct rpc_task *task);
118119
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
119120
void (*connect)(struct rpc_task *task);
@@ -281,6 +282,8 @@ void xprt_connect(struct rpc_task *task);
281282
void xprt_reserve(struct rpc_task *task);
282283
int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
283284
int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
285+
void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
286+
void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
284287
int xprt_prepare_transmit(struct rpc_task *task);
285288
void xprt_transmit(struct rpc_task *task);
286289
void xprt_end_transmit(struct rpc_task *task);

net/sunrpc/xprt.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -969,11 +969,11 @@ static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
969969
return false;
970970
}
971971

972-
static void xprt_alloc_slot(struct rpc_task *task)
972+
void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
973973
{
974-
struct rpc_xprt *xprt = task->tk_xprt;
975974
struct rpc_rqst *req;
976975

976+
spin_lock(&xprt->reserve_lock);
977977
if (!list_empty(&xprt->free)) {
978978
req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
979979
list_del(&req->rq_list);
@@ -994,12 +994,29 @@ static void xprt_alloc_slot(struct rpc_task *task)
994994
default:
995995
task->tk_status = -EAGAIN;
996996
}
997+
spin_unlock(&xprt->reserve_lock);
997998
return;
998999
out_init_req:
9991000
task->tk_status = 0;
10001001
task->tk_rqstp = req;
10011002
xprt_request_init(task, xprt);
1003+
spin_unlock(&xprt->reserve_lock);
1004+
}
1005+
EXPORT_SYMBOL_GPL(xprt_alloc_slot);
1006+
1007+
void 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+
}
10021018
}
1019+
EXPORT_SYMBOL_GPL(xprt_lock_and_alloc_slot);
10031020

10041021
static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
10051022
{
@@ -1083,20 +1100,9 @@ void xprt_reserve(struct rpc_task *task)
10831100
if (task->tk_rqstp != NULL)
10841101
return;
10851102

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-
*/
10911103
task->tk_timeout = 0;
10921104
task->tk_status = -EAGAIN;
1093-
if (!xprt_lock_write(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);
1105+
xprt->ops->alloc_slot(xprt, task);
11001106
}
11011107

11021108
static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)

net/sunrpc/xprtrdma/transport.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
713713
static struct rpc_xprt_ops xprt_rdma_procs = {
714714
.reserve_xprt = xprt_rdma_reserve_xprt,
715715
.release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */
716+
.alloc_slot = xprt_alloc_slot,
716717
.release_request = xprt_release_rqst_cong, /* ditto */
717718
.set_retrans_timeout = xprt_set_retrans_timeout_def, /* ditto */
718719
.rpcbind = rpcb_getport_async, /* sunrpc/rpcb_clnt.c */

net/sunrpc/xprtsock.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,6 +2473,7 @@ static void bc_destroy(struct rpc_xprt *xprt)
24732473
static struct rpc_xprt_ops xs_local_ops = {
24742474
.reserve_xprt = xprt_reserve_xprt,
24752475
.release_xprt = xs_tcp_release_xprt,
2476+
.alloc_slot = xprt_alloc_slot,
24762477
.rpcbind = xs_local_rpcbind,
24772478
.set_port = xs_local_set_port,
24782479
.connect = xs_connect,
@@ -2489,6 +2490,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
24892490
.set_buffer_size = xs_udp_set_buffer_size,
24902491
.reserve_xprt = xprt_reserve_xprt_cong,
24912492
.release_xprt = xprt_release_xprt_cong,
2493+
.alloc_slot = xprt_alloc_slot,
24922494
.rpcbind = rpcb_getport_async,
24932495
.set_port = xs_set_port,
24942496
.connect = xs_connect,
@@ -2506,6 +2508,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
25062508
static struct rpc_xprt_ops xs_tcp_ops = {
25072509
.reserve_xprt = xprt_reserve_xprt,
25082510
.release_xprt = xs_tcp_release_xprt,
2511+
.alloc_slot = xprt_lock_and_alloc_slot,
25092512
.rpcbind = rpcb_getport_async,
25102513
.set_port = xs_set_port,
25112514
.connect = xs_connect,

0 commit comments

Comments
 (0)