Skip to content

Commit d025fbf

Browse files
committed
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
2 parents f6f3732 + 90d91b0 commit d025fbf

File tree

8 files changed

+50
-19
lines changed

8 files changed

+50
-19
lines changed

fs/nfs/client.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,23 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
291291
const struct sockaddr *sap = data->addr;
292292
struct nfs_net *nn = net_generic(data->net, nfs_net_id);
293293

294+
again:
294295
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
295296
const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
296297
/* Don't match clients that failed to initialise properly */
297298
if (clp->cl_cons_state < 0)
298299
continue;
299300

301+
/* If a client is still initializing then we need to wait */
302+
if (clp->cl_cons_state > NFS_CS_READY) {
303+
refcount_inc(&clp->cl_count);
304+
spin_unlock(&nn->nfs_client_lock);
305+
nfs_wait_client_init_complete(clp);
306+
nfs_put_client(clp);
307+
spin_lock(&nn->nfs_client_lock);
308+
goto again;
309+
}
310+
300311
/* Different NFS versions cannot share the same nfs_client */
301312
if (clp->rpc_ops != data->nfs_mod->rpc_ops)
302313
continue;

fs/nfs/nfs4client.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -404,15 +404,19 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
404404
if (error < 0)
405405
goto error;
406406

407-
if (!nfs4_has_session(clp))
408-
nfs_mark_client_ready(clp, NFS_CS_READY);
409-
410407
error = nfs4_discover_server_trunking(clp, &old);
411408
if (error < 0)
412409
goto error;
413410

414-
if (clp != old)
411+
if (clp != old) {
415412
clp->cl_preserve_clid = true;
413+
/*
414+
* Mark the client as having failed initialization so other
415+
* processes walking the nfs_client_list in nfs_match_client()
416+
* won't try to use it.
417+
*/
418+
nfs_mark_client_ready(clp, -EPERM);
419+
}
416420
nfs_put_client(clp);
417421
clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
418422
return old;
@@ -539,6 +543,9 @@ int nfs40_walk_client_list(struct nfs_client *new,
539543
spin_lock(&nn->nfs_client_lock);
540544
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
541545

546+
if (pos == new)
547+
goto found;
548+
542549
status = nfs4_match_client(pos, new, &prev, nn);
543550
if (status < 0)
544551
goto out_unlock;
@@ -559,6 +566,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
559566
* way that a SETCLIENTID_CONFIRM to pos can succeed is
560567
* if new and pos point to the same server:
561568
*/
569+
found:
562570
refcount_inc(&pos->cl_count);
563571
spin_unlock(&nn->nfs_client_lock);
564572

@@ -572,6 +580,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
572580
case 0:
573581
nfs4_swap_callback_idents(pos, new);
574582
pos->cl_confirm = new->cl_confirm;
583+
nfs_mark_client_ready(pos, NFS_CS_READY);
575584

576585
prev = NULL;
577586
*result = pos;

fs/nfs/write.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,6 +1890,8 @@ int nfs_commit_inode(struct inode *inode, int how)
18901890
if (res)
18911891
error = nfs_generic_commit_list(inode, &head, how, &cinfo);
18921892
nfs_commit_end(cinfo.mds);
1893+
if (res == 0)
1894+
return res;
18931895
if (error < 0)
18941896
goto out_error;
18951897
if (!may_wait)

net/sunrpc/xprt.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ void xprt_transmit(struct rpc_task *task)
10011001
{
10021002
struct rpc_rqst *req = task->tk_rqstp;
10031003
struct rpc_xprt *xprt = req->rq_xprt;
1004+
unsigned int connect_cookie;
10041005
int status, numreqs;
10051006

10061007
dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
@@ -1024,6 +1025,7 @@ void xprt_transmit(struct rpc_task *task)
10241025
} else if (!req->rq_bytes_sent)
10251026
return;
10261027

1028+
connect_cookie = xprt->connect_cookie;
10271029
req->rq_xtime = ktime_get();
10281030
status = xprt->ops->send_request(task);
10291031
trace_xprt_transmit(xprt, req->rq_xid, status);
@@ -1047,20 +1049,28 @@ void xprt_transmit(struct rpc_task *task)
10471049
xprt->stat.bklog_u += xprt->backlog.qlen;
10481050
xprt->stat.sending_u += xprt->sending.qlen;
10491051
xprt->stat.pending_u += xprt->pending.qlen;
1052+
spin_unlock_bh(&xprt->transport_lock);
10501053

1051-
/* Don't race with disconnect */
1052-
if (!xprt_connected(xprt))
1053-
task->tk_status = -ENOTCONN;
1054-
else {
1054+
req->rq_connect_cookie = connect_cookie;
1055+
if (rpc_reply_expected(task) && !READ_ONCE(req->rq_reply_bytes_recvd)) {
10551056
/*
1056-
* Sleep on the pending queue since
1057-
* we're expecting a reply.
1057+
* Sleep on the pending queue if 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().
10581060
*/
1059-
if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task))
1061+
spin_lock(&xprt->recv_lock);
1062+
if (!req->rq_reply_bytes_recvd) {
10601063
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);
10621073
}
1063-
spin_unlock_bh(&xprt->transport_lock);
10641074
}
10651075

10661076
static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task)

net/sunrpc/xprtrdma/rpc_rdma.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,11 +1408,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
14081408
dprintk("RPC: %s: reply %p completes request %p (xid 0x%08x)\n",
14091409
__func__, rep, req, be32_to_cpu(rep->rr_xid));
14101410

1411-
if (list_empty(&req->rl_registered) &&
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);
1411+
queue_work_on(req->rl_cpu, rpcrdma_receive_wq, &rep->rr_work);
14161412
return;
14171413

14181414
out_badstatus:

net/sunrpc/xprtrdma/transport.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <linux/slab.h>
5353
#include <linux/seq_file.h>
5454
#include <linux/sunrpc/addr.h>
55+
#include <linux/smp.h>
5556

5657
#include "xprt_rdma.h"
5758

@@ -656,6 +657,7 @@ xprt_rdma_allocate(struct rpc_task *task)
656657
task->tk_pid, __func__, rqst->rq_callsize,
657658
rqst->rq_rcvsize, req);
658659

660+
req->rl_cpu = smp_processor_id();
659661
req->rl_connect_cookie = 0; /* our reserved value */
660662
rpcrdma_set_xprtdata(rqst, req);
661663
rqst->rq_buffer = req->rl_sendbuf->rg_base;

net/sunrpc/xprtrdma/verbs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ rpcrdma_alloc_wq(void)
8383
struct workqueue_struct *recv_wq;
8484

8585
recv_wq = alloc_workqueue("xprtrdma_receive",
86-
WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_HIGHPRI,
86+
WQ_MEM_RECLAIM | WQ_HIGHPRI,
8787
0);
8888
if (!recv_wq)
8989
return -ENOMEM;

net/sunrpc/xprtrdma/xprt_rdma.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ enum {
342342
struct rpcrdma_buffer;
343343
struct rpcrdma_req {
344344
struct list_head rl_list;
345+
int rl_cpu;
345346
unsigned int rl_connect_cookie;
346347
struct rpcrdma_buffer *rl_buffer;
347348
struct rpcrdma_rep *rl_reply;

0 commit comments

Comments
 (0)