mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 06:57:30 -04:00
driver core: Use mod_delayed_work to prevent lost deferred probe work
The deferred_probe_timeout_work may be permanently and unexpectedly
canceled when deferred_probe_extend_timeout() executes concurrently.
Starting with deferred_probe_timeout_work pending, the problem can
occur after the following sequence:
CPU0 CPU1
deferred_probe_extend_timeout
-> cancel_delayed_work() => true
deferred_probe_extend_timeout
-> cancel_delayed_work()
-> __cancel_work()
-> try_grab_pending()
-> schedule_delayed_work()
-> queue_delayed_work_on()
(Since the pending bit is grabbed,
it just returns without queuing)
-> set_work_pool_and_clear_pending()
(This __cancel_work() returns false and
the work will never be queued again)
The root cause is that the WORK_STRUCT_PENDING_BIT of the work_struct
is set temporarily in __cancel_work() (via try_grab_pending()). This
transient state prevents the work_struct from being successfully queued
by another CPU.
To fix this, replace the original non-atomic cancel and schedule
mechanism with mod_delayed_work(). This ensures the modification is
handled atomically and guarantees that the work is not lost.
Fixes: 2b28a1a84a ("driver core: Extend deferred probe timeout on driver registration")
Signed-off-by: Zhang Yuwei <zhangyuwei20@huawei.com>
Link: https://patch.msgid.link/20260410024448.387231-1-zhangyuwei20@huawei.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
9582485a65
commit
1137838865
@@ -323,12 +323,10 @@ void deferred_probe_extend_timeout(void)
|
||||
* If the work hasn't been queued yet or if the work expired, don't
|
||||
* start a new one.
|
||||
*/
|
||||
if (cancel_delayed_work(&deferred_probe_timeout_work)) {
|
||||
schedule_delayed_work(&deferred_probe_timeout_work,
|
||||
driver_deferred_probe_timeout * HZ);
|
||||
if (mod_delayed_work(system_wq, &deferred_probe_timeout_work,
|
||||
driver_deferred_probe_timeout))
|
||||
pr_debug("Extended deferred probe timeout by %d secs\n",
|
||||
driver_deferred_probe_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user