• Tejun Heo's avatar
    workqueue: Allow cancel_work_sync() and disable_work() from atomic contexts on BH work items · 134874e2
    Tejun Heo authored
    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: default avatarTejun Heo <tj@kernel.org>
    Reviewed-by: default avatarLai Jiangshan <jiangshanlai@gmail.com>
    134874e2
workqueue.c 223 KB