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

Commit aeabb3c9 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: Fix a NFSv4 state manager deadlock



Fix a deadlock whereby the NFSv4 state manager can get stuck in the
delegation return code, waiting for a layout return to complete in
another thread. If the server reboots before that other thread
completes, then we need to be able to start a second state
manager thread in order to perform recovery.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 9ff01193
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ enum nfs4_client_state {
	NFS4CLNT_MOVED,
	NFS4CLNT_LEASE_MOVED,
	NFS4CLNT_DELEGATION_EXPIRED,
	NFS4CLNT_RUN_MANAGER,
	NFS4CLNT_DELEGRETURN_RUNNING,
};

#define NFS4_RENEW_TIMEOUT		0x01
+11 −5
Original line number Diff line number Diff line
@@ -1210,6 +1210,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
	struct task_struct *task;
	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];

	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;
	__module_get(THIS_MODULE);
@@ -2503,6 +2504,7 @@ static void nfs4_state_manager(struct nfs_client *clp)

	/* Ensure exclusive access to NFSv4 state */
	do {
		clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
			section = "purge state";
			status = nfs4_purge_lease(clp);
@@ -2593,14 +2595,18 @@ static void nfs4_state_manager(struct nfs_client *clp)
		}

		nfs4_end_drain_session(clp);
		nfs4_clear_state_manager_bit(clp);

		if (!test_and_set_bit(NFS4CLNT_DELEGRETURN_RUNNING, &clp->cl_state)) {
			if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
				nfs_client_return_marked_delegations(clp);
			continue;
				set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
			}
			clear_bit(NFS4CLNT_DELEGRETURN_RUNNING, &clp->cl_state);
		}

		nfs4_clear_state_manager_bit(clp);
		/* Did we race with an attempt to give us more work? */
		if (clp->cl_state == 0)
		if (!test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
			return;
		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
			return;