Since flush operation synchronously waits for completion, flushing system-wide WQs (e.g. system_wq) might introduce possibility of deadlock due to unexpected locking dependency. Tejun Heo commented at [1] that it makes no sense at all to call flush_workqueue() on the shared WQs as the caller has no idea what it's gonna end up waiting for. Although there is flush_scheduled_work() which flushes system_wq WQ with "Think twice before calling this function! It's very easy to get into trouble if you don't take great care." warning message, syzbot found a circular locking dependency caused by flushing system_wq WQ [2]. Therefore, let's change the direction to that developers had better use their local WQs if flush_scheduled_work()/flush_workqueue(system_*_wq) is inevitable. Steps for converting system-wide WQs into local WQs are explained at [3], and a conversion to stop flushing system-wide WQs is in progress. Now we want some mechanism for preventing developers who are not aware of this conversion from again start flushing system-wide WQs. Since I found that WARN_ON() is complete but awkward approach for teaching developers about this problem, let's use __compiletime_warning() for incomplete but handy approach. For completeness, we will also insert WARN_ON() into __flush_workqueue() after all in-tree users stopped calling flush_scheduled_work().
Showing the changes to kernel/workqueue.c (1 of 2 files). Show all
Unified · Split
| @@ -2788,13 +2788,13 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq, · 2787 unmodified lines | ||
| 2788 | 2788 | } |
| 2789 | 2789 | |
| 2790 | 2790 | /** |
| 2791 | − * flush_workqueue - ensure that any scheduled work has run to completion. | |
| 2791 | + * __flush_workqueue - ensure that any scheduled work has run to completion. | |
| 2792 | 2792 | * @wq: workqueue to flush |
| 2793 | 2793 | * |
| 2794 | 2794 | * This function sleeps until all work items which were queued on entry |
| 2795 | 2795 | * have finished execution, but it is not livelocked by new incoming ones. |
| 2796 | 2796 | */ |
| 2797 | −void flush_workqueue(struct workqueue_struct *wq) | |
| 2797 | +void __flush_workqueue(struct workqueue_struct *wq) | |
| 2798 | 2798 | { |
| 2799 | 2799 | struct wq_flusher this_flusher = { |
| 2800 | 2800 | .list = LIST_HEAD_INIT(this_flusher.list), |
| @@ -2943,7 +2943,7 @@ void flush_workqueue(struct workqueue_struct *wq) · 142 unmodified lines | ||
| 2943 | 2943 | out_unlock: |
| 2944 | 2944 | mutex_unlock(&wq->mutex); |
| 2945 | 2945 | } |
| 2946 | −EXPORT_SYMBOL(flush_workqueue); | |
| 2946 | +EXPORT_SYMBOL(__flush_workqueue); | |
| 2947 | 2947 | |
| 2948 | 2948 | /** |
| 2949 | 2949 | * drain_workqueue - drain a workqueue |
| @@ -2971,7 +2971,7 @@ void drain_workqueue(struct workqueue_struct *wq) · 21 unmodified lines | ||
| 2971 | 2971 | wq->flags |= __WQ_DRAINING; |
| 2972 | 2972 | mutex_unlock(&wq->mutex); |
| 2973 | 2973 | reflush: |
| 2974 | − flush_workqueue(wq); | |
| 2974 | + __flush_workqueue(wq); | |
| 2975 | 2975 | |
| 2976 | 2976 | mutex_lock(&wq->mutex); |
| 2977 | 2977 | |
| @@ -6111,3 +6111,11 @@ void __init workqueue_init(void) · 3133 unmodified lines | ||
| 6111 | 6111 | wq_online = true; |
| 6112 | 6112 | wq_watchdog_init(); |
| 6113 | 6113 | } |
| 6114 | + | |
| 6115 | +/* | |
| 6116 | + * Despite the naming, this is a no-op function which is here only for avoiding | |
| 6117 | + * link error. Since compile-time warning may fail to catch, we will need to | |
| 6118 | + * emit run-time warning from __flush_workqueue(). | |
| 6119 | + */ | |
| 6120 | +void __warn_flushing_systemwide_wq(void) { } | |
| 6121 | +EXPORT_SYMBOL(__warn_flushing_systemwide_wq); | |