• Yang Yingliang's avatar
    w1: fix deadloop in __w1_remove_master_device() · 25d56488
    Yang Yingliang authored
    I got a deadloop report while doing device(ds2482) add/remove test:
    
      [  162.241881] w1_master_driver w1_bus_master1: Waiting for w1_bus_master1 to become free: refcnt=1.
      [  163.272251] w1_master_driver w1_bus_master1: Waiting for w1_bus_master1 to become free: refcnt=1.
      [  164.296157] w1_master_driver w1_bus_master1: Waiting for w1_bus_master1 to become free: refcnt=1.
      ...
    
    __w1_remove_master_device() can't return, because the dev->refcnt is not zero.
    
    w1_add_master_device()			|
      w1_alloc_dev()			|
        atomic_set(&dev->refcnt, 2)		|
      kthread_run()				|
    					|__w1_remove_master_device()
    					|  kthread_stop()
      // KTHREAD_SHOULD_STOP is set,	|
      // threadfn(w1_process) won't be	|
      // called.				|
      kthread()				|
    					|  // refcnt will never be 0, it's deadloop.
    					|  while (atomic_read(&dev->refcnt)) {...}
    
    After calling w1_add_master_device(), w1_process() is not really
    invoked, before w1_process() starting, if kthread_stop() is called
    in __w1_remove_master_device(), w1_process() will never be called,
    the refcnt can not be decreased, then it causes deadloop in remove
    function because of non-zero refcnt.
    
    We need to make sure w1_process() is really started, so move the
    set refcnt into w1_process() to fix this problem.
    
    Fixes: 1da177e4 ("Linux-2.6.12-rc2")
    Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
    Link: https://lore.kernel.org/r/20221205080434.3149205-1-yangyingliang@huawei.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    25d56488
w1.c 31.7 KB