| From 52663508f4b611eff5b1da10eced77a96f7e7b77 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 7 Mar 2022 10:41:44 +1100 |
| Subject: SUNRPC/xprt: async tasks mustn't block waiting for memory |
| |
| From: NeilBrown <neilb@suse.de> |
| |
| [ Upstream commit a721035477fb5fb8abc738fbe410b07c12af3dc5 ] |
| |
| 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. |
| |
| xprt_dynamic_alloc_slot can block indefinitely. This can tie up all |
| workqueue threads and NFS can deadlock. So when called from a |
| workqueue, set __GFP_NORETRY. |
| |
| The rdma alloc_slot already does not block. However it sets the error |
| to -EAGAIN suggesting this will trigger a sleep. It does not. As we |
| can see in call_reserveresult(), only -ENOMEM causes a sleep. -EAGAIN |
| causes immediate retry. |
| |
| 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/xprt.c | 5 ++++- |
| net/sunrpc/xprtrdma/transport.c | 2 +- |
| 2 files changed, 5 insertions(+), 2 deletions(-) |
| |
| diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c |
| index 396a74974f60..75acde97d748 100644 |
| --- a/net/sunrpc/xprt.c |
| +++ b/net/sunrpc/xprt.c |
| @@ -1690,12 +1690,15 @@ static bool xprt_throttle_congested(struct rpc_xprt *xprt, struct rpc_task *task |
| static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt) |
| { |
| struct rpc_rqst *req = ERR_PTR(-EAGAIN); |
| + gfp_t gfp_mask = GFP_KERNEL; |
| |
| if (xprt->num_reqs >= xprt->max_reqs) |
| goto out; |
| ++xprt->num_reqs; |
| spin_unlock(&xprt->reserve_lock); |
| - req = kzalloc(sizeof(struct rpc_rqst), GFP_NOFS); |
| + if (current->flags & PF_WQ_WORKER) |
| + gfp_mask |= __GFP_NORETRY | __GFP_NOWARN; |
| + req = kzalloc(sizeof(*req), gfp_mask); |
| spin_lock(&xprt->reserve_lock); |
| if (req != NULL) |
| goto out; |
| diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c |
| index 6268af7e0310..256b06a92391 100644 |
| --- a/net/sunrpc/xprtrdma/transport.c |
| +++ b/net/sunrpc/xprtrdma/transport.c |
| @@ -525,7 +525,7 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) |
| return; |
| |
| out_sleep: |
| - task->tk_status = -EAGAIN; |
| + task->tk_status = -ENOMEM; |
| xprt_add_backlog(xprt, task); |
| } |
| |
| -- |
| 2.35.1 |
| |