Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f8f3a1c authored by Trond Myklebust's avatar Trond Myklebust Committed by Greg Kroah-Hartman
Browse files

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: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 96cdf2fd
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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>

@@ -2504,9 +2505,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)
			clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
		}

		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 @@ 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);
}