summaryrefslogtreecommitdiffstats
path: root/kernel/softirq.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2024-02-27 02:38:55 +0100
committerTejun Heo <tj@kernel.org>2024-02-29 22:51:24 +0100
commit1acd92d95fa24edca8f0292b21870025da93e24f (patch)
tree2b6d2805ff5700650f326e138a62316c532328ce /kernel/softirq.c
parentworkqueue: Introduce from_work() helper for cleaner callback declarations (diff)
downloadlinux-1acd92d95fa24edca8f0292b21870025da93e24f.tar.xz
linux-1acd92d95fa24edca8f0292b21870025da93e24f.zip
workqueue: Drain BH work items on hot-unplugged CPUs
Boqun pointed out that workqueues aren't handling BH work items on offlined CPUs. Unlike tasklet which transfers out the pending tasks from CPUHP_SOFTIRQ_DEAD, BH workqueue would just leave them pending which is problematic. Note that this behavior is specific to BH workqueues as the non-BH per-CPU workers just become unbound when the CPU goes offline. This patch fixes the issue by draining the pending BH work items from an offlined CPU from CPUHP_SOFTIRQ_DEAD. Because work items carry more context, it's not as easy to transfer the pending work items from one pool to another. Instead, run BH work items which execute the offlined pools on an online CPU. Note that this assumes that no further BH work items will be queued on the offlined CPUs. This assumption is shared with tasklet and should be fine for conversions. However, this issue also exists for per-CPU workqueues which will just keep executing work items queued after CPU offline on unbound workers and workqueue should reject per-CPU and BH work items queued on offline CPUs. This will be addressed separately later. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-and-reviewed-by: Boqun Feng <boqun.feng@gmail.com> Link: http://lkml.kernel.org/r/Zdvw0HdSXcU3JZ4g@boqun-archlinux
Diffstat (limited to 'kernel/softirq.c')
-rw-r--r--kernel/softirq.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 547d282548a8..b315b21fb28c 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -932,6 +932,8 @@ static void run_ksoftirqd(unsigned int cpu)
#ifdef CONFIG_HOTPLUG_CPU
static int takeover_tasklets(unsigned int cpu)
{
+ workqueue_softirq_dead(cpu);
+
/* CPU is dead, so no lock needed. */
local_irq_disable();