Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1484494 > unrolled thread

[PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot

Started byTejun Heo <tj@kernel.org>
First post2016-09-15 21:40 +0200
Last post2016-09-16 22:00 +0200
Articles 12 — 4 participants

Back to article view | Back to linux.kernel


Contents

  [PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot Tejun Heo <tj@kernel.org> - 2016-09-15 21:40 +0200
    [PATCH 2/7] mce, workqueue: remove keventd_up() usage Tejun Heo <tj@kernel.org> - 2016-09-15 21:40 +0200
      Re: [PATCH 2/7] mce, workqueue: remove keventd_up() usage Borislav Petkov <bp@alien8.de> - 2016-09-17 10:00 +0200
        Re: [PATCH 2/7] mce, workqueue: remove keventd_up() usage Tejun Heo <tj@kernel.org> - 2016-09-17 19:30 +0200
          Re: [PATCH 2/7] mce, workqueue: remove keventd_up() usage Borislav Petkov <bp@alien8.de> - 2016-09-17 22:30 +0200
    [PATCH 5/7] slab, workqueue: remove keventd_up() usage Tejun Heo <tj@kernel.org> - 2016-09-15 21:40 +0200
      Re: [PATCH 5/7] slab, workqueue: remove keventd_up() usage Joonsoo Kim <iamjoonsoo.kim@lge.com> - 2016-09-22 10:10 +0200
    [PATCH 7/7] workqueue: remove keventd_up() Tejun Heo <tj@kernel.org> - 2016-09-15 21:40 +0200
    [PATCH 1/7] workqueue: make workqueue available early during boot Tejun Heo <tj@kernel.org> - 2016-09-15 21:40 +0200
      [PATCH v2 1/7] workqueue: make workqueue available early during boot Tejun Heo <tj@kernel.org> - 2016-09-17 19:30 +0200
    Re: [PATCHSET wq/for-4.9] workqueue: make workqueue available very  early during boot Linus Torvalds <torvalds@linux-foundation.org> - 2016-09-15 22:00 +0200
    Re: [PATCHSET wq/for-4.9] workqueue: make workqueue available very  early during boot Tejun Heo <tj@kernel.org> - 2016-09-16 22:00 +0200

#1484494 — [PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot

FromTejun Heo <tj@kernel.org>
Date2016-09-15 21:40 +0200
Subject[PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot
Message-ID<shKFP-2IM-5@gated-at.bofh.it>
Hello,

Workqueue is currently initialized in an early init call; however,
there are cases where early boot code has to be split and reordered to
come after workqueue initialization or the same code path which makes
use of workqueues is used both before workqueue initailization and
after.  The latter cases have to gate workqueue usages with
keventd_up() tests, which is nasty and easy to get wrong.

This patchset makes workqueue creation and work item
queueing/canceling available from very early during boot which allows
all existing usages of keventd_up() which is removed by the last
patch.

This patchset contains the following seven patches.

 0001-workqueue-make-workqueue-available-early-during-boot.patch
 0002-mce-workqueue-remove-keventd_up-usage.patch
 0003-tty-workqueue-remove-keventd_up-usage.patch
 0004-power-workqueue-remove-keventd_up-usage.patch
 0005-slab-workqueue-remove-keventd_up-usage.patch
 0006-debugobj-workqueue-remove-keventd_up-usage.patch
 0007-workqueue-remove-keventd_up.patch

The patchset is also available in the following git branch.

 git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git review-wq-early

Once the patches are reviewed, I'll route the patches through the
wq/for-4.9 branch.  diffstat follows.  Thanks.

 arch/x86/kernel/cpu/mcheck/mce.c |    2 -
 drivers/tty/vt/vt.c              |    4 --
 include/linux/workqueue.h        |   11 +----
 init/main.c                      |   10 +++++
 kernel/power/qos.c               |   11 -----
 kernel/workqueue.c               |   77 ++++++++++++++++++++++++++++++---------
 lib/debugobjects.c               |    2 -
 mm/slab.c                        |    7 ---
 8 files changed, 78 insertions(+), 46 deletions(-)

--
tejun

[toc] | [next] | [standalone]


#1484496 — [PATCH 2/7] mce, workqueue: remove keventd_up() usage

FromTejun Heo <tj@kernel.org>
Date2016-09-15 21:40 +0200
Subject[PATCH 2/7] mce, workqueue: remove keventd_up() usage
Message-ID<shKFQ-2IM-15@gated-at.bofh.it>
In reply to#1484494
Now that workqueue can handle work item queueing from very early
during boot, there is no need to gate schedule_work() with
keventd_up().  Remove it.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: linux-edac@vger.kernel.org
---
Hello,

This change depends on an earlier workqueue patch and is followed by a
patch to remove keventd_up().  It'd be great if it can be routed
through the wq/for-4.9 branch.

Thanks.

 arch/x86/kernel/cpu/mcheck/mce.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 79d8ec8..675b7d8 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -491,7 +491,7 @@ int mce_available(struct cpuinfo_x86 *c)
 
 static void mce_schedule_work(void)
 {
-	if (!mce_gen_pool_empty() && keventd_up())
+	if (!mce_gen_pool_empty())
 		schedule_work(&mce_work);
 }
 
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1485495 — Re: [PATCH 2/7] mce, workqueue: remove keventd_up() usage

FromBorislav Petkov <bp@alien8.de>
Date2016-09-17 10:00 +0200
SubjectRe: [PATCH 2/7] mce, workqueue: remove keventd_up() usage
Message-ID<siiHw-87W-27@gated-at.bofh.it>
In reply to#1484496
On Thu, Sep 15, 2016 at 03:30:16PM -0400, Tejun Heo wrote:
> Now that workqueue can handle work item queueing from very early
> during boot, there is no need to gate schedule_work() with
> keventd_up().  Remove it.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: linux-edac@vger.kernel.org
> ---
> Hello,
> 
> This change depends on an earlier workqueue patch and is followed by a
> patch to remove keventd_up().  It'd be great if it can be routed
> through the wq/for-4.9 branch.

I don't mind as long as I can call it as early as:

->x86_64_start_reservations
|->start_kernel
  |->check_bugs
     |->identify_boot_cpu
        |->identify_cpu
	   |->mcheck_cpu_init
	     |->do_machine_check
	       |->mce_report_event
	          |->mce_schedule_work

because this is the earliest callchain I can see.

Thanks.

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

[toc] | [prev] | [next] | [standalone]


#1485580 — Re: [PATCH 2/7] mce, workqueue: remove keventd_up() usage

FromTejun Heo <tj@kernel.org>
Date2016-09-17 19:30 +0200
SubjectRe: [PATCH 2/7] mce, workqueue: remove keventd_up() usage
Message-ID<sirB7-5py-15@gated-at.bofh.it>
In reply to#1485495
On Sat, Sep 17, 2016 at 09:56:23AM +0200, Borislav Petkov wrote:
> > This change depends on an earlier workqueue patch and is followed by a
> > patch to remove keventd_up().  It'd be great if it can be routed
> > through the wq/for-4.9 branch.
> 
> I don't mind as long as I can call it as early as:
> 
> ->x86_64_start_reservations
> |->start_kernel
>   |->check_bugs
>      |->identify_boot_cpu
>         |->identify_cpu
> 	   |->mcheck_cpu_init
> 	     |->do_machine_check
> 	       |->mce_report_event
> 	          |->mce_schedule_work
> 
> because this is the earliest callchain I can see.

Yeah, that's way after workqueue early init.  Should be fine.

Thanks.

-- 
tejun

[toc] | [prev] | [next] | [standalone]


#1485607 — Re: [PATCH 2/7] mce, workqueue: remove keventd_up() usage

FromBorislav Petkov <bp@alien8.de>
Date2016-09-17 22:30 +0200
SubjectRe: [PATCH 2/7] mce, workqueue: remove keventd_up() usage
Message-ID<siupj-79p-5@gated-at.bofh.it>
In reply to#1485580
On Sat, Sep 17, 2016 at 01:24:05PM -0400, Tejun Heo wrote:
> Yeah, that's way after workqueue early init.  Should be fine.

Ok.

Acked-by: Borislav Petkov <bp@suse.de>

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

[toc] | [prev] | [next] | [standalone]


#1484497 — [PATCH 5/7] slab, workqueue: remove keventd_up() usage

FromTejun Heo <tj@kernel.org>
Date2016-09-15 21:40 +0200
Subject[PATCH 5/7] slab, workqueue: remove keventd_up() usage
Message-ID<shKFQ-2IM-19@gated-at.bofh.it>
In reply to#1484494
Now that workqueue can handle work item queueing from very early
during boot, there is no need to gate schedule_delayed_work_on() while
!keventd_up().  Remove it.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
---
Hello,

This change depends on an earlier workqueue patch and is followed by a
patch to remove keventd_up().  It'd be great if it can be routed
through the wq/for-4.9 branch.

Thanks.

 mm/slab.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/mm/slab.c b/mm/slab.c
index b672710..dc69b6b 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -550,12 +550,7 @@ static void start_cpu_timer(int cpu)
 {
 	struct delayed_work *reap_work = &per_cpu(slab_reap_work, cpu);
 
-	/*
-	 * When this gets called from do_initcalls via cpucache_init(),
-	 * init_workqueues() has already run, so keventd will be setup
-	 * at that time.
-	 */
-	if (keventd_up() && reap_work->work.func == NULL) {
+	if (reap_work->work.func == NULL) {
 		init_reap_node(cpu);
 		INIT_DEFERRABLE_WORK(reap_work, cache_reap);
 		schedule_delayed_work_on(cpu, reap_work,
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1488611 — Re: [PATCH 5/7] slab, workqueue: remove keventd_up() usage

FromJoonsoo Kim <iamjoonsoo.kim@lge.com>
Date2016-09-22 10:10 +0200
SubjectRe: [PATCH 5/7] slab, workqueue: remove keventd_up() usage
Message-ID<sk7eV-3OW-13@gated-at.bofh.it>
In reply to#1484497
On Thu, Sep 15, 2016 at 03:30:19PM -0400, Tejun Heo wrote:
> Now that workqueue can handle work item queueing from very early
> during boot, there is no need to gate schedule_delayed_work_on() while
> !keventd_up().  Remove it.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> Cc: Christoph Lameter <cl@linux.com>
> Cc: Pekka Enberg <penberg@kernel.org>
> Cc: David Rientjes <rientjes@google.com>
> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: linux-mm@kvack.org
> ---
> Hello,
> 
> This change depends on an earlier workqueue patch and is followed by a
> patch to remove keventd_up().  It'd be great if it can be routed
> through the wq/for-4.9 branch.

Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

Thanks.

[toc] | [prev] | [next] | [standalone]


#1484499 — [PATCH 7/7] workqueue: remove keventd_up()

FromTejun Heo <tj@kernel.org>
Date2016-09-15 21:40 +0200
Subject[PATCH 7/7] workqueue: remove keventd_up()
Message-ID<shKFQ-2IM-27@gated-at.bofh.it>
In reply to#1484494
keventd_up() no longer has in-kernel users.  Remove it and make
wq_online static.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
 include/linux/workqueue.h | 10 ----------
 kernel/workqueue.c        |  2 +-
 2 files changed, 1 insertion(+), 11 deletions(-)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 91d416f..5641713 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -358,8 +358,6 @@ extern struct workqueue_struct *system_freezable_wq;
 extern struct workqueue_struct *system_power_efficient_wq;
 extern struct workqueue_struct *system_freezable_power_efficient_wq;
 
-extern bool wq_online;
-
 extern struct workqueue_struct *
 __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
 	struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6);
@@ -591,14 +589,6 @@ static inline bool schedule_delayed_work(struct delayed_work *dwork,
 	return queue_delayed_work(system_wq, dwork, delay);
 }
 
-/**
- * keventd_up - is workqueue initialized yet?
- */
-static inline bool keventd_up(void)
-{
-	return wq_online;
-}
-
 #ifndef CONFIG_SMP
 static inline long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
 {
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index a05ab14..3bef80a 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -290,7 +290,7 @@ module_param_named(disable_numa, wq_disable_numa, bool, 0444);
 static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT);
 module_param_named(power_efficient, wq_power_efficient, bool, 0444);
 
-bool wq_online;				/* can kworkers be created yet? */
+static bool wq_online;			/* can kworkers be created yet? */
 
 static bool wq_numa_enabled;		/* unbound NUMA affinity enabled */
 
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1484501 — [PATCH 1/7] workqueue: make workqueue available early during boot

FromTejun Heo <tj@kernel.org>
Date2016-09-15 21:40 +0200
Subject[PATCH 1/7] workqueue: make workqueue available early during boot
Message-ID<shKFQ-2IM-33@gated-at.bofh.it>
In reply to#1484494
Workqueue is currently initialized in an early init call; however,
there are cases where early boot code has to be split and reordered to
come after workqueue initialization or the same code path which makes
use of workqueues is used both before workqueue initailization and
after.  The latter cases have to gate workqueue usages with
keventd_up() tests, which is nasty and easy to get wrong.

Workqueue usages have become widespread and it'd be a lot more
convenient if it can be used very early from boot.  This patch splits
workqueue initialization into two steps.  workqueue_init_early() which
sets up the basic data structures so that workqueues can be created
and work items queued, and workqueue_init() which actually brings up
workqueues online and starts executing queued work items.  The former
step can be done very early during boot once memory allocation,
cpumasks and idr are initialized.  The latter right after kthreads
become available.

This allows work item queueing and canceling from very early boot
which is what most of these use cases want.

* As systemd_wq being initialized doesn't indicate that workqueue is
  fully online anymore, update keventd_up() to test wq_online instead.
  The follow-up patches will get rid of all its usages and the
  function itself.

* Flushing doesn't make sense before workqueue is fully initialized.
  The flush functions trigger WARN and return immediately before fully
  online.

* Work items are never in-flight before fully online.  Canceling can
  always succeed by skipping the flush step.

* Some code paths can no longer assume to be called with irq enabled
  as irq is disabled during early boot.  Use irqsave/restore
  operations instead.

Signed-off-by: Tejun Heo <tj@kernel.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/CA+55aFx0vPuMuxn00rBSM192n-Du5uxy+4AvKa0SBSOVJeuCGg@mail.gmail.com
---
 include/linux/workqueue.h |  7 ++++-
 init/main.c               | 10 ++++++
 kernel/workqueue.c        | 77 +++++++++++++++++++++++++++++++++++++----------
 3 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 26cc1df..91d416f 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -358,6 +358,8 @@ extern struct workqueue_struct *system_freezable_wq;
 extern struct workqueue_struct *system_power_efficient_wq;
 extern struct workqueue_struct *system_freezable_power_efficient_wq;
 
+extern bool wq_online;
+
 extern struct workqueue_struct *
 __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
 	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,
  */
 static inline bool keventd_up(void)
 {
-	return system_wq != NULL;
+	return wq_online;
 }
 
 #ifndef CONFIG_SMP
@@ -631,4 +633,7 @@ int workqueue_online_cpu(unsigned int cpu);
 int workqueue_offline_cpu(unsigned int cpu);
 #endif
 
+int __init workqueue_init_early(void);
+int __init workqueue_init(void);
+
 #endif
diff --git a/init/main.c b/init/main.c
index a8a58e2..5c4fd68 100644
--- a/init/main.c
+++ b/init/main.c
@@ -551,6 +551,14 @@ asmlinkage __visible void __init start_kernel(void)
 		 "Interrupts were enabled *very* early, fixing it\n"))
 		local_irq_disable();
 	idr_init_cache();
+
+	/*
+	 * Allow workqueue creation and work item queueing/cancelling
+	 * early.  Work item execution depends on kthreads and starts after
+	 * workqueue_init().
+	 */
+	workqueue_init_early();
+
 	rcu_init();
 
 	/* trace_printk() and trace points may be used after this */
@@ -1005,6 +1013,8 @@ static noinline void __init kernel_init_freeable(void)
 
 	smp_prepare_cpus(setup_max_cpus);
 
+	workqueue_init();
+
 	do_pre_smp_initcalls();
 	lockup_detector_init();
 
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index ef071ca..a05ab14 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -290,6 +290,8 @@ module_param_named(disable_numa, wq_disable_numa, bool, 0444);
 static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT);
 module_param_named(power_efficient, wq_power_efficient, bool, 0444);
 
+bool wq_online;				/* can kworkers be created yet? */
+
 static bool wq_numa_enabled;		/* unbound NUMA affinity enabled */
 
 /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */
@@ -2583,6 +2585,9 @@ void flush_workqueue(struct workqueue_struct *wq)
 	};
 	int next_color;
 
+	if (WARN_ON(!wq_online))
+		return;
+
 	lock_map_acquire(&wq->lockdep_map);
 	lock_map_release(&wq->lockdep_map);
 
@@ -2843,6 +2848,9 @@ bool flush_work(struct work_struct *work)
 {
 	struct wq_barrier barr;
 
+	if (WARN_ON(!wq_online))
+		return false;
+
 	lock_map_acquire(&work->lockdep_map);
 	lock_map_release(&work->lockdep_map);
 
@@ -2913,7 +2921,13 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 	mark_work_canceling(work);
 	local_irq_restore(flags);
 
-	flush_work(work);
+	/*
+	 * This allows canceling during early boot.  We know that @work
+	 * isn't executing.
+	 */
+	if (wq_online)
+		flush_work(work);
+
 	clear_work_data(work);
 
 	/*
@@ -3352,7 +3366,7 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs)
 		goto fail;
 
 	/* create and start the initial worker */
-	if (!create_worker(pool))
+	if (wq_online && !create_worker(pool))
 		goto fail;
 
 	/* install */
@@ -3417,6 +3431,7 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq)
 {
 	struct workqueue_struct *wq = pwq->wq;
 	bool freezable = wq->flags & WQ_FREEZABLE;
+	unsigned long flags;
 
 	/* for @wq->saved_max_active */
 	lockdep_assert_held(&wq->mutex);
@@ -3425,7 +3440,8 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq)
 	if (!freezable && pwq->max_active == wq->saved_max_active)
 		return;
 
-	spin_lock_irq(&pwq->pool->lock);
+	/* this function can be called during early boot w/ irq disabled */
+	spin_lock_irqsave(&pwq->pool->lock, flags);
 
 	/*
 	 * During [un]freezing, the caller is responsible for ensuring that
@@ -3448,7 +3464,7 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq)
 		pwq->max_active = 0;
 	}
 
-	spin_unlock_irq(&pwq->pool->lock);
+	spin_unlock_irqrestore(&pwq->pool->lock, flags);
 }
 
 /* initialize newly alloced @pwq which is associated with @wq and @pool */
@@ -5455,7 +5471,17 @@ static void __init wq_numa_init(void)
 	wq_numa_enabled = true;
 }
 
-static int __init init_workqueues(void)
+/**
+ * workqueue_init_early - early init for workqueue subsystem
+ *
+ * This is the first half of two-staged workqueue subsystem initialization
+ * and invoked as soon as the bare basics - memory allocation, cpumasks and
+ * idr are up.  It sets up all the data structures and system workqueues
+ * and allows early boot code to create workqueues and queue/cancel work
+ * items.  Actual work item execution starts only after kthreads can be
+ * created and scheduled right before early initcalls.
+ */
+int __init workqueue_init_early(void)
 {
 	int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
 	int i, cpu;
@@ -5488,16 +5514,6 @@ static int __init init_workqueues(void)
 		}
 	}
 
