[lkml]   [2012]   [Apr]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    Subject[PATCH 2/2] ks8851: Fix mutex deadlock in ks8851_net_stop()
    There is a potential deadlock scenario when the ks8851 driver
    is removed. The interrupt handler schedules a workqueue which
    acquires a mutex that ks8851_net_stop() also acquires before
    flushing the workqueue. Previously lockdep wouldn't be able
    to find this problem but now that it has the support we can
    trigger this lockdep warning by rmmoding the driver after
    an ifconfig up.

    Fix the possible deadlock by disabling the interrupts in
    the chip and then release the lock across the workqueue
    flushing. The mutex is only there to proect the registers
    anyway so this should be ok.

    [ INFO: possible circular locking dependency detected ]
    3.0.21-00021-g8b33780-dirty #2911
    rmmod/125 is trying to acquire lock:
    ((&ks->irq_work)){+.+...}, at: [<c019e0b8>] flush_work+0x0/0xac

    but task is already holding lock:
    (&ks->lock){+.+...}, at: [<bf00b850>] ks8851_net_stop+0x64/0x138 [ks8851]

    which lock already depends on the new lock.

    the existing dependency chain (in reverse order) is:

    -> #1 (&ks->lock){+.+...}:
    [<c01b89c8>] __lock_acquire+0x940/0x9f8
    [<c01b9058>] lock_acquire+0x10c/0x130
    [<c083dbec>] mutex_lock_nested+0x68/0x3dc
    [<bf00bd48>] ks8851_irq_work+0x24/0x46c [ks8851]
    [<c019c580>] process_one_work+0x2d8/0x518
    [<c019cb98>] worker_thread+0x220/0x3a0
    [<c01a2ad4>] kthread+0x88/0x94
    [<c0107008>] kernel_thread_exit+0x0/0x8

    -> #0 ((&ks->irq_work)){+.+...}:
    [<c01b7984>] validate_chain+0x914/0x1018
    [<c01b89c8>] __lock_acquire+0x940/0x9f8
    [<c01b9058>] lock_acquire+0x10c/0x130
    [<c019e104>] flush_work+0x4c/0xac
    [<bf00b858>] ks8851_net_stop+0x6c/0x138 [ks8851]
    [<c06b209c>] __dev_close_many+0x98/0xcc
    [<c06b2174>] dev_close_many+0x68/0xd0
    [<c06b22ec>] rollback_registered_many+0xcc/0x2b8
    [<c06b2554>] rollback_registered+0x28/0x34
    [<c06b25b8>] unregister_netdevice_queue+0x58/0x7c
    [<c06b25f4>] unregister_netdev+0x18/0x20
    [<bf00c1f4>] ks8851_remove+0x64/0xb4 [ks8851]
    [<c049ddf0>] spi_drv_remove+0x18/0x1c
    [<c0468e98>] __device_release_driver+0x7c/0xbc
    [<c0468f64>] driver_detach+0x8c/0xb4
    [<c0467f00>] bus_remove_driver+0xb8/0xe8
    [<c01c1d20>] sys_delete_module+0x1e8/0x27c
    [<c0105ec0>] ret_fast_syscall+0x0/0x3c

    other info that might help us debug this:

    Possible unsafe locking scenario:

    CPU0 CPU1
    ---- ----

    *** DEADLOCK ***

    4 locks held by rmmod/125:
    #0: (&__lockdep_no_validate__){+.+.+.}, at: [<c0468f44>] driver_detach+0x6c/0xb4
    #1: (&__lockdep_no_validate__){+.+.+.}, at: [<c0468f50>] driver_detach+0x78/0xb4
    #2: (rtnl_mutex){+.+.+.}, at: [<c06b25e8>] unregister_netdev+0xc/0x20
    #3: (&ks->lock){+.+...}, at: [<bf00b850>] ks8851_net_stop+0x64/0x138 [ks8851]

    Cc: Ben Dooks <>
    Signed-off-by: Stephen Boyd <>
    drivers/net/ethernet/micrel/ks8851.c | 11 ++++++-----
    1 file changed, 6 insertions(+), 5 deletions(-)

    diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
    index c722aa60..20f50ec 100644
    --- a/drivers/net/ethernet/micrel/ks8851.c
    +++ b/drivers/net/ethernet/micrel/ks8851.c
    @@ -889,16 +889,17 @@ static int ks8851_net_stop(struct net_device *dev)

    + /* turn off the IRQs and ack any outstanding */
    + ks8851_wrreg16(ks, KS_IER, 0x0000);
    + ks8851_wrreg16(ks, KS_ISR, 0xffff);
    + mutex_unlock(&ks->lock);

    /* stop any outstanding work */

    - /* turn off the IRQs and ack any outstanding */
    - ks8851_wrreg16(ks, KS_IER, 0x0000);
    - ks8851_wrreg16(ks, KS_ISR, 0xffff);
    + mutex_lock(&ks->lock);
    /* shutdown RX process */
    ks8851_wrreg16(ks, KS_RXCR1, 0x0000);

    @@ -907,6 +908,7 @@ static int ks8851_net_stop(struct net_device *dev)

    /* set powermode to soft power down to save power */
    ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
    + mutex_unlock(&ks->lock);

    /* ensure any queued tx buffers are dumped */
    while (!skb_queue_empty(&ks->txq)) {
    @@ -918,7 +920,6 @@ static int ks8851_net_stop(struct net_device *dev)

    - mutex_unlock(&ks->lock);
    return 0;

    Sent by an employee of the Qualcomm Innovation Center, Inc.
    The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

     \ /
      Last update: 2012-04-19 05:29    [W:0.026 / U:25.652 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site