diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2022-01-29 13:32:45 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-04-15 14:15:03 +0200 |
commit | 2724d7743bb7df345feb7e4f88ecee97f0416d65 (patch) | |
tree | 9852bdb6531ecb04ff67624f3d83f24bd33bf34e | |
parent | 789988e2f2b1d7d1a4fd6f820917016484dbf558 (diff) | |
download | linux-stable-2724d7743bb7df345feb7e4f88ecee97f0416d65.tar.gz linux-stable-2724d7743bb7df345feb7e4f88ecee97f0416d65.tar.bz2 linux-stable-2724d7743bb7df345feb7e4f88ecee97f0416d65.zip |
NFSv4: Protect the state recovery thread against direct reclaim
[ 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>
-rw-r--r-- | fs/nfs/nfs4state.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 9c98547fcefc..30576a10a1f4 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> @@ -2505,9 +2506,17 @@ static int nfs4_bind_conn_to_session(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 { clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); @@ -2600,6 +2609,7 @@ static void nfs4_state_manager(struct nfs_client *clp) goto out_error; } + memalloc_nofs_restore(memflags); nfs4_end_drain_session(clp); nfs4_clear_state_manager_bit(clp); @@ -2616,6 +2626,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; @@ -2627,6 +2638,7 @@ out_error: clp->cl_hostname, -status); ssleep(1); out_drain: + memalloc_nofs_restore(memflags); nfs4_end_drain_session(clp); nfs4_clear_state_manager_bit(clp); } |