diff options
-rw-r--r-- | include/linux/workqueue.h | 7 | ||||
-rw-r--r-- | init/main.c | 10 | ||||
-rw-r--r-- | kernel/workqueue.c | 76 |
3 files changed, 76 insertions, 17 deletions
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 26cc1df280d6..91d416f9c0a7 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h | |||
@@ -358,6 +358,8 @@ extern struct workqueue_struct *system_freezable_wq; | |||
358 | extern struct workqueue_struct *system_power_efficient_wq; | 358 | extern struct workqueue_struct *system_power_efficient_wq; |
359 | extern struct workqueue_struct *system_freezable_power_efficient_wq; | 359 | extern struct workqueue_struct *system_freezable_power_efficient_wq; |
360 | 360 | ||
361 | extern bool wq_online; | ||
362 | |||
361 | extern struct workqueue_struct * | 363 | extern struct workqueue_struct * |
362 | __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, | 364 | __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, |
363 | struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6); | 365 | struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6); |
@@ -594,7 +596,7 @@ static inline bool schedule_delayed_work(struct delayed_work *dwork, | |||
594 | */ | 596 | */ |
595 | static inline bool keventd_up(void) | 597 | static inline bool keventd_up(void) |
596 | { | 598 | { |
597 | return system_wq != NULL; | 599 | return wq_online; |
598 | } | 600 | } |
599 | 601 | ||
600 | #ifndef CONFIG_SMP | 602 | #ifndef CONFIG_SMP |
@@ -631,4 +633,7 @@ int workqueue_online_cpu(unsigned int cpu); | |||
631 | int workqueue_offline_cpu(unsigned int cpu); | 633 | int workqueue_offline_cpu(unsigned int cpu); |
632 | #endif | 634 | #endif |
633 | 635 | ||
636 | int __init workqueue_init_early(void); | ||
637 | int __init workqueue_init(void); | ||
638 | |||
634 | #endif | 639 | #endif |
diff --git a/init/main.c b/init/main.c index a8a58e2794a5..5c4fd68a8671 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -551,6 +551,14 @@ asmlinkage __visible void __init start_kernel(void) | |||
551 | "Interrupts were enabled *very* early, fixing it\n")) | 551 | "Interrupts were enabled *very* early, fixing it\n")) |
552 | local_irq_disable(); | 552 | local_irq_disable(); |
553 | idr_init_cache(); | 553 | idr_init_cache(); |
554 | |||
555 | /* | ||
556 | * Allow workqueue creation and work item queueing/cancelling | ||
557 | * early. Work item execution depends on kthreads and starts after | ||
558 | * workqueue_init(). | ||
559 | */ | ||
560 | workqueue_init_early(); | ||
561 | |||
554 | rcu_init(); | 562 | rcu_init(); |
555 | 563 | ||
556 | /* trace_printk() and trace points may be used after this */ | 564 | /* trace_printk() and trace points may be used after this */ |
@@ -1005,6 +1013,8 @@ static noinline void __init kernel_init_freeable(void) | |||
1005 | 1013 | ||
1006 | smp_prepare_cpus(setup_max_cpus); | 1014 | smp_prepare_cpus(setup_max_cpus); |
1007 | 1015 | ||
1016 | workqueue_init(); | ||
1017 | |||
1008 | do_pre_smp_initcalls(); | 1018 | do_pre_smp_initcalls(); |
1009 | lockup_detector_init(); | 1019 | lockup_detector_init(); |
1010 | 1020 | ||
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 4eaec8b86d65..15d0811c9e91 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -290,6 +290,8 @@ module_param_named(disable_numa, wq_disable_numa, bool, 0444); | |||
290 | static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT); | 290 | static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT); |
291 | module_param_named(power_efficient, wq_power_efficient, bool, 0444); | 291 | module_param_named(power_efficient, wq_power_efficient, bool, 0444); |
292 | 292 | ||
293 | bool wq_online; /* can kworkers be created yet? */ | ||
294 | |||
293 | static bool wq_numa_enabled; /* unbound NUMA affinity enabled */ | 295 | static bool wq_numa_enabled; /* unbound NUMA affinity enabled */ |
294 | 296 | ||
295 | /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */ | 297 | /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */ |
@@ -2583,6 +2585,9 @@ void flush_workqueue(struct workqueue_struct *wq) | |||
2583 | }; | 2585 | }; |
2584 | int next_color; | 2586 | int next_color; |
2585 | 2587 | ||
2588 | if (WARN_ON(!wq_online)) | ||
2589 | return; | ||
2590 | |||
2586 | lock_map_acquire(&wq->lockdep_map); | 2591 | lock_map_acquire(&wq->lockdep_map); |
2587 | lock_map_release(&wq->lockdep_map); | 2592 | lock_map_release(&wq->lockdep_map); |
2588 | 2593 | ||
@@ -2843,6 +2848,9 @@ bool flush_work(struct work_struct *work) | |||
2843 | { | 2848 | { |
2844 | struct wq_barrier barr; | 2849 | struct wq_barrier barr; |
2845 | 2850 | ||
2851 | if (WARN_ON(!wq_online)) | ||
2852 | return false; | ||
2853 | |||
2846 | lock_map_acquire(&work->lockdep_map); | 2854 | lock_map_acquire(&work->lockdep_map); |
2847 | lock_map_release(&work->lockdep_map); | 2855 | lock_map_release(&work->lockdep_map); |
2848 | 2856 | ||
@@ -2913,7 +2921,13 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) | |||
2913 | mark_work_canceling(work); | 2921 | mark_work_canceling(work); |
2914 | local_irq_restore(flags); | 2922 | local_irq_restore(flags); |
2915 | 2923 | ||
2916 | flush_work(work); | 2924 | /* |
2925 | * This allows canceling during early boot. We know that @work | ||
2926 | * isn't executing. | ||
2927 | */ | ||
2928 | if (wq_online) | ||
2929 | flush_work(work); | ||
2930 | |||
2917 | clear_work_data(work); | 2931 | clear_work_data(work); |
2918 | 2932 | ||
2919 | /* | 2933 | /* |
@@ -3352,7 +3366,7 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) | |||
3352 | goto fail; | 3366 | goto fail; |
3353 | 3367 | ||
3354 | /* create and start the initial worker */ | 3368 | /* create and start the initial worker */ |
3355 | if (!create_worker(pool)) | 3369 | if (wq_online && !create_worker(pool)) |
3356 | goto fail; | 3370 | goto fail; |
3357 | 3371 | ||
3358 | /* install */ | 3372 | /* install */ |
@@ -3417,6 +3431,7 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq) | |||
3417 | { | 3431 | { |
3418 | struct workqueue_struct *wq = pwq->wq; | 3432 | struct workqueue_struct *wq = pwq->wq; |
3419 | bool freezable = wq->flags & WQ_FREEZABLE; | 3433 | bool freezable = wq->flags & WQ_FREEZABLE; |
3434 | unsigned long flags; | ||
3420 | 3435 | ||
3421 | /* for @wq->saved_max_active */ | 3436 | /* for @wq->saved_max_active */ |
3422 | lockdep_assert_held(&wq->mutex); | 3437 | lockdep_assert_held(&wq->mutex); |
@@ -3425,7 +3440,8 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq) | |||
3425 | if (!freezable && pwq->max_active == wq->saved_max_active) | 3440 | if (!freezable && pwq->max_active == wq->saved_max_active) |
3426 | return; | 3441 | return; |
3427 | 3442 | ||
3428 | spin_lock_irq(&pwq->pool->lock); | 3443 | /* this function can be called during early boot w/ irq disabled */ |
3444 | spin_lock_irqsave(&pwq->pool->lock, flags); | ||
3429 | 3445 | ||
3430 | /* | 3446 | /* |
3431 | * During [un]freezing, the caller is responsible for ensuring that | 3447 | * During [un]freezing, the caller is responsible for ensuring that |
@@ -3448,7 +3464,7 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq) | |||
3448 | pwq->max_active = 0; | 3464 | pwq->max_active = 0; |
3449 | } | 3465 | } |
3450 | 3466 | ||
3451 | spin_unlock_irq(&pwq->pool->lock); | 3467 | spin_unlock_irqrestore(&pwq->pool->lock, flags); |
3452 | } | 3468 | } |
3453 | 3469 | ||
3454 | /* initialize newly alloced @pwq which is associated with @wq and @pool */ | 3470 | /* initialize newly alloced @pwq which is associated with @wq and @pool */ |
@@ -5457,7 +5473,17 @@ static void __init wq_numa_init(void) | |||
5457 | wq_numa_enabled = true; | 5473 | wq_numa_enabled = true; |
5458 | } | 5474 | } |
5459 | 5475 | ||
5460 | static int __init init_workqueues(void) | 5476 | /** |
5477 | * workqueue_init_early - early init for workqueue subsystem | ||
5478 | * | ||
5479 | * This is the first half of two-staged workqueue subsystem initialization | ||
5480 | * and invoked as soon as the bare basics - memory allocation, cpumasks and | ||
5481 | * idr are up. It sets up all the data structures and system workqueues | ||
5482 | * and allows early boot code to create workqueues and queue/cancel work | ||
5483 | * items. Actual work item execution starts only after kthreads can be | ||
5484 | * created and scheduled right before early initcalls. | ||
5485 | */ | ||
5486 | int __init workqueue_init_early(void) | ||
5461 | { | 5487 | { |
5462 | int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL }; | 5488 | int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL }; |
5463 | int i, cpu; | 5489 | int i, cpu; |
@@ -5490,16 +5516,6 @@ static int __init init_workqueues(void) | |||
5490 | } | 5516 | } |
5491 | } | 5517 | } |
5492 | 5518 | ||
5493 | /* create the initial worker */ | ||
5494 | for_each_online_cpu(cpu) { | ||
5495 | struct worker_pool *pool; | ||
5496 | |||
5497 | for_each_cpu_worker_pool(pool, cpu) { | ||
5498 | pool->flags &= ~POOL_DISASSOCIATED; | ||
5499 | BUG_ON(!create_worker(pool)); | ||
5500 | } | ||
5501 | } | ||
5502 | |||
5503 | /* create default unbound and ordered wq attrs */ | 5519 | /* create default unbound and ordered wq attrs */ |
5504 | for (i = 0; i < NR_STD_WORKER_POOLS; i++) { | 5520 | for (i = 0; i < NR_STD_WORKER_POOLS; i++) { |
5505 | struct workqueue_attrs *attrs; | 5521 | struct workqueue_attrs *attrs; |
@@ -5536,8 +5552,36 @@ static int __init init_workqueues(void) | |||
5536 | !system_power_efficient_wq || | 5552 | !system_power_efficient_wq || |
5537 | !system_freezable_power_efficient_wq); | 5553 | !system_freezable_power_efficient_wq); |
5538 | 5554 | ||
5555 | return 0; | ||
5556 | } | ||
5557 | |||
5558 | /** | ||
5559 | * workqueue_init - bring workqueue subsystem fully online | ||
5560 | * | ||
5561 | * This is the latter half of two-staged workqueue subsystem initialization | ||
5562 | * and invoked as soon as kthreads can be created and scheduled. | ||
5563 | * Workqueues have been created and work items queued on them, but there | ||
5564 | * are no kworkers executing the work items yet. Populate the worker pools | ||
5565 | * with the initial workers and enable future kworker creations. | ||
5566 | */ | ||
5567 | int __init workqueue_init(void) | ||
5568 | { | ||
5569 | struct worker_pool *pool; | ||
5570 | int cpu, bkt; | ||
5571 | |||
5572 | /* create the initial workers */ | ||
5573 | for_each_online_cpu(cpu) { | ||
5574 | for_each_cpu_worker_pool(pool, cpu) { | ||
5575 | pool->flags &= ~POOL_DISASSOCIATED; | ||
5576 | BUG_ON(!create_worker(pool)); | ||
5577 | } | ||
5578 | } | ||
5579 | |||
5580 | hash_for_each(unbound_pool_hash, bkt, pool, hash_node) | ||
5581 | BUG_ON(!create_worker(pool)); | ||
5582 | |||
5583 | wq_online = true; | ||
5539 | wq_watchdog_init(); | 5584 | wq_watchdog_init(); |
5540 | 5585 | ||
5541 | return 0; | 5586 | return 0; |
5542 | } | 5587 | } |
5543 | early_initcall(init_workqueues); | ||