mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
workqueue: Fixes for v7.3-rc1
- 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. -----BEGIN PGP SIGNATURE----- iIQEABYKACwWIQTfIjM1kS57o3GsC/uxYfJx3gVYGQUCapXs/Q4cdGpAa2VybmVs Lm9yZwAKCRCxYfJx3gVYGd75AP9VTI8d7dor4mn82j7J6l8Xcy8U1ePM/K5v1PqU n9lfUwD/aopS+dp/uCuqR6pLBxineFAPxNoEgxxO2bDv9OqhoAY= =fj3U -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
abdf623ddb
|
|
@ -3197,7 +3197,16 @@ __acquires(&pool->lock)
|
|||
#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)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,12 @@ def cpumask_str(cpumask):
|
|||
|
||||
wq_type_len = 9
|
||||
|
||||
def wq_attrs(wq):
|
||||
try:
|
||||
return wq.attrs
|
||||
except AttributeError:
|
||||
return wq.unbound_attrs
|
||||
|
||||
def wq_type_str(wq):
|
||||
if wq.flags & WQ_BH:
|
||||
return f'{"bh":{wq_type_len}}'
|
||||
|
|
@ -85,7 +91,7 @@ def wq_type_str(wq):
|
|||
if wq.flags & WQ_ORDERED:
|
||||
return f'{"ordered":{wq_type_len}}'
|
||||
else:
|
||||
if wq.attrs.affn_strict:
|
||||
if wq_attrs(wq).affn_strict:
|
||||
return f'{"unbound,S":{wq_type_len}}'
|
||||
else:
|
||||
return f'{"unbound":{wq_type_len}}'
|
||||
|
|
@ -206,7 +212,7 @@ for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(
|
|||
|
||||
print(f'{wq.name.string_().decode():{WQ_NAME_LEN}}', end='')
|
||||
if wq.flags & WQ_UNBOUND:
|
||||
print(f' {cpumask_str(wq.attrs.cpumask):{ucpus_len}}', end='')
|
||||
print(f' {cpumask_str(wq_attrs(wq).cpumask):{ucpus_len}}', end='')
|
||||
else:
|
||||
print(f' {"":{ucpus_len}}', end='')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user