w1: fix deadloop in __w1_remove_master_device()
[ Upstream commit25d5648802
] 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:1da177e4c3
("Linux-2.6.12-rc2") Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Link: https://lore.kernel.org/r/20221205080434.3149205-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
e75485fc58
commit
8bc7d87067
|
@ -1166,6 +1166,8 @@ int w1_process(void *data)
|
|||
/* remainder if it woke up early */
|
||||
unsigned long jremain = 0;
|
||||
|
||||
atomic_inc(&dev->refcnt);
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (!jremain && dev->search_count) {
|
||||
|
|
|
@ -51,10 +51,9 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
|
|||
dev->search_count = w1_search_count;
|
||||
dev->enable_pullup = w1_enable_pullup;
|
||||
|
||||
/* 1 for w1_process to decrement
|
||||
* 1 for __w1_remove_master_device to decrement
|
||||
/* For __w1_remove_master_device to decrement
|
||||
*/
|
||||
atomic_set(&dev->refcnt, 2);
|
||||
atomic_set(&dev->refcnt, 1);
|
||||
|
||||
INIT_LIST_HEAD(&dev->slist);
|
||||
INIT_LIST_HEAD(&dev->async_list);
|
||||
|
|
Loading…
Reference in New Issue