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: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
9ff01193a2
commit
aeabb3c961
|
@ -41,6 +41,8 @@ enum nfs4_client_state {
|
||||||
NFS4CLNT_MOVED,
|
NFS4CLNT_MOVED,
|
||||||
NFS4CLNT_LEASE_MOVED,
|
NFS4CLNT_LEASE_MOVED,
|
||||||
NFS4CLNT_DELEGATION_EXPIRED,
|
NFS4CLNT_DELEGATION_EXPIRED,
|
||||||
|
NFS4CLNT_RUN_MANAGER,
|
||||||
|
NFS4CLNT_DELEGRETURN_RUNNING,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NFS4_RENEW_TIMEOUT 0x01
|
#define NFS4_RENEW_TIMEOUT 0x01
|
||||||
|
|
|
@ -1210,6 +1210,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
|
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)
|
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
||||||
return;
|
return;
|
||||||
__module_get(THIS_MODULE);
|
__module_get(THIS_MODULE);
|
||||||
|
@ -2503,6 +2504,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
||||||
|
|
||||||
/* Ensure exclusive access to NFSv4 state */
|
/* Ensure exclusive access to NFSv4 state */
|
||||||
do {
|
do {
|
||||||
|
clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
|
||||||
if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
|
if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
|
||||||
section = "purge state";
|
section = "purge state";
|
||||||
status = nfs4_purge_lease(clp);
|
status = nfs4_purge_lease(clp);
|
||||||
|
@ -2593,14 +2595,18 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
||||||
}
|
}
|
||||||
|
|
||||||
nfs4_end_drain_session(clp);
|
nfs4_end_drain_session(clp);
|
||||||
if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
|
nfs4_clear_state_manager_bit(clp);
|
||||||
nfs_client_return_marked_delegations(clp);
|
|
||||||
continue;
|
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);
|
||||||
|
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? */
|
/* 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;
|
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;
|
||||||
|
|
Loading…
Reference in New Issue