Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSv4: Fix a state manager thread deadlock regression

Commit 4dc73c679114 reintroduces the deadlock that was fixed by commit
aeabb3c96186 ("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: 4dc73c679114 ("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>

authored by

Trond Myklebust and committed by
Anna Schumaker
956fd46f ed1cc05a

+29 -13
+3 -1
fs/nfs/nfs4proc.c
··· 10622 10622 */ 10623 10623 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; 10624 10624 10625 - nfs4_schedule_state_manager(clp); 10625 + set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); 10626 + clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state); 10627 + wake_up_var(&clp->cl_state); 10626 10628 } 10627 10629 10628 10630 static const struct inode_operations nfs4_dir_inode_operations = {
+26 -12
fs/nfs/nfs4state.c
··· 1209 1209 { 1210 1210 struct task_struct *task; 1211 1211 char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; 1212 + struct rpc_clnt *clnt = clp->cl_rpcclient; 1213 + bool swapon = false; 1212 1214 1213 - if (clp->cl_rpcclient->cl_shutdown) 1215 + if (clnt->cl_shutdown) 1214 1216 return; 1215 1217 1216 1218 set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); 1217 - if (test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) != 0) { 1218 - wake_up_var(&clp->cl_state); 1219 - return; 1219 + 1220 + if (atomic_read(&clnt->cl_swapper)) { 1221 + swapon = !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, 1222 + &clp->cl_state); 1223 + if (!swapon) { 1224 + wake_up_var(&clp->cl_state); 1225 + return; 1226 + } 1220 1227 } 1221 - set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state); 1228 + 1229 + if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) 1230 + return; 1231 + 1222 1232 __module_get(THIS_MODULE); 1223 1233 refcount_inc(&clp->cl_count); 1224 1234 ··· 1245 1235 __func__, PTR_ERR(task)); 1246 1236 if (!nfs_client_init_is_complete(clp)) 1247 1237 nfs_mark_client_ready(clp, PTR_ERR(task)); 1238 + if (swapon) 1239 + clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state); 1248 1240 nfs4_clear_state_manager_bit(clp); 1249 - clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state); 1250 1241 nfs_put_client(clp); 1251 1242 module_put(THIS_MODULE); 1252 1243 } ··· 2759 2748 2760 2749 allow_signal(SIGKILL); 2761 2750 again: 2762 - set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state); 2763 2751 nfs4_state_manager(clp); 2764 - if (atomic_read(&cl->cl_swapper)) { 2752 + 2753 + if (test_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) && 2754 + !test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state)) { 2765 2755 wait_var_event_interruptible(&clp->cl_state, 2766 2756 test_bit(NFS4CLNT_RUN_MANAGER, 2767 2757 &clp->cl_state)); 2768 - if (atomic_read(&cl->cl_swapper) && 2769 - test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state)) 2758 + if (!atomic_read(&cl->cl_swapper)) 2759 + clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state); 2760 + if (refcount_read(&clp->cl_count) > 1 && !signalled() && 2761 + !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state)) 2770 2762 goto again; 2771 2763 /* Either no longer a swapper, or were signalled */ 2764 + clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state); 2772 2765 } 2773 - clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state); 2774 2766 2775 2767 if (refcount_read(&clp->cl_count) > 1 && !signalled() && 2776 2768 test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) && 2777 - !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state)) 2769 + !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state)) 2778 2770 goto again; 2779 2771 2780 2772 nfs_put_client(clp);