-	/* create the initial worker */
-	for_each_online_cpu(cpu) {
-		struct worker_pool *pool;
-
-		for_each_cpu_worker_pool(pool, cpu) {
-			pool->flags &= ~POOL_DISASSOCIATED;
-			BUG_ON(!create_worker(pool));
-		}
-	}
-
 	/* create default unbound and ordered wq attrs */
 	for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
 		struct workqueue_attrs *attrs;
@@ -5538,4 +5554,33 @@ static int __init init_workqueues(void)
 
 	return 0;
 }
-early_initcall(init_workqueues);
+
+/**
+ * workqueue_init - bring workqueue subsystem fully online
+ *
+ * This is the latter half of two-staged workqueue subsystem initialization
+ * and invoked as soon as kthreads can be created and scheduled.
+ * Workqueues have been created and work items queued on them, but there
+ * are no kworkers executing the work items yet.  Populate the worker pools
+ * with the initial workers and enable future kworker creations.
+ */
+int __init workqueue_init(void)
+{
+	struct worker_pool *pool;
+	int cpu, bkt;
+
+	/* create the initial workers */
+	for_each_online_cpu(cpu) {
+		for_each_cpu_worker_pool(pool, cpu) {
+			pool->flags &= ~POOL_DISASSOCIATED;
+			BUG_ON(!create_worker(pool));
+		}
+	}
+
+	hash_for_each(unbound_pool_hash, bkt, pool, hash_node)
+		BUG_ON(!create_worker(pool));
+
+	wq_online = true;
+
+	return 0;
+}
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1485579 — [PATCH v2 1/7] workqueue: make workqueue available early during boot

