Skip to content

Commit

Permalink
NFSv4: Fix a state manager thread deadlock regression
Browse files Browse the repository at this point in the history
[ Upstream commit 956fd46 ]

Commit 4dc73c6 reintroduces the deadlock that was fixed by commit
aeabb3c ("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: 4dc73c6 ("NFSv4: keep state manager thread active if swap is enabled")
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Trond Myklebust authored and gregkh committed Oct 10, 2023
1 parent 80ba4fd commit 89f2ace
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
4 changes: 3 additions & 1 deletion fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -10629,7 +10629,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 = {
Expand Down
36 changes: 25 additions & 11 deletions fs/nfs/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -1209,13 +1209,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) {
wake_up_var(&clp->cl_state);
return;

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

Expand All @@ -1232,8 +1242,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));
if (swapon)
clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
nfs4_clear_state_manager_bit(clp);
clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
nfs_put_client(clp);
module_put(THIS_MODULE);
}
Expand Down Expand Up @@ -2737,22 +2748,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);
}
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);
Expand Down

0 comments on commit 89f2ace

Please sign in to comment.