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

Configure Feed

Select the types of activity you want to include in your feed.

afs: Fix hang on rmmod due to outstanding timer

The fileserver probe timer, net->fs_probe_timer, isn't cancelled when
the kafs module is being removed and so the count it holds on
net->servers_outstanding doesn't get dropped..

This causes rmmod to wait forever. The hung process shows a stack like:

afs_purge_servers+0x1b5/0x23c [kafs]
afs_net_exit+0x44/0x6e [kafs]
ops_exit_list+0x72/0x93
unregister_pernet_operations+0x14c/0x1ba
unregister_pernet_subsys+0x1d/0x2a
afs_exit+0x29/0x6f [kafs]
__do_sys_delete_module.isra.0+0x1a2/0x24b
do_syscall_64+0x51/0x95
entry_SYSCALL_64_after_hwframe+0x44/0xa9

Fix this by:

(1) Attempting to cancel the probe timer and, if successful, drop the
count that the timer was holding.

(2) Make the timer function just drop the count and not schedule the
prober if the afs portion of net namespace is being destroyed.

Also, whilst we're at it, make the following changes:

(3) Initialise net->servers_outstanding to 1 and decrement it before
waiting on it so that it doesn't generate wake up events by being
decremented to 0 until we're cleaning up.

(4) Switch the atomic_dec() on ->servers_outstanding for ->fs_timer in
afs_purge_servers() to use the helper function for that.

Fixes: f6cbb368bcb0 ("afs: Actively poll fileservers to maintain NAT or firewall openings")
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Howells and committed by
Linus Torvalds
5481fc6e f8ea5c7b

+16 -2
+10 -1
fs/afs/fs_probe.c
··· 314 314 { 315 315 struct afs_net *net = container_of(timer, struct afs_net, fs_probe_timer); 316 316 317 - if (!queue_work(afs_wq, &net->fs_prober)) 317 + if (!net->live || !queue_work(afs_wq, &net->fs_prober)) 318 318 afs_dec_servers_outstanding(net); 319 319 } 320 320 ··· 457 457 if (timo == 0) 458 458 return -ETIME; 459 459 return -EDESTADDRREQ; 460 + } 461 + 462 + /* 463 + * Clean up the probing when the namespace is killed off. 464 + */ 465 + void afs_fs_probe_cleanup(struct afs_net *net) 466 + { 467 + if (del_timer_sync(&net->fs_probe_timer)) 468 + afs_dec_servers_outstanding(net); 460 469 }
+1
fs/afs/internal.h
··· 1065 1065 extern void afs_probe_fileserver(struct afs_net *, struct afs_server *); 1066 1066 extern void afs_fs_probe_dispatcher(struct work_struct *); 1067 1067 extern int afs_wait_for_one_fs_probe(struct afs_server *, bool); 1068 + extern void afs_fs_probe_cleanup(struct afs_net *); 1068 1069 1069 1070 /* 1070 1071 * inode.c
+3
fs/afs/main.c
··· 100 100 timer_setup(&net->fs_timer, afs_servers_timer, 0); 101 101 INIT_WORK(&net->fs_prober, afs_fs_probe_dispatcher); 102 102 timer_setup(&net->fs_probe_timer, afs_fs_probe_timer, 0); 103 + atomic_set(&net->servers_outstanding, 1); 103 104 104 105 ret = -ENOMEM; 105 106 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); ··· 131 130 132 131 error_open_socket: 133 132 net->live = false; 133 + afs_fs_probe_cleanup(net); 134 134 afs_cell_purge(net); 135 135 afs_purge_servers(net); 136 136 error_cell_init: ··· 152 150 struct afs_net *net = afs_net(net_ns); 153 151 154 152 net->live = false; 153 + afs_fs_probe_cleanup(net); 155 154 afs_cell_purge(net); 156 155 afs_purge_servers(net); 157 156 afs_close_socket(net);
+2 -1
fs/afs/server.c
··· 605 605 _enter(""); 606 606 607 607 if (del_timer_sync(&net->fs_timer)) 608 - atomic_dec(&net->servers_outstanding); 608 + afs_dec_servers_outstanding(net); 609 609 610 610 afs_queue_server_manager(net); 611 611 612 612 _debug("wait"); 613 + atomic_dec(&net->servers_outstanding); 613 614 wait_var_event(&net->servers_outstanding, 614 615 !atomic_read(&net->servers_outstanding)); 615 616 _leave("");