From 8460504bdd9aa5996dfc5dd69cd61582a25139ec Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Wed, 18 Mar 2015 09:32:58 +0800 Subject: [PATCH] tipc: fix a potential deadlock when nametable is purged [ 28.531768] ============================================= [ 28.532322] [ INFO: possible recursive locking detected ] [ 28.532322] 3.19.0+ #194 Not tainted [ 28.532322] --------------------------------------------- [ 28.532322] insmod/583 is trying to acquire lock: [ 28.532322] (&(&nseq->lock)->rlock){+.....}, at: [] tipc_nametbl_remove_publ+0x49/0x2e0 [tipc] [ 28.532322] [ 28.532322] but task is already holding lock: [ 28.532322] (&(&nseq->lock)->rlock){+.....}, at: [] tipc_nametbl_stop+0xfc/0x1f0 [tipc] [ 28.532322] [ 28.532322] other info that might help us debug this: [ 28.532322] Possible unsafe locking scenario: [ 28.532322] [ 28.532322] CPU0 [ 28.532322] ---- [ 28.532322] lock(&(&nseq->lock)->rlock); [ 28.532322] lock(&(&nseq->lock)->rlock); [ 28.532322] [ 28.532322] *** DEADLOCK *** [ 28.532322] [ 28.532322] May be due to missing lock nesting notation [ 28.532322] [ 28.532322] 3 locks held by insmod/583: [ 28.532322] #0: (net_mutex){+.+.+.}, at: [] register_pernet_subsys+0x1f/0x50 [ 28.532322] #1: (&(&tn->nametbl_lock)->rlock){+.....}, at: [] tipc_nametbl_stop+0xb1/0x1f0 [tipc] [ 28.532322] #2: (&(&nseq->lock)->rlock){+.....}, at: [] tipc_nametbl_stop+0xfc/0x1f0 [tipc] [ 28.532322] [ 28.532322] stack backtrace: [ 28.532322] CPU: 1 PID: 583 Comm: insmod Not tainted 3.19.0+ #194 [ 28.532322] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 28.532322] ffffffff82394460 ffff8800144cb928 ffffffff81792f3e 0000000000000007 [ 28.532322] ffffffff82394460 ffff8800144cba28 ffffffff810a8080 ffff8800144cb998 [ 28.532322] ffffffff810a4df3 ffff880013e9cb10 ffffffff82b0d330 ffff880013e9cb38 [ 28.532322] Call Trace: [ 28.532322] [] dump_stack+0x4c/0x65 [ 28.532322] [] __lock_acquire+0x740/0x1ca0 [ 28.532322] [] ? __bfs+0x23/0x270 [ 28.532322] [] ? check_irq_usage+0x96/0xe0 [ 28.532322] [] ? __lock_acquire+0x1133/0x1ca0 [ 28.532322] [] ? tipc_nametbl_remove_publ+0x49/0x2e0 [tipc] [ 28.532322] [] lock_acquire+0x9c/0x140 [ 28.532322] [] ? tipc_nametbl_remove_publ+0x49/0x2e0 [tipc] [ 28.532322] [] _raw_spin_lock_bh+0x3f/0x50 [ 28.532322] [] ? tipc_nametbl_remove_publ+0x49/0x2e0 [tipc] [ 28.532322] [] tipc_nametbl_remove_publ+0x49/0x2e0 [tipc] [ 28.532322] [] tipc_nametbl_stop+0x13e/0x1f0 [tipc] [ 28.532322] [] ? tipc_nametbl_stop+0x5/0x1f0 [tipc] [ 28.532322] [] tipc_init_net+0x13b/0x150 [tipc] [ 28.532322] [] ? tipc_init_net+0x5/0x150 [tipc] [ 28.532322] [] ops_init+0x4e/0x150 [ 28.532322] [] ? trace_hardirqs_on+0xd/0x10 [ 28.532322] [] register_pernet_operations+0xf3/0x190 [ 28.532322] [] register_pernet_subsys+0x2e/0x50 [ 28.532322] [] tipc_init+0x6a/0x1000 [tipc] [ 28.532322] [] ? 0xffffffffa0024000 [ 28.532322] [] do_one_initcall+0x89/0x1c0 [ 28.532322] [] ? kmem_cache_alloc_trace+0x50/0x1b0 [ 28.532322] [] ? do_init_module+0x2b/0x200 [ 28.532322] [] do_init_module+0x64/0x200 [ 28.532322] [] load_module+0x12f3/0x18e0 [ 28.532322] [] ? show_initstate+0x50/0x50 [ 28.532322] [] SyS_init_module+0xd9/0x110 [ 28.532322] [] sysenter_dispatch+0x7/0x1f Before tipc_purge_publications() calls tipc_nametbl_remove_publ() to remove a publication with a name sequence, the name sequence's lock is held. However, when tipc_nametbl_remove_publ() calling tipc_nameseq_remove_publ() to remove the publication, it first tries to query name sequence instance with the publication, and then holds the lock of the found name sequence. But as the lock may be already taken in tipc_purge_publications(), deadlock happens like above scenario demonstrated. As tipc_nameseq_remove_publ() doesn't grab name sequence's lock, the deadlock can be avoided if it's directly invoked by tipc_purge_publications(). Fixes: 97ede29e80ee ("tipc: convert name table read-write lock to RCU") Signed-off-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/name_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 105ba7adf06f..ab0ac62a1287 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -811,8 +811,8 @@ static void tipc_purge_publications(struct net *net, struct name_seq *seq) sseq = seq->sseqs; info = sseq->info; list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { - tipc_nametbl_remove_publ(net, publ->type, publ->lower, - publ->node, publ->ref, publ->key); + tipc_nameseq_remove_publ(net, seq, publ->lower, publ->node, + publ->ref, publ->key); kfree_rcu(publ, rcu); } hlist_del_init_rcu(&seq->ns_list);