Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

workqueue: Add system_dfl_long_wq for long unbound works

Currently there are users of queue_delayed_work() who specify
system_long_wq, the per-cpu workqueue. This workqueue should
be used for long per-cpu works, but queue_delayed_work()
queue the work using:

queue_delayed_work_on(WORK_CPU_UNBOUND, ...);

This would end up calling __queue_delayed_work() that does:

if (housekeeping_enabled(HK_TYPE_TIMER)) {
// [....]
} else {
if (likely(cpu == WORK_CPU_UNBOUND))
add_timer_global(timer);
else
add_timer_on(timer, cpu);
}

So when cpu == WORK_CPU_UNBOUND the timer is global and is
not using a specific CPU. Later, when __queue_work() is called:

if (req_cpu == WORK_CPU_UNBOUND) {
if (wq->flags & WQ_UNBOUND)
cpu = wq_select_unbound_cpu(raw_smp_processor_id());
else
cpu = raw_smp_processor_id();
}

Because the wq is not unbound, it takes the CPU where the timer
fired and enqueue the work on that CPU.
The consequence of all of this is that the work can run anywhere,
depending on where the timer fired.

Introduce system_dfl_long_wq in order to change, in a future step,
users that are still calling:

queue_delayed_work(system_long_wq, ...);

with the new system_dfl_long_wq instead, so that the work may
benefit from scheduler task placement.

Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Marco Crivellari and committed by
Tejun Heo
c116737e 25e1a46c

+10 -1
+6
include/linux/workqueue.h
··· 440 440 * system_long_wq is similar to system_percpu_wq but may host long running 441 441 * works. Queue flushing might take relatively long. 442 442 * 443 + * system_dfl_long_wq is similar to system_dfl_wq but it may host long running 444 + * works. 445 + * 443 446 * system_dfl_wq is unbound workqueue. Workers are not bound to 444 447 * any specific CPU, not concurrency managed, and all queued works are 445 448 * executed immediately as long as max_active limit is not reached and ··· 471 468 extern struct workqueue_struct *system_freezable_power_efficient_wq; 472 469 extern struct workqueue_struct *system_bh_wq; 473 470 extern struct workqueue_struct *system_bh_highpri_wq; 471 + extern struct workqueue_struct *system_dfl_long_wq; 474 472 475 473 void workqueue_softirq_action(bool highpri); 476 474 void workqueue_softirq_dead(unsigned int cpu); ··· 787 783 _wq == system_highpri_wq) || \ 788 784 (__builtin_constant_p(_wq == system_long_wq) && \ 789 785 _wq == system_long_wq) || \ 786 + (__builtin_constant_p(_wq == system_dfl_long_wq) && \ 787 + _wq == system_dfl_long_wq) || \ 790 788 (__builtin_constant_p(_wq == system_dfl_wq) && \ 791 789 _wq == system_dfl_wq) || \ 792 790 (__builtin_constant_p(_wq == system_freezable_wq) && \
+4 -1
kernel/workqueue.c
··· 530 530 EXPORT_SYMBOL_GPL(system_bh_wq); 531 531 struct workqueue_struct *system_bh_highpri_wq; 532 532 EXPORT_SYMBOL_GPL(system_bh_highpri_wq); 533 + struct workqueue_struct *system_dfl_long_wq __ro_after_init; 534 + EXPORT_SYMBOL_GPL(system_dfl_long_wq); 533 535 534 536 static int worker_thread(void *__worker); 535 537 static void workqueue_sysfs_unregister(struct workqueue_struct *wq); ··· 7956 7954 system_bh_wq = alloc_workqueue("events_bh", WQ_BH | WQ_PERCPU, 0); 7957 7955 system_bh_highpri_wq = alloc_workqueue("events_bh_highpri", 7958 7956 WQ_BH | WQ_HIGHPRI | WQ_PERCPU, 0); 7957 + system_dfl_long_wq = alloc_workqueue("events_dfl_long", WQ_UNBOUND, WQ_MAX_ACTIVE); 7959 7958 BUG_ON(!system_wq || !system_percpu_wq|| !system_highpri_wq || !system_long_wq || 7960 7959 !system_unbound_wq || !system_freezable_wq || !system_dfl_wq || 7961 7960 !system_power_efficient_wq || 7962 7961 !system_freezable_power_efficient_wq || 7963 - !system_bh_wq || !system_bh_highpri_wq); 7962 + !system_bh_wq || !system_bh_highpri_wq || !system_dfl_long_wq); 7964 7963 } 7965 7964 7966 7965 static void __init wq_cpu_intensive_thresh_init(void)