| From 62d26802bb6094ff8528ddf448705909ca03d402 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 29 Jan 2022 13:32:45 -0500 |
| Subject: NFSv4: Protect the state recovery thread against direct reclaim |
| |
| From: Trond Myklebust <trond.myklebust@hammerspace.com> |
| |
| [ Upstream commit 3e17898aca293a24dae757a440a50aa63ca29671 ] |
| |
| If memory allocation triggers a direct reclaim from the state recovery |
| thread, then we can deadlock. Use memalloc_nofs_save/restore to ensure |
| that doesn't happen. |
| |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/nfs/nfs4state.c | 12 ++++++++++++ |
| 1 file changed, 12 insertions(+) |
| |
| diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c |
| index 499bef9fe118..94f1876afab2 100644 |
| --- a/fs/nfs/nfs4state.c |
| +++ b/fs/nfs/nfs4state.c |
| @@ -49,6 +49,7 @@ |
| #include <linux/workqueue.h> |
| #include <linux/bitops.h> |
| #include <linux/jiffies.h> |
| +#include <linux/sched/mm.h> |
| |
| #include <linux/sunrpc/clnt.h> |
| |
| @@ -2560,9 +2561,17 @@ static void nfs4_layoutreturn_any_run(struct nfs_client *clp) |
| |
| static void nfs4_state_manager(struct nfs_client *clp) |
| { |
| + unsigned int memflags; |
| int status = 0; |
| const char *section = "", *section_sep = ""; |
| |
| + /* |
| + * State recovery can deadlock if the direct reclaim code tries |
| + * start NFS writeback. So ensure memory allocations are all |
| + * GFP_NOFS. |
| + */ |
| + memflags = memalloc_nofs_save(); |
| + |
| /* Ensure exclusive access to NFSv4 state */ |
| do { |
| trace_nfs4_state_mgr(clp); |
| @@ -2657,6 +2666,7 @@ static void nfs4_state_manager(struct nfs_client *clp) |
| clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); |
| } |
| |
| + memalloc_nofs_restore(memflags); |
| nfs4_end_drain_session(clp); |
| nfs4_clear_state_manager_bit(clp); |
| |
| @@ -2674,6 +2684,7 @@ static void nfs4_state_manager(struct nfs_client *clp) |
| return; |
| if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
| return; |
| + memflags = memalloc_nofs_save(); |
| } while (refcount_read(&clp->cl_count) > 1 && !signalled()); |
| goto out_drain; |
| |
| @@ -2686,6 +2697,7 @@ static void nfs4_state_manager(struct nfs_client *clp) |
| clp->cl_hostname, -status); |
| ssleep(1); |
| out_drain: |
| + memalloc_nofs_restore(memflags); |
| nfs4_end_drain_session(clp); |
| nfs4_clear_state_manager_bit(clp); |
| } |
| -- |
| 2.35.1 |
| |