diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-16 16:12:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-16 16:12:53 -0500 |
commit | d025fbf1a2cd1d60f39579d331a9accf84c5ec5b (patch) | |
tree | 0314bc504eb0f5cc1ea4dd611eb55eb2cc88b98e /net/sunrpc | |
parent | f6f3732162b5ae3c771b9285a5a32d72b8586920 (diff) | |
parent | 90d91b0cd371193d9dbfa9beacab8ab9a4cb75e0 (diff) |
Merge tag 'nfs-for-4.15-3' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client fixes from Anna Schumaker:
"This has two stable bugfixes, one to fix a BUG_ON() when
nfs_commit_inode() is called with no outstanding commit requests and
another to fix a race in the SUNRPC receive codepath.
Additionally, there are also fixes for an NFS client deadlock and an
xprtrdma performance regression.
Summary:
Stable bugfixes:
- NFS: Avoid a BUG_ON() in nfs_commit_inode() by not waiting for a
commit in the case that there were no commit requests.
- SUNRPC: Fix a race in the receive code path
Other fixes:
- NFS: Fix a deadlock in nfs client initialization
- xprtrdma: Fix a performance regression for small IOs"
* tag 'nfs-for-4.15-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
SUNRPC: Fix a race in the receive code path
nfs: don't wait on commit in nfs_commit_inode() if there were no commit requests
xprtrdma: Spread reply processing over more CPUs
nfs: fix a deadlock in nfs client initialization
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/xprt.c | 28 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 6 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/transport.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/xprt_rdma.h | 1 |
5 files changed, 24 insertions, 15 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 333b9d697ae5..33b74fd84051 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -1001,6 +1001,7 @@ void xprt_transmit(struct rpc_task *task) | |||
1001 | { | 1001 | { |
1002 | struct rpc_rqst *req = task->tk_rqstp; | 1002 | struct rpc_rqst *req = task->tk_rqstp; |
1003 | struct rpc_xprt *xprt = req->rq_xprt; | 1003 | struct rpc_xprt *xprt = req->rq_xprt; |
1004 | unsigned int connect_cookie; | ||
1004 | int status, numreqs; | 1005 | int status, numreqs; |
1005 | 1006 | ||
1006 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); | 1007 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); |
@@ -1024,6 +1025,7 @@ void xprt_transmit(struct rpc_task *task) | |||
1024 | } else if (!req->rq_bytes_sent) | 1025 | } else if (!req->rq_bytes_sent) |
1025 | return; | 1026 | return; |
1026 | 1027 | ||
1028 | connect_cookie = xprt->connect_cookie; | ||
1027 | req->rq_xtime = ktime_get(); | 1029 | req->rq_xtime = ktime_get(); |
1028 | status = xprt->ops->send_request(task); | 1030 | status = xprt->ops->send_request(task); |
1029 | trace_xprt_transmit(xprt, req->rq_xid, status); | 1031 | trace_xprt_transmit(xprt, req->rq_xid, status); |
@@ -1047,20 +1049,28 @@ void xprt_transmit(struct rpc_task *task) | |||
1047 | xprt->stat.bklog_u += xprt->backlog.qlen; | 1049 | xprt->stat.bklog_u += xprt->backlog.qlen; |
1048 | xprt->stat.sending_u += xprt->sending.qlen; | 1050 | xprt->stat.sending_u += xprt->sending.qlen; |
1049 | xprt->stat.pending_u += xprt->pending.qlen; | 1051 | xprt->stat.pending_u += xprt->pending.qlen; |
1052 | spin_unlock_bh(&xprt->transport_lock); | ||
1050 | 1053 | ||
1051 | /* Don't race with disconnect */ | 1054 | req->rq_connect_cookie = connect_cookie; |
1052 | if (!xprt_connected(xprt)) | 1055 | if (rpc_reply_expected(task) && !READ_ONCE(req->rq_reply_bytes_recvd)) { |
1053 | task->tk_status = -ENOTCONN; | ||
1054 | else { | ||
1055 | /* | 1056 | /* |
1056 | * Sleep on the pending queue since | 1057 | * Sleep on the pending queue if we're expecting a reply. |
1057 | * we're expecting a reply. | 1058 | * The spinlock ensures atomicity between the test of |
1059 | * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on(). | ||
1058 | */ | 1060 | */ |
1059 | if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) | 1061 | spin_lock(&xprt->recv_lock); |
1062 | if (!req->rq_reply_bytes_recvd) { | ||
1060 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | 1063 | rpc_sleep_on(&xprt->pending, task, xprt_timer); |
1061 | req->rq_connect_cookie = xprt->connect_cookie; | 1064 | /* |
1065 | * Send an extra queue wakeup call if the | ||
1066 | * connection was dropped in case the call to | ||
1067 | * rpc_sleep_on() raced. | ||
1068 | */ | ||
1069 | if (!xprt_connected(xprt)) | ||
1070 | xprt_wake_pending_tasks(xprt, -ENOTCONN); | ||
1071 | } | ||
1072 | spin_unlock(&xprt->recv_lock); | ||
1062 | } | 1073 | } |
1063 | spin_unlock_bh(&xprt->transport_lock); | ||
1064 | } | 1074 | } |
1065 | 1075 | ||
1066 | static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) | 1076 | static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index ed34dc0f144c..a3f2ab283aeb 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
@@ -1408,11 +1408,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) | |||
1408 | dprintk("RPC: %s: reply %p completes request %p (xid 0x%08x)\n", | 1408 | dprintk("RPC: %s: reply %p completes request %p (xid 0x%08x)\n", |
1409 | __func__, rep, req, be32_to_cpu(rep->rr_xid)); | 1409 | __func__, rep, req, be32_to_cpu(rep->rr_xid)); |
1410 | 1410 | ||
1411 | if (list_empty(&req->rl_registered) && | 1411 | queue_work_on(req->rl_cpu, rpcrdma_receive_wq, &rep->rr_work); |
1412 | !test_bit(RPCRDMA_REQ_F_TX_RESOURCES, &req->rl_flags)) | ||
1413 | rpcrdma_complete_rqst(rep); | ||
1414 | else | ||
1415 | queue_work(rpcrdma_receive_wq, &rep->rr_work); | ||
1416 | return; | 1412 | return; |
1417 | 1413 | ||
1418 | out_badstatus: | 1414 | out_badstatus: |
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 646c24494ea7..6ee1ad8978f3 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/slab.h> | 52 | #include <linux/slab.h> |
53 | #include <linux/seq_file.h> | 53 | #include <linux/seq_file.h> |
54 | #include <linux/sunrpc/addr.h> | 54 | #include <linux/sunrpc/addr.h> |
55 | #include <linux/smp.h> | ||
55 | 56 | ||
56 | #include "xprt_rdma.h" | 57 | #include "xprt_rdma.h" |
57 | 58 | ||
@@ -656,6 +657,7 @@ xprt_rdma_allocate(struct rpc_task *task) | |||
656 | task->tk_pid, __func__, rqst->rq_callsize, | 657 | task->tk_pid, __func__, rqst->rq_callsize, |
657 | rqst->rq_rcvsize, req); | 658 | rqst->rq_rcvsize, req); |
658 | 659 | ||
660 | req->rl_cpu = smp_processor_id(); | ||
659 | req->rl_connect_cookie = 0; /* our reserved value */ | 661 | req->rl_connect_cookie = 0; /* our reserved value */ |
660 | rpcrdma_set_xprtdata(rqst, req); | 662 | rpcrdma_set_xprtdata(rqst, req); |
661 | rqst->rq_buffer = req->rl_sendbuf->rg_base; | 663 | rqst->rq_buffer = req->rl_sendbuf->rg_base; |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 710b3f77db82..8607c029c0dd 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -83,7 +83,7 @@ rpcrdma_alloc_wq(void) | |||
83 | struct workqueue_struct *recv_wq; | 83 | struct workqueue_struct *recv_wq; |
84 | 84 | ||
85 | recv_wq = alloc_workqueue("xprtrdma_receive", | 85 | recv_wq = alloc_workqueue("xprtrdma_receive", |
86 | WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_HIGHPRI, | 86 | WQ_MEM_RECLAIM | WQ_HIGHPRI, |
87 | 0); | 87 | 0); |
88 | if (!recv_wq) | 88 | if (!recv_wq) |
89 | return -ENOMEM; | 89 | return -ENOMEM; |
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index 51686d9eac5f..1342f743f1c4 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h | |||
@@ -342,6 +342,7 @@ enum { | |||
342 | struct rpcrdma_buffer; | 342 | struct rpcrdma_buffer; |
343 | struct rpcrdma_req { | 343 | struct rpcrdma_req { |
344 | struct list_head rl_list; | 344 | struct list_head rl_list; |
345 | int rl_cpu; | ||
345 | unsigned int rl_connect_cookie; | 346 | unsigned int rl_connect_cookie; |
346 | struct rpcrdma_buffer *rl_buffer; | 347 | struct rpcrdma_buffer *rl_buffer; |
347 | struct rpcrdma_rep *rl_reply; | 348 | struct rpcrdma_rep *rl_reply; |