mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Merge tag 'wq-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue updates from Tejun Heo:
- Continued progress toward making alloc_workqueue() unbound by
default: more callers converted to WQ_PERCPU / system_percpu_wq /
system_dfl_wq, and new warnings for queues that use neither WQ_PERCPU
nor WQ_UNBOUND or the legacy system_wq / system_unbound_wq.
- Misc: drop the now-trivial apply_wqattrs_lock()/unlock() wrappers,
forbid the TEST_WORKQUEUE benchmark from being built-in, and fix a
spurious pointer level in the worker debug-dump path.
* tag 'wq-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
drm/bridge: anx7625: Add WQ_PERCPU add to alloc_workqueue
wifi: ath6kl: fix invalid workqueue flags in ath6kl_usb_create()
btrfs: Drop WQ_PERCPU from ordered_flags in btrfs_init_workqueues()
workqueue: Add warnings and ensure one among WQ_PERCPU or WQ_UNBOUND is present
workqueue: Add warnings and fallback if system_{unbound}_wq is used
workqueue: drop spurious '*' from print_worker_info() fn declaration
workqueue: forbid TEST_WORKQUEUE from being built-in
workqueue: drop apply_wqattrs_lock()/unlock() wrappers
umh: replace use of system_unbound_wq with system_dfl_wq
rapidio: rio: add WQ_PERCPU to alloc_workqueue users
media: ddbridge: add WQ_PERCPU to alloc_workqueue users
platform: cznic: turris-omnia-mcu: replace use of system_wq with system_percpu_wq
media: synopsys: hdmirx: replace use of system_unbound_wq with system_dfl_wq
virt: acrn: Add WQ_PERCPU to alloc_workqueue users
This commit is contained in:
@@ -2849,7 +2849,8 @@ static int anx7625_i2c_probe(struct i2c_client *client)
|
||||
if (platform->pdata.intp_irq) {
|
||||
INIT_WORK(&platform->work, anx7625_work_func);
|
||||
platform->workqueue = alloc_workqueue("anx7625_work",
|
||||
WQ_FREEZABLE | WQ_MEM_RECLAIM, 1);
|
||||
WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
|
||||
1);
|
||||
if (!platform->workqueue) {
|
||||
DRM_DEV_ERROR(dev, "fail to create work queue\n");
|
||||
ret = -ENOMEM;
|
||||
|
||||
@@ -3430,7 +3430,7 @@ int ddb_init_ddbridge(void)
|
||||
|
||||
if (ddb_class_create() < 0)
|
||||
return -1;
|
||||
ddb_wq = alloc_workqueue("ddbridge", 0, 0);
|
||||
ddb_wq = alloc_workqueue("ddbridge", WQ_PERCPU, 0);
|
||||
if (!ddb_wq)
|
||||
return ddb_exit_ddbridge(1, -1);
|
||||
|
||||
|
||||
@@ -1776,7 +1776,7 @@ static void process_signal_change(struct snps_hdmirx_dev *hdmirx_dev)
|
||||
FIFO_UNDERFLOW_INT_EN |
|
||||
HDMIRX_AXI_ERROR_INT_EN, 0);
|
||||
hdmirx_reset_dma(hdmirx_dev);
|
||||
queue_delayed_work(system_unbound_wq,
|
||||
queue_delayed_work(system_dfl_wq,
|
||||
&hdmirx_dev->delayed_work_res_change,
|
||||
msecs_to_jiffies(50));
|
||||
}
|
||||
@@ -2238,7 +2238,7 @@ static void hdmirx_delayed_work_res_change(struct work_struct *work)
|
||||
|
||||
if (hdmirx_wait_signal_lock(hdmirx_dev)) {
|
||||
hdmirx_plugout(hdmirx_dev);
|
||||
queue_delayed_work(system_unbound_wq,
|
||||
queue_delayed_work(system_dfl_wq,
|
||||
&hdmirx_dev->delayed_work_hotplug,
|
||||
msecs_to_jiffies(200));
|
||||
} else {
|
||||
@@ -2253,7 +2253,7 @@ static irqreturn_t hdmirx_5v_det_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct snps_hdmirx_dev *hdmirx_dev = dev_id;
|
||||
|
||||
queue_delayed_work(system_unbound_wq,
|
||||
queue_delayed_work(system_dfl_wq,
|
||||
&hdmirx_dev->delayed_work_hotplug,
|
||||
msecs_to_jiffies(10));
|
||||
|
||||
@@ -2518,7 +2518,7 @@ static void hdmirx_enable_irq(struct device *dev)
|
||||
enable_irq(hdmirx_dev->dma_irq);
|
||||
enable_irq(hdmirx_dev->det_irq);
|
||||
|
||||
queue_delayed_work(system_unbound_wq,
|
||||
queue_delayed_work(system_dfl_wq,
|
||||
&hdmirx_dev->delayed_work_hotplug,
|
||||
msecs_to_jiffies(110));
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
|
||||
ar_usb = kzalloc_obj(struct ath6kl_usb);
|
||||
if (ar_usb == NULL)
|
||||
return NULL;
|
||||
ar_usb->wq = alloc_workqueue("ath6kl_wq", 0, 0);
|
||||
ar_usb->wq = alloc_workqueue("ath6kl_wq", WQ_PERCPU, 0);
|
||||
if (!ar_usb->wq) {
|
||||
kfree(ar_usb);
|
||||
return NULL;
|
||||
|
||||
@@ -893,7 +893,7 @@ static bool omnia_irq_read_pending_old(struct omnia_mcu *mcu,
|
||||
|
||||
if (status & OMNIA_STS_BUTTON_PRESSED) {
|
||||
mcu->button_pressed_emul = true;
|
||||
mod_delayed_work(system_wq, &mcu->button_release_emul_work,
|
||||
mod_delayed_work(system_percpu_wq, &mcu->button_release_emul_work,
|
||||
msecs_to_jiffies(FRONT_BUTTON_RELEASE_DELAY_MS));
|
||||
} else if (mcu->button_pressed_emul) {
|
||||
status |= OMNIA_STS_BUTTON_PRESSED;
|
||||
|
||||
@@ -1994,7 +1994,7 @@ int rio_init_mports(void)
|
||||
* TODO: Implement restart of discovery process for all or
|
||||
* individual discovering mports.
|
||||
*/
|
||||
rio_wq = alloc_workqueue("riodisc", 0, 0);
|
||||
rio_wq = alloc_workqueue("riodisc", WQ_PERCPU, 0);
|
||||
if (!rio_wq) {
|
||||
pr_err("RIO: unable allocate rio_wq\n");
|
||||
goto no_disc;
|
||||
|
||||
@@ -206,7 +206,7 @@ int acrn_irqfd_init(struct acrn_vm *vm)
|
||||
{
|
||||
INIT_LIST_HEAD(&vm->irqfds);
|
||||
mutex_init(&vm->irqfds_lock);
|
||||
vm->irqfd_wq = alloc_workqueue("acrn_irqfd-%u", 0, 0, vm->vmid);
|
||||
vm->irqfd_wq = alloc_workqueue("acrn_irqfd-%u", WQ_PERCPU, 0, vm->vmid);
|
||||
if (!vm->irqfd_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -1951,7 +1951,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
u32 max_active = fs_info->thread_pool_size;
|
||||
unsigned int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND;
|
||||
unsigned int ordered_flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_PERCPU;
|
||||
unsigned int ordered_flags = WQ_MEM_RECLAIM | WQ_FREEZABLE;
|
||||
|
||||
fs_info->workers =
|
||||
btrfs_alloc_workqueue(fs_info, "worker", flags, max_active, 16);
|
||||
|
||||
@@ -409,6 +409,7 @@ enum wq_flags {
|
||||
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
|
||||
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
|
||||
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
|
||||
__WQ_DEPRECATED = 1 << 19, /* internal: workqueue is deprecated */
|
||||
|
||||
/* BH wq only allows the following flags */
|
||||
__WQ_BH_ALLOWS = WQ_BH | WQ_HIGHPRI | WQ_PERCPU,
|
||||
|
||||
@@ -430,7 +430,7 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
|
||||
sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done;
|
||||
sub_info->wait = wait;
|
||||
|
||||
queue_work(system_unbound_wq, &sub_info->work);
|
||||
queue_work(system_dfl_wq, &sub_info->work);
|
||||
if (wait == UMH_NO_WAIT) /* task has freed sub_info */
|
||||
goto unlock;
|
||||
|
||||
|
||||
@@ -2280,6 +2280,14 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
|
||||
unsigned int work_flags;
|
||||
unsigned int req_cpu = cpu;
|
||||
|
||||
/*
|
||||
* NOTE: Check whether the used workqueue is deprecated and warn
|
||||
*/
|
||||
if (unlikely(wq->flags & __WQ_DEPRECATED))
|
||||
pr_warn_once("workqueue: work func %ps enqueued on deprecated workqueue. "
|
||||
"Use system_{percpu|dfl}_wq instead.\n",
|
||||
work->func);
|
||||
|
||||
/*
|
||||
* While a work item is PENDING && off queue, a task trying to
|
||||
* steal the PENDING will busy-loop waiting for it to either get
|
||||
@@ -5312,16 +5320,6 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq,
|
||||
return pwq;
|
||||
}
|
||||
|
||||
static void apply_wqattrs_lock(void)
|
||||
{
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
}
|
||||
|
||||
static void apply_wqattrs_unlock(void)
|
||||
{
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* wq_calc_pod_cpumask - calculate a wq_attrs' cpumask for a pod
|
||||
* @attrs: the wq_attrs of the default pwq of the target workqueue
|
||||
@@ -5818,7 +5816,7 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
|
||||
|
||||
/* see the comment above the definition of WQ_POWER_EFFICIENT */
|
||||
if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
|
||||
flags |= WQ_UNBOUND;
|
||||
flags = (flags & ~WQ_PERCPU) | WQ_UNBOUND;
|
||||
|
||||
/* allocate wq and format name */
|
||||
if (flags & WQ_UNBOUND)
|
||||
@@ -5842,6 +5840,23 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
|
||||
pr_warn_once("workqueue: name exceeds WQ_NAME_LEN. Truncating to: %s\n",
|
||||
wq->name);
|
||||
|
||||
/*
|
||||
* One among WQ_PERCPU and WQ_UNBOUND must be set, but not both.
|
||||
* - If neither is set, default to WQ_PERCPU
|
||||
* - If both are set, default to WQ_UNBOUND
|
||||
*
|
||||
* This code can be removed after workqueue are unbound by default
|
||||
*/
|
||||
if (unlikely(!(flags & (WQ_UNBOUND | WQ_PERCPU)))) {
|
||||
WARN_ONCE(1, "workqueue: %s is using neither WQ_PERCPU or WQ_UNBOUND. "
|
||||
"Setting WQ_PERCPU.\n", wq->name);
|
||||
flags |= WQ_PERCPU;
|
||||
} else if (unlikely((flags & WQ_PERCPU) && (flags & WQ_UNBOUND))) {
|
||||
WARN_ONCE(1, "workqueue: %s uses both WQ_PERCPU and WQ_UNBOUND. "
|
||||
"Dropped WQ_PERCPU, keeping WQ_UNBOUND.\n", wq->name);
|
||||
flags &= ~WQ_PERCPU;
|
||||
}
|
||||
|
||||
if (flags & WQ_BH) {
|
||||
/*
|
||||
* BH workqueues always share a single execution context per CPU
|
||||
@@ -5877,7 +5892,7 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
|
||||
* wq_pool_mutex protects the workqueues list, allocations of PWQs,
|
||||
* and the global freeze state.
|
||||
*/
|
||||
apply_wqattrs_lock();
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
|
||||
if (alloc_and_link_pwqs(wq) < 0)
|
||||
goto err_unlock_free_node_nr_active;
|
||||
@@ -5891,7 +5906,7 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
|
||||
if (wq_online && init_rescuer(wq) < 0)
|
||||
goto err_unlock_destroy;
|
||||
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
|
||||
if ((wq->flags & WQ_SYSFS) && workqueue_sysfs_register(wq))
|
||||
goto err_destroy;
|
||||
@@ -5899,7 +5914,7 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
|
||||
return wq;
|
||||
|
||||
err_unlock_free_node_nr_active:
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
/*
|
||||
* Failed alloc_and_link_pwqs() may leave pending pwq->release_work,
|
||||
* flushing the pwq_release_worker ensures that the pwq_release_workfn()
|
||||
@@ -5914,7 +5929,7 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
|
||||
kfree(wq);
|
||||
return NULL;
|
||||
err_unlock_destroy:
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
err_destroy:
|
||||
destroy_workqueue(wq);
|
||||
return NULL;
|
||||
@@ -6310,7 +6325,7 @@ EXPORT_SYMBOL_GPL(set_worker_desc);
|
||||
*/
|
||||
void print_worker_info(const char *log_lvl, struct task_struct *task)
|
||||
{
|
||||
work_func_t *fn = NULL;
|
||||
work_func_t fn = NULL;
|
||||
char name[WQ_NAME_LEN] = { };
|
||||
char desc[WORKER_DESC_LEN] = { };
|
||||
struct pool_workqueue *pwq = NULL;
|
||||
@@ -7315,7 +7330,7 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr,
|
||||
struct workqueue_attrs *attrs;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (!attrs)
|
||||
@@ -7328,7 +7343,7 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr,
|
||||
ret = -EINVAL;
|
||||
|
||||
out_unlock:
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
free_workqueue_attrs(attrs);
|
||||
return ret ?: count;
|
||||
}
|
||||
@@ -7354,7 +7369,7 @@ static ssize_t wq_cpumask_store(struct device *dev,
|
||||
struct workqueue_attrs *attrs;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (!attrs)
|
||||
@@ -7365,7 +7380,7 @@ static ssize_t wq_cpumask_store(struct device *dev,
|
||||
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||
|
||||
out_unlock:
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
free_workqueue_attrs(attrs);
|
||||
return ret ?: count;
|
||||
}
|
||||
@@ -7401,13 +7416,13 @@ static ssize_t wq_affn_scope_store(struct device *dev,
|
||||
if (affn < 0)
|
||||
return affn;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (attrs) {
|
||||
attrs->affn_scope = affn;
|
||||
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||
}
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
free_workqueue_attrs(attrs);
|
||||
return ret ?: count;
|
||||
}
|
||||
@@ -7432,13 +7447,13 @@ static ssize_t wq_affinity_strict_store(struct device *dev,
|
||||
if (sscanf(buf, "%d", &v) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (attrs) {
|
||||
attrs->affn_strict = (bool)v;
|
||||
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||
}
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
free_workqueue_attrs(attrs);
|
||||
return ret ?: count;
|
||||
}
|
||||
@@ -7479,12 +7494,12 @@ static int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
|
||||
cpumask_and(cpumask, cpumask, cpu_possible_mask);
|
||||
if (!cpumask_empty(cpumask)) {
|
||||
ret = 0;
|
||||
apply_wqattrs_lock();
|
||||
mutex_lock(&wq_pool_mutex);
|
||||
if (!cpumask_equal(cpumask, wq_unbound_cpumask))
|
||||
ret = workqueue_apply_unbound_cpumask(cpumask);
|
||||
if (!ret)
|
||||
cpumask_copy(wq_requested_unbound_cpumask, cpumask);
|
||||
apply_wqattrs_unlock();
|
||||
mutex_unlock(&wq_pool_mutex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -8037,12 +8052,12 @@ void __init workqueue_init_early(void)
|
||||
ordered_wq_attrs[i] = attrs;
|
||||
}
|
||||
|
||||
system_wq = alloc_workqueue("events", WQ_PERCPU, 0);
|
||||
system_wq = alloc_workqueue("events", WQ_PERCPU | __WQ_DEPRECATED, 0);
|
||||
system_percpu_wq = alloc_workqueue("events", WQ_PERCPU, 0);
|
||||
system_highpri_wq = alloc_workqueue("events_highpri",
|
||||
WQ_HIGHPRI | WQ_PERCPU, 0);
|
||||
system_long_wq = alloc_workqueue("events_long", WQ_PERCPU, 0);
|
||||
system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_MAX_ACTIVE);
|
||||
system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND | __WQ_DEPRECATED, WQ_MAX_ACTIVE);
|
||||
system_dfl_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_MAX_ACTIVE);
|
||||
system_freezable_wq = alloc_workqueue("events_freezable",
|
||||
WQ_FREEZABLE | WQ_PERCPU, 0);
|
||||
|
||||
@@ -2649,12 +2649,17 @@ config TEST_VMALLOC
|
||||
|
||||
config TEST_WORKQUEUE
|
||||
tristate "Test module for stress/performance analysis of workqueue"
|
||||
depends on m
|
||||
default n
|
||||
help
|
||||
This builds the "test_workqueue" module for benchmarking
|
||||
workqueue throughput under contention. Useful for evaluating
|
||||
affinity scope changes (e.g., cache_shard vs cache).
|
||||
|
||||
The test drives sysfs to switch affinity scopes, so it must be
|
||||
loaded after userspace has mounted sysfs; building it in (=y)
|
||||
would run module_init before /sys is available.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config TEST_BPF
|
||||
|
||||
Reference in New Issue
Block a user