| From ef3e218a3404c1d381c6ae099176098d3c05c4bb Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 7 Mar 2022 10:41:44 +1100 |
| Subject: SUNRPC/call_alloc: async tasks mustn't block waiting for memory |
| |
| From: NeilBrown <neilb@suse.de> |
| |
| [ Upstream commit c487216bec83b0c5a8803e5c61433d33ad7b104d ] |
| |
| When memory is short, new worker threads cannot be created and we depend |
| on the minimum one rpciod thread to be able to handle everything. |
| So it must not block waiting for memory. |
| |
| mempools are particularly a problem as memory can only be released back |
| to the mempool by an async rpc task running. If all available |
| workqueue threads are waiting on the mempool, no thread is available to |
| return anything. |
| |
| rpc_malloc() can block, and this might cause deadlocks. |
| So check RPC_IS_ASYNC(), rather than RPC_IS_SWAPPER() to determine if |
| blocking is acceptable. |
| |
| Signed-off-by: NeilBrown <neilb@suse.de> |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/sunrpc/sched.c | 4 +++- |
| net/sunrpc/xprtrdma/transport.c | 4 +++- |
| 2 files changed, 6 insertions(+), 2 deletions(-) |
| |
| diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c |
| index e339f8da1b0a..e36ae4d4b540 100644 |
| --- a/net/sunrpc/sched.c |
| +++ b/net/sunrpc/sched.c |
| @@ -893,8 +893,10 @@ int rpc_malloc(struct rpc_task *task) |
| struct rpc_buffer *buf; |
| gfp_t gfp = GFP_NOIO | __GFP_NOWARN; |
| |
| + if (RPC_IS_ASYNC(task)) |
| + gfp = GFP_NOWAIT | __GFP_NOWARN; |
| if (RPC_IS_SWAPPER(task)) |
| - gfp = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN; |
| + gfp |= __GFP_MEMALLOC; |
| |
| size += sizeof(struct rpc_buffer); |
| if (size <= RPC_BUFFER_MAXSIZE) |
| diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c |
| index fdd14908eacb..e87a79be7ef0 100644 |
| --- a/net/sunrpc/xprtrdma/transport.c |
| +++ b/net/sunrpc/xprtrdma/transport.c |
| @@ -665,8 +665,10 @@ xprt_rdma_allocate(struct rpc_task *task) |
| gfp_t flags; |
| |
| flags = RPCRDMA_DEF_GFP; |
| + if (RPC_IS_ASYNC(task)) |
| + flags = GFP_NOWAIT | __GFP_NOWARN; |
| if (RPC_IS_SWAPPER(task)) |
| - flags = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN; |
| + flags |= __GFP_MEMALLOC; |
| |
| if (!rpcrdma_get_sendbuf(r_xprt, req, rqst->rq_callsize, flags)) |
| goto out_fail; |
| -- |
| 2.35.1 |
| |