From: Li RongQing Date: Fri, 20 Jun 2014 09:32:36 +0000 (+0800) Subject: cxgb4: Not need to hold the adap_rcu_lock lock when read adap_rcu_list X-Git-Tag: Ubuntu-5.2.0-15.16~13272^2~9 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=ee9a33b2631edb50e3cd2937af7c0f9add5d2e2c;p=mirror_ubuntu-eoan-kernel.git cxgb4: Not need to hold the adap_rcu_lock lock when read adap_rcu_list cxgb4_netdev maybe lead to dead lock, since it uses a spin lock, and be called in both thread and softirq context, but not disable BH, the lockdep report is below; In fact, cxgb4_netdev only reads adap_rcu_list with RCU protection, so not need to hold spin lock again. ================================= [ INFO: inconsistent lock state ] 3.14.7+ #24 Tainted: G C O --------------------------------- inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. radvd/3794 [HC0[0]:SC1[1]:HE1:SE0] takes: (adap_rcu_lock){+.?...}, at: [] clip_add+0x2c/0x116 [cxgb4] {SOFTIRQ-ON-W} state was registered at: [] __lock_acquire+0x34a/0xe48 [] lock_acquire+0x82/0x9d [] _raw_spin_lock+0x34/0x43 [] clip_add+0x2c/0x116 [cxgb4] [] cxgb4_inet6addr_handler+0x117/0x12c [cxgb4] [] notifier_call_chain+0x32/0x5c [] __atomic_notifier_call_chain+0x44/0x6e [] atomic_notifier_call_chain+0xf/0x11 [] inet6addr_notifier_call_chain+0x16/0x18 [] ipv6_add_addr+0x404/0x46e [ipv6] [] addrconf_add_linklocal+0x5f/0x95 [ipv6] [] addrconf_notify+0x632/0x841 [ipv6] [] notifier_call_chain+0x32/0x5c [] __raw_notifier_call_chain+0x9/0xb [] raw_notifier_call_chain+0xf/0x11 [] call_netdevice_notifiers_info+0x4e/0x56 [] call_netdevice_notifiers+0x11/0x13 [] netdev_state_change+0x1f/0x38 [] linkwatch_do_dev+0x3b/0x49 [] __linkwatch_run_queue+0x10b/0x144 [] linkwatch_event+0x20/0x27 [] process_one_work+0x1cb/0x2ee [] worker_thread+0x12e/0x1fc [] kthread+0xc4/0xcc [] ret_from_fork+0x7c/0xb0 irq event stamp: 3388 hardirqs last enabled at (3388): [] __local_bh_enable_ip+0xaa/0xd9 hardirqs last disabled at (3387): [] __local_bh_enable_ip+0x52/0xd9 softirqs last enabled at (3288): [] rcu_read_unlock_bh+0x0/0x2f [ipv6] softirqs last disabled at (3289): [] do_softirq_own_stack+0x1c/0x30 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(adap_rcu_lock); lock(adap_rcu_lock); *** DEADLOCK *** 5 locks held by radvd/3794: #0: (sk_lock-AF_INET6){+.+.+.}, at: [] rawv6_sendmsg+0x74b/0xa4d [ipv6] #1: (rcu_read_lock){.+.+..}, at: [] rcu_lock_acquire+0x0/0x29 #2: (rcu_read_lock){.+.+..}, at: [] rcu_lock_acquire.constprop.16+0x0/0x30 [ipv6] #3: (rcu_read_lock){.+.+..}, at: [] rcu_lock_acquire+0x0/0x29 #4: (rcu_read_lock){.+.+..}, at: [] rcu_lock_acquire.constprop.40+0x0/0x30 [cxgb4] stack backtrace: CPU: 7 PID: 3794 Comm: radvd Tainted: G C O 3.14.7+ #24 Hardware name: Supermicro X7DBU/X7DBU, BIOS 6.00 12/03/2007 ffffffff81f15990 ffff88012fdc36a8 ffffffff815d0016 0000000000000006 ffff8800c80dc2a0 ffff88012fdc3708 ffffffff815cc727 0000000000000001 0000000000000001 ffff880100000000 ffffffff81015b02 ffff8800c80dcb58 Call Trace: [] dump_stack+0x4e/0x71 [] print_usage_bug+0x1ec/0x1fd [] ? save_stack_trace+0x27/0x44 [] ? check_usage_backwards+0xa0/0xa0 [] mark_lock+0x11b/0x212 [] __lock_acquire+0x2d4/0xe48 [] ? check_usage_backwards+0xa0/0xa0 [] ? check_usage_forwards+0x4c/0xa6 [] ? __local_bh_enable_ip+0xaf/0xd9 [] lock_acquire+0x82/0x9d [] ? clip_add+0x2c/0x116 [cxgb4] [] ? rcu_read_unlock+0x23/0x23 [cxgb4] [] _raw_spin_lock+0x34/0x43 [] ? clip_add+0x2c/0x116 [cxgb4] [] ? rcu_lock_acquire.constprop.40+0x2e/0x30 [cxgb4] [] ? rcu_read_unlock+0x23/0x23 [cxgb4] [] clip_add+0x2c/0x116 [cxgb4] [] cxgb4_inet6addr_handler+0x117/0x12c [cxgb4] [] ? lock_acquire+0x94/0x9d [] ? raw_notifier_call_chain+0x11/0x11 [] notifier_call_chain+0x32/0x5c [] __atomic_notifier_call_chain+0x44/0x6e [] atomic_notifier_call_chain+0xf/0x11 [] inet6addr_notifier_call_chain+0x16/0x18 [] ipv6_add_addr+0x404/0x46e [ipv6] [] ? trace_hardirqs_on+0xd/0xf [] addrconf_prefix_rcv+0x385/0x6ea [ipv6] [] ndisc_rcv+0x9d3/0xd76 [ipv6] [] icmpv6_rcv+0x592/0x67b [ipv6] [] ? __local_bh_enable_ip+0xaa/0xd9 [] ? __local_bh_enable_ip+0xaa/0xd9 [] ? lock_release+0x14e/0x17b [] ? rcu_read_unlock+0x21/0x23 [ipv6] [] ? rcu_read_unlock+0x23/0x23 [] ip6_input_finish+0x1e4/0x2fc [ipv6] [] ip6_input+0x33/0x38 [ipv6] [] ip6_mc_input+0x147/0x160 [ipv6] [] ip6_rcv_finish+0x7c/0x81 [ipv6] [] ipv6_rcv+0x3a1/0x3e2 [ipv6] [] __netif_receive_skb_core+0x4ab/0x511 [] ? mark_held_locks+0x71/0x99 [] ? process_backlog+0x69/0x15e [] __netif_receive_skb+0x49/0x5b [] process_backlog+0x78/0x15e [] ? net_rx_action+0x1a2/0x1cc [] net_rx_action+0xac/0x1cc [] ? __do_softirq+0xad/0x218 [] __do_softirq+0xf5/0x218 [] do_softirq_own_stack+0x1c/0x30 [] do_softirq+0x38/0x5d [] ? ip6_copy_metadata+0x156/0x156 [ipv6] [] __local_bh_enable_ip+0x9d/0xd9 [] rcu_read_unlock_bh+0x2d/0x2f [ipv6] [] ip6_finish_output2+0x381/0x3d8 [ipv6] [] ip6_finish_output+0x6e/0x73 [ipv6] [] ip6_output+0x7c/0xa8 [ipv6] [] dst_output+0x18/0x1c [] ip6_local_out+0x1c/0x21 [] ip6_push_pending_frames+0x37d/0x427 [ipv6] [] ? skb_orphan+0x39/0x39 [] ? rawv6_sendmsg+0x74b/0xa4d [ipv6] [] rawv6_sendmsg+0x942/0xa4d [ipv6] [] inet_sendmsg+0x3d/0x66 [] __sock_sendmsg_nosec+0x25/0x27 [] sock_sendmsg+0x5a/0x7b [] ? lock_release+0x14e/0x17b [] ? might_fault+0x9e/0xa5 [] ? might_fault+0x55/0xa5 [] ? copy_from_user+0x2a/0x2c [] ___sys_sendmsg+0x226/0x2d9 [] ? __lock_acquire+0x5ee/0xe48 [] ? trace_hardirqs_on_caller+0x145/0x1a1 [] ? slab_free_hook.isra.71+0x50/0x59 [] ? release_pages+0xbc/0x181 [] ? lock_acquire+0x94/0x9d [] ? read_seqcount_begin.constprop.25+0x73/0x90 [] __sys_sendmsg+0x3d/0x5b [] SyS_sendmsg+0xd/0x19 [] system_call_fastpath+0x1a/0x1f Reported-by: Ben Greear Cc: Casey Leedom Cc: Hariprasad Shenai Signed-off-by: Li RongQing Signed-off-by: Eric Dumazet Acked-by: Casey Leedom Signed-off-by: David S. Miller --- diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2f8d6b910383..a83271cf17c3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4057,22 +4057,19 @@ int cxgb4_unregister_uld(enum cxgb4_uld type) EXPORT_SYMBOL(cxgb4_unregister_uld); /* Check if netdev on which event is occured belongs to us or not. Return - * suceess (1) if it belongs otherwise failure (0). + * success (true) if it belongs otherwise failure (false). + * Called with rcu_read_lock() held. */ -static int cxgb4_netdev(struct net_device *netdev) +static bool cxgb4_netdev(const struct net_device *netdev) { struct adapter *adap; int i; - spin_lock(&adap_rcu_lock); list_for_each_entry_rcu(adap, &adap_rcu_list, rcu_node) for (i = 0; i < MAX_NPORTS; i++) - if (adap->port[i] == netdev) { - spin_unlock(&adap_rcu_lock); - return 1; - } - spin_unlock(&adap_rcu_lock); - return 0; + if (adap->port[i] == netdev) + return true; + return false; } static int clip_add(struct net_device *event_dev, struct inet6_ifaddr *ifa, @@ -6396,6 +6393,7 @@ static void remove_one(struct pci_dev *pdev) adapter->flags &= ~DEV_ENABLED; } pci_release_regions(pdev); + synchronize_rcu(); kfree(adapter); } else pci_release_regions(pdev);