Commit c8ed866d authored by Trond Myklebust's avatar Trond Myklebust Committed by sanglipeng
Browse files

NFSv4: Fix a state manager thread deadlock regression

stable inclusion
from stable-v5.10.198
commit 2ad1a1d3d61641a75c44c8008e00720782ab375f
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I987V5

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=2ad1a1d3d61641a75c44c8008e00720782ab375f



--------------------------------

[ Upstream commit 956fd46f ]

Commit 4dc73c67 reintroduces the deadlock that was fixed by commit
aeabb3c9 ("NFSv4: Fix a NFSv4 state manager deadlock") because it
prevents the setup of new threads to handle reboot recovery, while the
older recovery thread is stuck returning delegations.

Fixes: 4dc73c67 ("NFSv4: keep state manager thread active if swap is enabled")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarsanglipeng <sanglipeng1@jd.com>
parent faa513be
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -10408,7 +10408,9 @@ static void nfs4_disable_swap(struct inode *inode)
	 */
	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;

	nfs4_schedule_state_manager(clp);
	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
	clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
	wake_up_var(&clp->cl_state);
}

static const struct inode_operations nfs4_dir_inode_operations = {
+25 −11
Original line number Diff line number Diff line
@@ -1212,13 +1212,23 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
{
	struct task_struct *task;
	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
	struct rpc_clnt *clnt = clp->cl_rpcclient;
	bool swapon = false;

	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
	if (test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) != 0) {

	if (atomic_read(&clnt->cl_swapper)) {
		swapon = !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE,
					   &clp->cl_state);
		if (!swapon) {
			wake_up_var(&clp->cl_state);
			return;
		}
	set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
	}

	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;

	__module_get(THIS_MODULE);
	refcount_inc(&clp->cl_count);

@@ -1235,8 +1245,9 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
			__func__, PTR_ERR(task));
		if (!nfs_client_init_is_complete(clp))
			nfs_mark_client_ready(clp, PTR_ERR(task));
		nfs4_clear_state_manager_bit(clp);
		if (swapon)
			clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
		nfs4_clear_state_manager_bit(clp);
		nfs_put_client(clp);
		module_put(THIS_MODULE);
	}
@@ -2717,22 +2728,25 @@ static int nfs4_run_state_manager(void *ptr)

	allow_signal(SIGKILL);
again:
	set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
	nfs4_state_manager(clp);
	if (atomic_read(&cl->cl_swapper)) {

	if (test_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) &&
	    !test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state)) {
		wait_var_event_interruptible(&clp->cl_state,
					     test_bit(NFS4CLNT_RUN_MANAGER,
						      &clp->cl_state));
		if (atomic_read(&cl->cl_swapper) &&
		    test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
		if (!atomic_read(&cl->cl_swapper))
			clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
		if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
		    !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state))
			goto again;
		/* Either no longer a swapper, or were signalled */
	}
		clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
	}

	if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
	    test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) &&
	    !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state))
	    !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state))
		goto again;

	nfs_put_client(clp);