FromTejun Heo <tj@kernel.org>
Date2016-09-17 19:30 +0200
Subject[PATCH v2 1/7] workqueue: make workqueue available early during boot
Message-ID<sirB7-5py-13@gated-at.bofh.it>
In reply to#1484501
From f85002f627f7fdc7b3cda526863f5c9a8d36b997 Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Fri, 16 Sep 2016 15:49:32 -0400
Subject: [PATCH] workqueue: make workqueue available early during boot

Workqueue is currently initialized in an early init call; however,
there are cases where early boot code has to be split and reordered to
come after workqueue initialization or the same code path which makes
use of workqueues is used both before workqueue initailization and
after.  The latter cases have to gate workqueue usages with
keventd_up() tests, which is nasty and easy to get wrong.

Workqueue usages have become widespread and it'd be a lot more
convenient if it can be used very early from boot.  This patch splits
workqueue initialization into two steps.  workqueue_init_early() which
sets up the basic data structures so that workqueues can be created
and work items queued, and workqueue_init() which actually brings up
workqueues online and starts executing queued work items.  The former
step can be done very early during boot once memory allocation,
cpumasks and idr are initialized.  The latter right after kthreads
become available.

This allows work item queueing and canceling from very early boot
which is what most of these use cases want.

* As systemd_wq being initialized doesn't indicate that workqueue is
  fully online anymore, update keventd_up() to test wq_online instead.
  The follow-up patches will get rid of all its usages and the
  function itself.

