summaryrefslogtreecommitdiff
path: root/kernel/workqueue.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-31 14:38:40 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-31 14:38:40 -0700
commitabdf623ddb75b24659018d3952d8f61937306ae5 (patch)
treeb8a9cf22a71ed06e06de944ee4f91c0ad0086259 /kernel/workqueue.c
parentc3b510de420d70def08190083d388e0873c1aa84 (diff)
parent93e257938aa67a6c957217db94091d9d9e5d403f (diff)
downloadlinux-next-abdf623ddb75b24659018d3952d8f61937306ae5.tar.gz
linux-next-abdf623ddb75b24659018d3952d8f61937306ae5.zip
Merge tag 'wq-for-7.3-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue fixes from Tejun Heo: - An unbound worker pool could be freed while still reachable through the pending-activation list, leading to a use-after-free. Unlink before dropping the reference - On PREEMPT_RT, the BH workqueue kick raised softirqs from preemptible context, tripping a lockdep assertion and possibly losing concurrently raised softirq bits - Draining BH work off a dead CPU nests two pools' callback locks, which lockdep misreported as recursive locking. The nesting cannot deadlock. Annotate it - Reject watchdog thresholds that overflow the conversion to jiffies - Make the drgn workqueue dump script work again on kernels and vmcores from before the workqueue attrs field rename * tag 'wq-for-7.3-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: tools/workqueue/wq_dump.py: Support backward compatibility for wq->attrs rename workqueue: reject watchdog thresholds that overflow jiffies workqueue: Fix unbound pool lifetime for pending pwqs workqueue: Use raise_softirq() to trigger softirq in irq_work handler workqueue: Annotate cb_lock nesting when draining a dead BH pool
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r--kernel/workqueue.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 3c034cbc5bb3..1ae3732a2c51 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -3197,7 +3197,16 @@ restart:
#ifdef CONFIG_PREEMPT_RT
static void worker_lock_callback(struct worker_pool *pool)
{
- spin_lock(&pool->cb_lock);
+ /*
+ * SINGLE_DEPTH_NESTING is for a dead pool's bh_worker() running from
+ * drain_dead_softirq_workfn() inside a live pool's bh_worker(). The
+ * unlocked read is stable: the flag is only set while @pool's CPU is
+ * dead, inside a serialized hotplug operation. data_race() as the value
+ * only affects the lockdep annotation and the read can be elided when
+ * lockdep is disabled.
+ */
+ spin_lock_nested(&pool->cb_lock,
+ data_race(pool->flags) & POOL_BH_DRAINING ? SINGLE_DEPTH_NESTING : 0);
}
static void worker_unlock_callback(struct worker_pool *pool)
@@ -5285,12 +5294,6 @@ static void pwq_release_workfn(struct kthread_work *work)
mutex_unlock(&wq->mutex);
}
- if (!is_percpu_pool(pool)) {
- mutex_lock(&wq_pool_mutex);
- put_unbound_pool(pool);
- mutex_unlock(&wq_pool_mutex);
- }
-
if (!list_empty(&pwq->pending_node)) {
struct wq_node_nr_active *nna =
wq_node_nr_active(pwq->wq, pwq->pool->node);
@@ -5300,6 +5303,12 @@ static void pwq_release_workfn(struct kthread_work *work)
raw_spin_unlock_irq(&nna->lock);
}
+ if (!is_percpu_pool(pool)) {
+ mutex_lock(&wq_pool_mutex);
+ put_unbound_pool(pool);
+ mutex_unlock(&wq_pool_mutex);
+ }
+
kfree_rcu(pwq, rcu);
/*
@@ -8050,6 +8059,9 @@ static int wq_watchdog_param_set_thresh(const char *val,
if (ret)
return ret;
+ if (thresh > MAX_JIFFY_OFFSET / HZ)
+ return -ERANGE;
+
if (system_percpu_wq)
wq_watchdog_set_thresh(thresh);
else
@@ -8080,12 +8092,12 @@ static inline void wq_watchdog_init(void) { }
static void bh_pool_kick_normal(struct irq_work *irq_work)
{
- raise_softirq_irqoff(TASKLET_SOFTIRQ);
+ raise_softirq(TASKLET_SOFTIRQ);
}
static void bh_pool_kick_highpri(struct irq_work *irq_work)
{
- raise_softirq_irqoff(HI_SOFTIRQ);
+ raise_softirq(HI_SOFTIRQ);
}
static void __init restrict_unbound_cpumask(const char *name, const struct cpumask *mask)