diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-30 23:45:39 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-30 23:45:39 +0100 |
commit | f8cc87b6c1e333ce7adc9fb2cb698d93b16eabe3 (patch) | |
tree | 3930a111959740f2ff2a1881f7ae627b38e477b4 /kernel | |
parent | Merge branch 'userns-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/... (diff) | |
parent | workqueue: allow WQ_MEM_RECLAIM on early init workqueues (diff) | |
download | linux-f8cc87b6c1e333ce7adc9fb2cb698d93b16eabe3.tar.xz linux-f8cc87b6c1e333ce7adc9fb2cb698d93b16eabe3.zip |
Merge branch 'for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue updates from Tejun Heo:
"Workqueue has an early init trick where workqueues can be created and
work items queued on them before the workqueue subsystem is online.
This helps simplifying early init and operation of low level
subsystems which use workqueues for managerial things which aren't
depended upon early during boot.
Out of laziness, the early init didn't cover workqueues with
WQ_MEM_RECLAIM, which is inconsistent and confusing because adding the
flag simply makes the system fail to boot. Cover WQ_MEM_RECLAIM too.
This was originally brought up for RCU but RCU didn't actually need
this. I still think it's a good idea to cover it"
* 'for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
workqueue: allow WQ_MEM_RECLAIM on early init workqueues
workqueue: separate out init_rescuer()
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/workqueue.c | 64 |
1 files changed, 40 insertions, 24 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8c34981d90ad..8dd2e66e8383 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3940,6 +3940,37 @@ static int wq_clamp_max_active(int max_active, unsigned int flags, return clamp_val(max_active, 1, lim); } +/* + * Workqueues which may be used during memory reclaim should have a rescuer + * to guarantee forward progress. + */ +static int init_rescuer(struct workqueue_struct *wq) +{ + struct worker *rescuer; + int ret; + + if (!(wq->flags & WQ_MEM_RECLAIM)) + return 0; + + rescuer = alloc_worker(NUMA_NO_NODE); + if (!rescuer) + return -ENOMEM; + + rescuer->rescue_wq = wq; + rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", wq->name); + ret = PTR_ERR_OR_ZERO(rescuer->task); + if (ret) { + kfree(rescuer); + return ret; + } + + wq->rescuer = rescuer; + kthread_bind_mask(rescuer->task, cpu_possible_mask); + wake_up_process(rescuer->task); + + return 0; +} + struct workqueue_struct *__alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, @@ -4002,29 +4033,8 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, if (alloc_and_link_pwqs(wq) < 0) goto err_free_wq; - /* - * Workqueues which may be used during memory reclaim should - * have a rescuer to guarantee forward progress. - */ - if (flags & WQ_MEM_RECLAIM) { - struct worker *rescuer; - - rescuer = alloc_worker(NUMA_NO_NODE); - if (!rescuer) - goto err_destroy; - - rescuer->rescue_wq = wq; - rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", - wq->name); - if (IS_ERR(rescuer->task)) { - kfree(rescuer); - goto err_destroy; - } - - wq->rescuer = rescuer; - kthread_bind_mask(rescuer->task, cpu_possible_mask); - wake_up_process(rescuer->task); - } + if (wq_online && init_rescuer(wq) < 0) + goto err_destroy; if ((wq->flags & WQ_SYSFS) && workqueue_sysfs_register(wq)) goto err_destroy; @@ -5642,6 +5652,8 @@ int __init workqueue_init(void) * archs such as power and arm64. As per-cpu pools created * previously could be missing node hint and unbound pools NUMA * affinity, fix them up. + * + * Also, while iterating workqueues, create rescuers if requested. */ wq_numa_init(); @@ -5653,8 +5665,12 @@ int __init workqueue_init(void) } } - list_for_each_entry(wq, &workqueues, list) + list_for_each_entry(wq, &workqueues, list) { wq_update_unbound_numa(wq, smp_processor_id(), true); + WARN(init_rescuer(wq), + "workqueue: failed to create early rescuer for %s", + wq->name); + } mutex_unlock(&wq_pool_mutex); |