* Flushing doesn't make sense before workqueue is fully initialized.
  The flush functions trigger WARN and return immediately before fully
  online.

* Work items are never in-flight before fully online.  Canceling can
  always succeed by skipping the flush step.

* Some code paths can no longer assume to be called with irq enabled
  as irq is disabled during early boot.  Use irqsave/restore
  operations instead.

v2: Watchdog init, which requires timer to be running, moved from
    workqueue_init_early() to workqueue_init().

Signed-off-by: Tejun Heo <tj@kernel.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/CA+55aFx0vPuMuxn00rBSM192n-Du5uxy+4AvKa0SBSOVJeuCGg@mail.gmail.com
---
Hello,

0day bot detected warning during boot due to workqueue hang watchdog
being initialized before timer subsystem is online.  Moved watchdog
init to late init.

Thanks.

 include/linux/workqueue.h |    7 +++-
 init/main.c               |   10 ++++++
 kernel/workqueue.c        |   76 ++++++++++++++++++++++++++++++++++++----------
 3 files changed, 76 insertions(+), 17 deletions(-)

--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -358,6 +358,8 @@ extern struct workqueue_struct *system_f
 extern struct workqueue_struct *system_power_efficient_wq;
 extern struct workqueue_struct *system_freezable_power_efficient_wq;
 
