]> git.ipfire.org Git - thirdparty/kernel/stable.git/commit
workqueue: Allow cancel_work_sync() and disable_work() from atomic contexts on BH...
authorTejun Heo <tj@kernel.org>
Mon, 25 Mar 2024 17:21:03 +0000 (07:21 -1000)
committerTejun Heo <tj@kernel.org>
Mon, 25 Mar 2024 17:21:03 +0000 (07:21 -1000)
commit134874e2eee9380c2700411d4844cbc29297bc01
treeee79520ba6213eebefac269a1762f49bda1045ca
parent456a78eef2670d0e9521e87f35a056de8fec7fb2
workqueue: Allow cancel_work_sync() and disable_work() from atomic contexts on BH work items

Now that work_grab_pending() can always grab the PENDING bit without
sleeping, the only thing that prevents allowing cancel_work_sync() of a BH
work item from an atomic context is the flushing of the in-flight instance.

When we're flushing a BH work item for cancel_work_sync(), we know that the
work item is not queued and must be executing in a BH context, which means
that it's safe to busy-wait for its completion from a non-hardirq atomic
context.

This patch updates __flush_work() so that it busy-waits when flushing a BH
work item for cancel_work_sync(). might_sleep() is pushed from
start_flush_work() to its callers - when operating on a BH work item,
__cancel_work_sync() now enforces !in_hardirq() instead of might_sleep().

This allows cancel_work_sync() and disable_work() to be called from
non-hardirq atomic contexts on BH work items.

v3: In __flush_work(), test WORK_OFFQ_BH to tell whether a work item being
    canceled can be busy waited instead of making start_flush_work() return
    the pool. (Lai)

v2: Lai pointed out that __flush_work() was accessing pool->flags outside
    the RCU critical section protecting the pool pointer. Fix it by testing
    and remembering the result inside the RCU critical section.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Lai Jiangshan <jiangshanlai@gmail.com>
kernel/workqueue.c