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>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
9b9feec97c
commit
4a2544ce24
@@ -49,6 +49,7 @@
|
|||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/sched/mm.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
|
||||||
@@ -2557,9 +2558,17 @@ static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
|
|||||||
|
|
||||||
static void nfs4_state_manager(struct nfs_client *clp)
|
static void nfs4_state_manager(struct nfs_client *clp)
|
||||||
{
|
{
|
||||||
|
unsigned int memflags;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
const char *section = "", *section_sep = "";
|
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 */
|
/* Ensure exclusive access to NFSv4 state */
|
||||||
do {
|
do {
|
||||||
trace_nfs4_state_mgr(clp);
|
trace_nfs4_state_mgr(clp);
|
||||||
@@ -2654,6 +2663,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
|||||||
clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
|
clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memalloc_nofs_restore(memflags);
|
||||||
nfs4_end_drain_session(clp);
|
nfs4_end_drain_session(clp);
|
||||||
nfs4_clear_state_manager_bit(clp);
|
nfs4_clear_state_manager_bit(clp);
|
||||||
|
|
||||||
@@ -2671,6 +2681,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
|||||||
return;
|
return;
|
||||||
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
||||||
return;
|
return;
|
||||||
|
memflags = memalloc_nofs_save();
|
||||||
} while (refcount_read(&clp->cl_count) > 1 && !signalled());
|
} while (refcount_read(&clp->cl_count) > 1 && !signalled());
|
||||||
goto out_drain;
|
goto out_drain;
|
||||||
|
|
||||||
@@ -2683,6 +2694,7 @@ out_error:
|
|||||||
clp->cl_hostname, -status);
|
clp->cl_hostname, -status);
|
||||||
ssleep(1);
|
ssleep(1);
|
||||||
out_drain:
|
out_drain:
|
||||||
|
memalloc_nofs_restore(memflags);
|
||||||
nfs4_end_drain_session(clp);
|
nfs4_end_drain_session(clp);
|
||||||
nfs4_clear_state_manager_bit(clp);
|
nfs4_clear_state_manager_bit(clp);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user