+extern bool wq_online;
+
 extern struct workqueue_struct *
 __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
 	struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6);
@@ -594,7 +596,7 @@ static inline bool schedule_delayed_work
  */
 static inline bool keventd_up(void)
 {
-	return system_wq != NULL;
+	return wq_online;
 }
 
 #ifndef CONFIG_SMP
@@ -631,4 +633,7 @@ int workqueue_online_cpu(unsigned int cp
 int workqueue_offline_cpu(unsigned int cpu);
 #endif
 
+int __init workqueue_init_early(void);
+int __init workqueue_init(void);
+
 #endif
--- a/init/main.c
+++ b/init/main.c
@@ -551,6 +551,14 @@ asmlinkage __visible void __init start_k
 		 "Interrupts were enabled *very* early, fixing it\n"))
 		local_irq_disable();
 	idr_init_cache();
+
+	/*
+	 * Allow workqueue creation and work item queueing/cancelling
+	 * early.  Work item execution depends on kthreads and starts after
+	 * workqueue_init().
+	 */
+	workqueue_init_early();
+
 	rcu_init();
 
 	/* trace_printk() and trace points may be used after this */
@@ -1005,6 +1013,8 @@ static noinline void __init kernel_init_
 
 	smp_prepare_cpus(setup_max_cpus);
 
+	workqueue_init();
+
 	do_pre_smp_initcalls();
 	lockup_detector_init();
 
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -290,6 +290,8 @@ module_param_named(disable_numa, wq_disa
 static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT);
 module_param_named(power_efficient, wq_power_efficient, bool, 0444);
 
+bool wq_online;				/* can kworkers be created yet? */
+
 static bool wq_numa_enabled;		/* unbound NUMA affinity enabled */
 
 /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */
@@ -2583,6 +2585,9 @@ void flush_workqueue(struct workqueue_st
 	};
 	int next_color;
 
+	if (WARN_ON(!wq_online))
+		return;
+
 	lock_map_acquire(&wq->lockdep_map);
 	lock_map_release(&wq->lockdep_map);
 
@@ -2843,6 +2848,9 @@ bool flush_work(struct work_struct *work
 {
 	struct wq_barrier barr;
 
+	if (WARN_ON(!wq_online))
+		return false;
+
 	lock_map_acquire(&work->lockdep_map);
 	lock_map_release(&work->lockdep_map);
 
@@ -2913,7 +2921,13 @@ static bool __cancel_work_timer(struct w
 	mark_work_canceling(work);
 	local_irq_restore(flags);
 
-	flush_work(work);
+	/*
+	 * This allows canceling during early boot.  We know that @work
+	 * isn't executing.
+	 */
+	if (wq_online)
+		flush_work(work);
+
 	clear_work_data(work);
 
 	/*
@@ -3352,7 +3366,7 @@ static struct worker_pool *get_unbound_p
 		goto fail;
 
 	/* create and start the initial worker */
-	if (!create_worker(pool))
+	if (wq_online && !create_worker(pool))
 		goto fail;
 
 	/* install */
@@ -3417,6 +3431,7 @@ static void pwq_adjust_max_active(struct
 {
 	struct workqueue_struct *wq = pwq->wq;
 	bool freezable = wq->flags & WQ_FREEZABLE;
+	unsigned long flags;
 
 	/* for @wq->saved_max_active */
 	lockdep_assert_held(&wq->mutex);
@@ -3425,7 +3440,8 @@ static void pwq_adjust_max_active(struct
 	if (!freezable && pwq->max_active == wq->saved_max_active)
 		return;
 
-	spin_lock_irq(&pwq->pool->lock);
+	/* this function can be called during early boot w/ irq disabled */
+	spin_lock_irqsave(&pwq->pool->lock, flags);
 
 	/*
 	 * During [un]freezing, the caller is responsible for ensuring that
@@ -3448,7 +3464,7 @@ static void pwq_adjust_max_active(struct
 		pwq->max_active = 0;
 	}
 
-	spin_unlock_irq(&pwq->pool->lock);
+	spin_unlock_irqrestore(&pwq->pool->lock, flags);
 }
 
 /* initialize newly alloced @pwq which is associated with @wq and @pool */
@@ -5455,7 +5471,17 @@ static void __init wq_numa_init(void)
 	wq_numa_enabled = true;
 }
 
-static int __init init_workqueues(void)
+/**
+ * workqueue_init_early - early init for workqueue subsystem
+ *
+ * This is the first half of two-staged workqueue subsystem initialization
+ * and invoked as soon as the bare basics - memory allocation, cpumasks and
+ * idr are up.  It sets up all the data structures and system workqueues
+ * and allows early boot code to create workqueues and queue/cancel work
+ * items.  Actual work item execution starts only after kthreads can be
+ * created and scheduled right before early initcalls.
+ */
+int __init workqueue_init_early(void)
 {
 	int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
 	int i, cpu;
@@ -5488,16 +5514,6 @@ static int __init init_workqueues(void)
 		}
 	}
 
-	/* create the initial worker */
-	for_each_online_cpu(cpu) {
-		struct worker_pool *pool;
-
-		for_each_cpu_worker_pool(pool, cpu) {
-			pool->flags &= ~POOL_DISASSOCIATED;
-			BUG_ON(!create_worker(pool));
-		}
-	}
-
 	/* create default unbound and ordered wq attrs */
 	for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
 		struct workqueue_attrs *attrs;
@@ -5534,8 +5550,36 @@ static int __init init_workqueues(void)
 	       !system_power_efficient_wq ||
 	       !system_freezable_power_efficient_wq);
 
+	return 0;
+}
+
+/**
+ * workqueue_init - bring workqueue subsystem fully online
+ *
+ * This is the latter half of two-staged workqueue subsystem initialization
+ * and invoked as soon as kthreads can be created and scheduled.
+ * Workqueues have been created and work items queued on them, but there
+ * are no kworkers executing the work items yet.  Populate the worker pools
+ * with the initial workers and enable future kworker creations.
+ */
+int __init workqueue_init(void)
+{
+	struct worker_pool *pool;
+	int cpu, bkt;
+
+	/* create the initial workers */
+	for_each_online_cpu(cpu) {
+		for_each_cpu_worker_pool(pool, cpu) {
+			pool->flags &= ~POOL_DISASSOCIATED;
+			BUG_ON(!create_worker(pool));
+		}
+	}
+
+	hash_for_each(unbound_pool_hash, bkt, pool, hash_node)
+		BUG_ON(!create_worker(pool));
+
+	wq_online = true;
 	wq_watchdog_init();
 
 	return 0;
 }
-early_initcall(init_workqueues);

[toc] | [prev] | [next] | [standalone]


#1484510 — Re: [PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot

FromLinus Torvalds <torvalds@linux-foundation.org>
Date2016-09-15 22:00 +0200
SubjectRe: [PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot
Message-ID<shKZb-2PE-5@gated-at.bofh.it>
In reply to#1484494
On Thu, Sep 15, 2016 at 12:30 PM, Tejun Heo <tj@kernel.org> wrote:
>
> This patchset makes workqueue creation and work item
> queueing/canceling available from very early during boot which allows
> all existing usages of keventd_up() which is removed by the last
> patch.

Looks good to me. I didn't *test* it, just looking at the patches..

               Linus

[toc] | [prev] | [next] | [standalone]


#1485292 — Re: [PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot

FromTejun Heo <tj@kernel.org>
Date2016-09-16 22:00 +0200
SubjectRe: [PATCHSET wq/for-4.9] workqueue: make workqueue available very early during boot
Message-ID<si7sJ-Kc-17@gated-at.bofh.it>
In reply to#1484494
On Thu, Sep 15, 2016 at 03:30:14PM -0400, Tejun Heo wrote:
> This patchset contains the following seven patches.
> 
>  0001-workqueue-make-workqueue-available-early-during-boot.patch
>  0002-mce-workqueue-remove-keventd_up-usage.patch
>  0003-tty-workqueue-remove-keventd_up-usage.patch
>  0004-power-workqueue-remove-keventd_up-usage.patch
>  0005-slab-workqueue-remove-keventd_up-usage.patch
>  0006-debugobj-workqueue-remove-keventd_up-usage.patch
>  0007-workqueue-remove-keventd_up.patch

Applied 1-7 to wq/for-4.9.

Thanks.

-- 
tejun

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web