Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1344561 > unrolled thread
| Started by | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| First post | 2016-02-26 19:50 +0100 |
| Last post | 2016-02-29 21:10 +0100 |
| Articles | 20 on this page of 55 — 8 participants |
Back to article view | Back to linux.kernel
[patch 00/20] cpu/hotplug: Core infrastructure for cpu hotplug rework Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[patch 14/20] cpu/hotplug: Split out the state walk into functions Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Split out the state walk into functions tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 17/20] arch/hotplug: Call into idle with a proper state Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] arch/hotplug: Call into idle with a proper state tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 04/20] cpu/hotplug: Split out cpu down functions Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Split out cpu down functions tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Split out cpu down functions "Srivatsa S. Bhat" <srivatsa@csail.mit.edu> - 2016-03-03 00:10 +0100
[patch 03/20] cpu/hotplug: Restructure cpu_up code Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Restructure cpu_up code tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Restructure cpu_up code "Srivatsa S. Bhat" <srivatsa@csail.mit.edu> - 2016-03-03 00:00 +0100
[patch 16/20] cpu/hotplug: Move online calls to hotplugged cpu Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Move online calls to hotplugged cpu tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 02/20] cpu/hotplug: Restructure FROZEN state handling Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Restructure FROZEN state handling tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Restructure FROZEN state handling "Srivatsa S. Bhat" <srivatsa@csail.mit.edu> - 2016-03-03 00:10 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Restructure FROZEN state handling "Srivatsa S. Bhat" <srivatsa@csail.mit.edu> - 2016-03-03 00:50 +0100
[patch 11/20] cpu/hotplug: Implement setup/removal interface Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Implement setup/removal interface tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 12/20] cpu/hotplug: Move scheduler cpu_online notifier to hotplug core Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Move scheduler cpu_online notifier to hotplug core tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 18/20] cpu/hotplug: Let upcoming cpu bring itself fully up Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Let upcoming cpu bring itself fully up tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [patch 18/20] cpu/hotplug: Let upcoming cpu bring itself fully up Richard Cochran <richardcochran@gmail.com> - 2016-03-02 18:30 +0100
[patch 15/20] cpu/hotplug: Create hotplug threads Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Create hotplug threads tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 09/20] cpu/hotplug: Add sysfs state interface Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Add sysfs state interface tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Add sysfs state interface Peter Zijlstra <peterz@infradead.org> - 2016-03-02 13:50 +0100
[patch 06/20] cpu/hotplug: Convert to a state machine for the control processor Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Convert to a state machine for the control processor tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Convert to a state machine for the control processor Peter Zijlstra <peterz@infradead.org> - 2016-03-02 12:30 +0100
[patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-02-27 03:20 +0100
Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-02-27 03:30 +0100
Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call Thomas Gleixner <tglx@linutronix.de> - 2016-02-27 08:50 +0100
Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-02-27 12:10 +0100
Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call Thomas Gleixner <tglx@linutronix.de> - 2016-02-27 12:40 +0100
Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-02-27 17:40 +0100
[tip:smp/hotplug] rcu: Make CPU_DYING_IDLE an explicit call tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
Re: [tip:smp/hotplug] rcu: Make CPU_DYING_IDLE an explicit call "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-03-02 21:20 +0100
Re: [tip:smp/hotplug] rcu: Make CPU_DYING_IDLE an explicit call Thomas Gleixner <tglx@linutronix.de> - 2016-03-03 08:40 +0100
[tip:smp/hotplug] cpu/hotplug: Plug death reporting race tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-03 11:10 +0100
Re: [tip:smp/hotplug] cpu/hotplug: Plug death reporting race "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-03-03 15:20 +0100
[patch 08/20] cpu/hotplug: Hand in target state to _cpu_up/down Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Hand in target state to _cpu_up/down tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 19/20] cpu/hotplug: Make wait for dead cpu completion based Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 19:50 +0100
[tip:smp/hotplug] cpu/hotplug: Make wait for dead cpu completion based tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 07/20] cpu/hotplug: Convert the hotplugged cpu work to a state machine Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 20:00 +0100
[tip:smp/hotplug] cpu/hotplug: Convert the hotplugged cpu work to a state machine tip-bot for Thomas Gleixner <tipbot@zytor.com> - 2016-03-01 21:00 +0100
[patch 01/20] idle: Move x86ism out of generic code Thomas Gleixner <tglx@linutronix.de> - 2016-02-26 20:00 +0100
Re: [patch 01/20] idle: Move x86ism out of generic code Brian Gerst <brgerst@gmail.com> - 2016-02-27 21:30 +0100
Re: [patch 01/20] idle: Move x86ism out of generic code Thomas Gleixner <tglx@linutronix.de> - 2016-02-29 20:40 +0100
Re: [patch 01/20] idle: Move x86ism out of generic code Will Deacon <will.deacon@arm.com> - 2016-02-29 20:50 +0100
Re: [patch 01/20] idle: Move x86ism out of generic code Thomas Gleixner <tglx@linutronix.de> - 2016-02-29 21:10 +0100
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | tip-bot for Thomas Gleixner <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-01 21:00 +0100 |
| Subject | [tip:smp/hotplug] cpu/hotplug: Move scheduler cpu_online notifier to hotplug core |
| Message-ID | <r7YCC-5hG-13@gated-at.bofh.it> |
| In reply to | #1344569 |
Commit-ID: 949338e35131c551f7bf54f48a2e3a227af6721b
Gitweb: http://git.kernel.org/tip/949338e35131c551f7bf54f48a2e3a227af6721b
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Fri, 26 Feb 2016 18:43:35 +0000
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 1 Mar 2016 20:36:55 +0100
cpu/hotplug: Move scheduler cpu_online notifier to hotplug core
Move the scheduler cpu online notifier part to the hotplug core. This is
anyway the highest priority callback and we need that functionality right now
for the next changes.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: Rik van Riel <riel@redhat.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20160226182341.200791046@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpuhotplug.h | 1 +
kernel/cpu.c | 18 ++++++++++++++++++
kernel/sched/core.c | 10 ----------
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 2993526..2f2e5d9 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -10,6 +10,7 @@ enum cpuhp_state {
CPUHP_AP_NOTIFY_STARTING,
CPUHP_AP_ONLINE,
CPUHP_TEARDOWN_CPU,
+ CPUHP_CPU_SET_ACTIVE,
CPUHP_NOTIFY_ONLINE,
CPUHP_ONLINE_DYN,
CPUHP_ONLINE_DYN_END = CPUHP_ONLINE_DYN + 30,
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b5eacb9..65e34d3 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -666,6 +666,19 @@ void notify_cpu_starting(unsigned int cpu)
}
}
+/*
+ * Called from the idle task. We need to set active here, so we can kick off
+ * the stopper thread.
+ */
+static int cpuhp_set_cpu_active(unsigned int cpu)
+{
+ /* The cpu is marked online, set it active now */
+ set_cpu_active(cpu, true);
+ /* Unpark the stopper thread */
+ stop_machine_unpark(cpu);
+ return 0;
+}
+
static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
{
for (st->state--; st->state > st->target; st->state--) {
@@ -941,6 +954,11 @@ static struct cpuhp_step cpuhp_bp_states[] = {
.teardown = takedown_cpu,
.cant_stop = true,
},
+ [CPUHP_CPU_SET_ACTIVE] = {
+ .name = "cpu:active",
+ .startup = cpuhp_set_cpu_active,
+ .teardown = NULL,
+ },
[CPUHP_NOTIFY_ONLINE] = {
.name = "notify:online",
.startup = notify_online,
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 9503d59..6266463 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5692,16 +5692,6 @@ static int sched_cpu_active(struct notifier_block *nfb,
set_cpu_rq_start_time();
return NOTIFY_OK;
- case CPU_ONLINE:
- /*
- * At this point a starting CPU has marked itself as online via
- * set_cpu_online(). But it might not yet have marked itself
- * as active, which is essential from here on.
- */
- set_cpu_active(cpu, true);
- stop_machine_unpark(cpu);
- return NOTIFY_OK;
-
case CPU_DOWN_FAILED:
set_cpu_active(cpu, true);
return NOTIFY_OK;
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-26 19:50 +0100 |
| Subject | [patch 18/20] cpu/hotplug: Let upcoming cpu bring itself fully up |
| Message-ID | <r6vCH-7sv-35@gated-at.bofh.it> |
| In reply to | #1344561 |
Let the upcoming cpu kick the hotplug thread and let itself complete the
bringup. That way the controll side can just wait for the completion or later
when we made the hotplug machinery async not care at all.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpuhotplug.h | 9 ++++--
kernel/cpu.c | 66 +++++++++++++++++++++++++--------------------
kernel/sched/idle.c | 2 +
3 files changed, 45 insertions(+), 32 deletions(-)
Index: b/include/linux/cpuhotplug.h
===================================================================
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -10,9 +10,6 @@ enum cpuhp_state {
CPUHP_AP_NOTIFY_STARTING,
CPUHP_AP_ONLINE,
CPUHP_TEARDOWN_CPU,
- CPUHP_CPU_SET_ACTIVE,
- CPUHP_KICK_AP_THREAD,
- CPUHP_BP_ONLINE,
CPUHP_AP_ONLINE_IDLE,
CPUHP_AP_SMPBOOT_THREADS,
CPUHP_AP_NOTIFY_ONLINE,
@@ -86,4 +83,10 @@ static inline void cpuhp_remove_state_no
__cpuhp_remove_state(state, false);
}
+#ifdef CONFIG_SMP
+void cpuhp_online_idle(enum cpuhp_state state);
+#else
+static inline void cpuhp_online_idle(enum cpuhp_state state) { }
+#endif
+
#endif
Index: b/kernel/cpu.c
===================================================================
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -329,6 +329,14 @@ static int notify_starting(unsigned int
return 0;
}
+static int bringup_wait_for_ap(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+ wait_for_completion(&st->done);
+ return st->result;
+}
+
static int bringup_cpu(unsigned int cpu)
{
struct task_struct *idle = idle_thread_get(cpu);
@@ -340,8 +348,9 @@ static int bringup_cpu(unsigned int cpu)
cpu_notify(CPU_UP_CANCELED, cpu);
return ret;
}
+ ret = bringup_wait_for_ap(cpu);
BUG_ON(!cpu_online(cpu));
- return 0;
+ return ret;
}
/*
@@ -470,7 +479,7 @@ static void cpuhp_thread_fun(unsigned in
}
} else {
/* Cannot happen .... */
- BUG_ON(st->state < CPUHP_KICK_AP_THREAD);
+ BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
/* Regular hotplug work */
if (st->state < st->target)
@@ -780,7 +789,7 @@ static int __ref _cpu_down(unsigned int
* If the current CPU state is in the range of the AP hotplug thread,
* then we need to kick the thread.
*/
- if (st->state >= CPUHP_KICK_AP_THREAD) {
+ if (st->state > CPUHP_TEARDOWN_CPU) {
ret = cpuhp_kick_ap_work(cpu);
/*
* The AP side has done the error rollback already. Just
@@ -793,11 +802,11 @@ static int __ref _cpu_down(unsigned int
* We might have stopped still in the range of the AP hotplug
* thread. Nothing to do anymore.
*/
- if (st->state >= CPUHP_KICK_AP_THREAD)
+ if (st->state > CPUHP_TEARDOWN_CPU)
goto out;
}
/*
- * The AP brought itself down below CPUHP_KICK_AP_THREAD. So we need
+ * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need
* to do the further cleanups.
*/
ret = cpuhp_down_callbacks(cpu, st, cpuhp_bp_states, target);
@@ -859,18 +868,32 @@ void notify_cpu_starting(unsigned int cp
/*
* Called from the idle task. We need to set active here, so we can kick off
- * the stopper thread.
+ * the stopper thread and unpark the smpboot threads. If the target state is
+ * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the
+ * cpu further.
*/
-static int cpuhp_set_cpu_active(unsigned int cpu)
+void cpuhp_online_idle(enum cpuhp_state state)
{
- struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+ unsigned int cpu = smp_processor_id();
+
+ /* Happens for the boot cpu */
+ if (state != CPUHP_AP_ONLINE_IDLE)
+ return;
+
+ st->state = CPUHP_AP_ONLINE_IDLE;
/* The cpu is marked online, set it active now */
set_cpu_active(cpu, true);
- /* Unpark the stopper thread and the hotplug thread */
+ /* Unpark the stopper thread and the hotplug thread of this cpu */
stop_machine_unpark(cpu);
kthread_unpark(st->thread);
- return 0;
+
+ /* Should we go further up ? */
+ if (st->target > CPUHP_AP_ONLINE_IDLE)
+ __cpuhp_kick_ap_work(st);
+ else
+ complete(&st->done);
}
/* Requires cpu_add_remove_lock to be held */
@@ -910,7 +933,7 @@ static int _cpu_up(unsigned int cpu, int
* If the current CPU state is in the range of the AP hotplug thread,
* then we need to kick the thread once more.
*/
- if (st->state >= CPUHP_KICK_AP_THREAD) {
+ if (st->state > CPUHP_BRINGUP_CPU) {
ret = cpuhp_kick_ap_work(cpu);
/*
* The AP side has done the error rollback already. Just
@@ -922,10 +945,10 @@ static int _cpu_up(unsigned int cpu, int
/*
* Try to reach the target state. We max out on the BP at
- * CPUHP_KICK_AP_THREAD. After that the AP hotplug thread is
+ * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is
* responsible for bringing it up to the target state.
*/
- target = min((int)target, CPUHP_KICK_AP_THREAD);
+ target = min((int)target, CPUHP_BRINGUP_CPU);
ret = cpuhp_up_callbacks(cpu, st, cpuhp_bp_states, target);
out:
cpu_hotplug_done();
@@ -1146,22 +1169,7 @@ static struct cpuhp_step cpuhp_bp_states
.teardown = takedown_cpu,
.cant_stop = true,
},
- [CPUHP_CPU_SET_ACTIVE] = {
- .name = "cpu:active",
- .startup = cpuhp_set_cpu_active,
- .teardown = NULL,
- },
- [CPUHP_KICK_AP_THREAD] = {
- .name = "cpuhp:kickthread",
- .startup = cpuhp_kick_ap_work,
- .teardown = cpuhp_kick_ap_work,
- },
#endif
- [CPUHP_BP_ONLINE] = {
- .name = "online",
- .startup = NULL,
- .teardown = NULL,
- },
};
/* Application processor state steps */
@@ -1204,7 +1212,7 @@ static bool cpuhp_is_ap_state(enum cpuhp
{
if (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE)
return true;
- return state > CPUHP_BP_ONLINE;
+ return state > CPUHP_BRINGUP_CPU;
}
static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
Index: b/kernel/sched/idle.c
===================================================================
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -4,6 +4,7 @@
#include <linux/sched.h>
#include <linux/cpu.h>
#include <linux/cpuidle.h>
+#include <linux/cpuhotplug.h>
#include <linux/tick.h>
#include <linux/mm.h>
#include <linux/stackprotector.h>
@@ -276,5 +277,6 @@ static void cpu_idle_loop(void)
void cpu_startup_entry(enum cpuhp_state state)
{
arch_cpu_idle_prepare();
+ cpuhp_online_idle(state);
cpu_idle_loop();
}
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Thomas Gleixner <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-01 21:00 +0100 |
| Subject | [tip:smp/hotplug] cpu/hotplug: Let upcoming cpu bring itself fully up |
| Message-ID | <r7YCE-5hG-51@gated-at.bofh.it> |
| In reply to | #1344570 |
Commit-ID: 8df3e07e7f21f2ed8d001e6fabf9505946b438aa
Gitweb: http://git.kernel.org/tip/8df3e07e7f21f2ed8d001e6fabf9505946b438aa
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Fri, 26 Feb 2016 18:43:41 +0000
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 1 Mar 2016 20:36:57 +0100
cpu/hotplug: Let upcoming cpu bring itself fully up
Let the upcoming cpu kick the hotplug thread and let itself complete the
bringup. That way the controll side can just wait for the completion or later
when we made the hotplug machinery async not care at all.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: Rik van Riel <riel@redhat.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20160226182341.697655464@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpuhotplug.h | 9 ++++---
kernel/cpu.c | 66 ++++++++++++++++++++++++++--------------------
kernel/sched/idle.c | 2 ++
3 files changed, 45 insertions(+), 32 deletions(-)
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 4aa263a..ad5d7fc 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -10,9 +10,6 @@ enum cpuhp_state {
CPUHP_AP_NOTIFY_STARTING,
CPUHP_AP_ONLINE,
CPUHP_TEARDOWN_CPU,
- CPUHP_CPU_SET_ACTIVE,
- CPUHP_KICK_AP_THREAD,
- CPUHP_BP_ONLINE,
CPUHP_AP_ONLINE_IDLE,
CPUHP_AP_SMPBOOT_THREADS,
CPUHP_AP_NOTIFY_ONLINE,
@@ -86,4 +83,10 @@ static inline void cpuhp_remove_state_nocalls(enum cpuhp_state state)
__cpuhp_remove_state(state, false);
}
+#ifdef CONFIG_SMP
+void cpuhp_online_idle(enum cpuhp_state state);
+#else
+static inline void cpuhp_online_idle(enum cpuhp_state state) { }
+#endif
+
#endif
diff --git a/kernel/cpu.c b/kernel/cpu.c
index e220e56..f1f880f 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -329,6 +329,14 @@ static int notify_starting(unsigned int cpu)
return 0;
}
+static int bringup_wait_for_ap(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+ wait_for_completion(&st->done);
+ return st->result;
+}
+
static int bringup_cpu(unsigned int cpu)
{
struct task_struct *idle = idle_thread_get(cpu);
@@ -340,8 +348,9 @@ static int bringup_cpu(unsigned int cpu)
cpu_notify(CPU_UP_CANCELED, cpu);
return ret;
}
+ ret = bringup_wait_for_ap(cpu);
BUG_ON(!cpu_online(cpu));
- return 0;
+ return ret;
}
/*
@@ -470,7 +479,7 @@ static void cpuhp_thread_fun(unsigned int cpu)
}
} else {
/* Cannot happen .... */
- BUG_ON(st->state < CPUHP_KICK_AP_THREAD);
+ BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
/* Regular hotplug work */
if (st->state < st->target)
@@ -780,7 +789,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
* If the current CPU state is in the range of the AP hotplug thread,
* then we need to kick the thread.
*/
- if (st->state >= CPUHP_KICK_AP_THREAD) {
+ if (st->state > CPUHP_TEARDOWN_CPU) {
ret = cpuhp_kick_ap_work(cpu);
/*
* The AP side has done the error rollback already. Just
@@ -793,11 +802,11 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
* We might have stopped still in the range of the AP hotplug
* thread. Nothing to do anymore.
*/
- if (st->state >= CPUHP_KICK_AP_THREAD)
+ if (st->state > CPUHP_TEARDOWN_CPU)
goto out;
}
/*
- * The AP brought itself down below CPUHP_KICK_AP_THREAD. So we need
+ * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need
* to do the further cleanups.
*/
ret = cpuhp_down_callbacks(cpu, st, cpuhp_bp_states, target);
@@ -859,18 +868,32 @@ void notify_cpu_starting(unsigned int cpu)
/*
* Called from the idle task. We need to set active here, so we can kick off
- * the stopper thread.
+ * the stopper thread and unpark the smpboot threads. If the target state is
+ * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the
+ * cpu further.
*/
-static int cpuhp_set_cpu_active(unsigned int cpu)
+void cpuhp_online_idle(enum cpuhp_state state)
{
- struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+ unsigned int cpu = smp_processor_id();
+
+ /* Happens for the boot cpu */
+ if (state != CPUHP_AP_ONLINE_IDLE)
+ return;
+
+ st->state = CPUHP_AP_ONLINE_IDLE;
/* The cpu is marked online, set it active now */
set_cpu_active(cpu, true);
- /* Unpark the stopper thread and the hotplug thread */
+ /* Unpark the stopper thread and the hotplug thread of this cpu */
stop_machine_unpark(cpu);
kthread_unpark(st->thread);
- return 0;
+
+ /* Should we go further up ? */
+ if (st->target > CPUHP_AP_ONLINE_IDLE)
+ __cpuhp_kick_ap_work(st);
+ else
+ complete(&st->done);
}
/* Requires cpu_add_remove_lock to be held */
@@ -910,7 +933,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
* If the current CPU state is in the range of the AP hotplug thread,
* then we need to kick the thread once more.
*/
- if (st->state >= CPUHP_KICK_AP_THREAD) {
+ if (st->state > CPUHP_BRINGUP_CPU) {
ret = cpuhp_kick_ap_work(cpu);
/*
* The AP side has done the error rollback already. Just
@@ -922,10 +945,10 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
/*
* Try to reach the target state. We max out on the BP at
- * CPUHP_KICK_AP_THREAD. After that the AP hotplug thread is
+ * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is
* responsible for bringing it up to the target state.
*/
- target = min((int)target, CPUHP_KICK_AP_THREAD);
+ target = min((int)target, CPUHP_BRINGUP_CPU);
ret = cpuhp_up_callbacks(cpu, st, cpuhp_bp_states, target);
out:
cpu_hotplug_done();
@@ -1146,22 +1169,7 @@ static struct cpuhp_step cpuhp_bp_states[] = {
.teardown = takedown_cpu,
.cant_stop = true,
},
- [CPUHP_CPU_SET_ACTIVE] = {
- .name = "cpu:active",
- .startup = cpuhp_set_cpu_active,
- .teardown = NULL,
- },
- [CPUHP_KICK_AP_THREAD] = {
- .name = "cpuhp:kickthread",
- .startup = cpuhp_kick_ap_work,
- .teardown = cpuhp_kick_ap_work,
- },
#endif
- [CPUHP_BP_ONLINE] = {
- .name = "online",
- .startup = NULL,
- .teardown = NULL,
- },
};
/* Application processor state steps */
@@ -1204,7 +1212,7 @@ static bool cpuhp_is_ap_state(enum cpuhp_state state)
{
if (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE)
return true;
- return state > CPUHP_BP_ONLINE;
+ return state > CPUHP_BRINGUP_CPU;
}
static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 544a713..a4b9813 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -4,6 +4,7 @@
#include <linux/sched.h>
#include <linux/cpu.h>
#include <linux/cpuidle.h>
+#include <linux/cpuhotplug.h>
#include <linux/tick.h>
#include <linux/mm.h>
#include <linux/stackprotector.h>
@@ -291,5 +292,6 @@ void cpu_startup_entry(enum cpuhp_state state)
boot_init_stack_canary();
#endif
arch_cpu_idle_prepare();
+ cpuhp_online_idle(state);
cpu_idle_loop();
}
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-03-02 18:30 +0100 |
| Subject | Re: [patch 18/20] cpu/hotplug: Let upcoming cpu bring itself fully up |
| Message-ID | <r8iL1-2in-27@gated-at.bofh.it> |
| In reply to | #1344570 |
On Fri, Feb 26, 2016 at 06:43:41PM -0000, Thomas Gleixner wrote:
> @@ -1204,7 +1212,7 @@ static bool cpuhp_is_ap_state(enum cpuhp
> {
> if (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE)
> return true;
FWIW, this test is superfluous after this change, because
CPUHP_BRINGUP_CPU is less than CPUHP_AP_OFFLINE.
> - return state > CPUHP_BP_ONLINE;
> + return state > CPUHP_BRINGUP_CPU;
> }
Thanks,
Richard
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-26 19:50 +0100 |
| Subject | [patch 15/20] cpu/hotplug: Create hotplug threads |
| Message-ID | <r6vCH-7sv-41@gated-at.bofh.it> |
| In reply to | #1344561 |
In order to let the hotplugged cpu take care of the setup/teardown, we need a
seperate hotplug thread.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/cpu.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
kernel/smp.c | 1
kernel/smpboot.h | 2
3 files changed, 147 insertions(+), 1 deletion(-)
Index: b/kernel/cpu.c
===================================================================
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -22,6 +22,7 @@
#include <linux/lockdep.h>
#include <linux/tick.h>
#include <linux/irq.h>
+#include <linux/smpboot.h>
#include <trace/events/power.h>
#define CREATE_TRACE_POINTS
@@ -33,10 +34,24 @@
* cpuhp_cpu_state - Per cpu hotplug state storage
* @state: The current cpu state
* @target: The target state
+ * @thread: Pointer to the hotplug thread
+ * @should_run: Thread should execute
+ * @cb_stat: The state for a single callback (install/uninstall)
+ * @cb: Single callback function (install/uninstall)
+ * @result: Result of the operation
+ * @done: Signal completion to the issuer of the task
*/
struct cpuhp_cpu_state {
enum cpuhp_state state;
enum cpuhp_state target;
+#ifdef CONFIG_SMP
+ struct task_struct *thread;
+ bool should_run;
+ enum cpuhp_state cb_state;
+ int (*cb)(unsigned int cpu);
+ int result;
+ struct completion done;
+#endif
};
static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
@@ -394,6 +409,134 @@ static int cpuhp_up_callbacks(unsigned i
return ret;
}
+/*
+ * The cpu hotplug threads manage the bringup and teardown of the cpus
+ */
+static void cpuhp_create(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+ init_completion(&st->done);
+}
+
+static int cpuhp_should_run(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+
+ return st->should_run;
+}
+
+/* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */
+static int cpuhp_ap_offline(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ enum cpuhp_state target = max((int)st->target, CPUHP_AP_ONLINE);
+
+ return cpuhp_down_callbacks(cpu, st, cpuhp_ap_states, target);
+}
+
+/* Execute the online startup callbacks. Used to be CPU_ONLINE */
+static int cpuhp_ap_online(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ return cpuhp_up_callbacks(cpu, st, cpuhp_ap_states, st->target);
+}
+
+/*
+ * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke
+ * callbacks when a state gets [un]installed at runtime.
+ */
+static void cpuhp_thread_fun(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+ int ret = 0;
+
+ /*
+ * Paired with the mb() in cpuhp_kick_ap_work and
+ * cpuhp_invoke_ap_callback, so the work set is consistent visible.
+ */
+ smp_mb();
+ if (!st->should_run)
+ return;
+
+ st->should_run = false;
+
+ /* Single callback invocation for [un]install ? */
+ if (st->cb) {
+ if (st->cb_state < CPUHP_AP_ONLINE) {
+ local_irq_disable();
+ ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb);
+ local_irq_enable();
+ } else {
+ ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb);
+ }
+ } else {
+ /* Regular hotplug work */
+ if (st->state < st->target)
+ ret = cpuhp_ap_online(cpu, st);
+ else if (st->state > st->target)
+ ret = cpuhp_ap_offline(cpu, st);
+ }
+ st->result = ret;
+ complete(&st->done);
+}
+
+/* Invoke a single callback on a remote cpu */
+static int cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state,
+ int (*cb)(unsigned int))
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ st->cb_state = state;
+ st->cb = cb;
+ /*
+ * Make sure the above stores are visible before should_run becomes
+ * true. Paired with the mb() above in cpuhp_thread_fun()
+ */
+ smp_mb();
+ st->should_run = true;
+ wake_up_process(st->thread);
+ wait_for_completion(&st->done);
+ return st->result;
+}
+
+/* Regular hotplug invocation of the AP hotplug thread */
+static int cpuhp_kick_ap_work(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ enum cpuhp_state state = st->state;
+
+ trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work);
+ st->result = 0;
+ st->cb = NULL;
+ /*
+ * Make sure the above stores are visible before should_run becomes
+ * true. Paired with the mb() above in cpuhp_thread_fun()
+ */
+ smp_mb();
+ st->should_run = true;
+ wake_up_process(st->thread);
+ wait_for_completion(&st->done);
+ trace_cpuhp_exit(cpu, st->state, state, st->result);
+ return st->result;
+}
+
+static struct smp_hotplug_thread cpuhp_threads = {
+ .store = &cpuhp_state.thread,
+ .create = &cpuhp_create,
+ .thread_should_run = cpuhp_should_run,
+ .thread_fn = cpuhp_thread_fun,
+ .thread_comm = "cpuhp/%u",
+ .selfparking = true,
+};
+
+void __init cpuhp_threads_init(void)
+{
+ BUG_ON(smpboot_register_percpu_thread(&cpuhp_threads));
+ kthread_unpark(this_cpu_read(cpuhp_state.thread));
+}
+
#ifdef CONFIG_HOTPLUG_CPU
EXPORT_SYMBOL(register_cpu_notifier);
EXPORT_SYMBOL(__register_cpu_notifier);
@@ -997,7 +1140,7 @@ static int cpuhp_cb_check(enum cpuhp_sta
static bool cpuhp_is_ap_state(enum cpuhp_state state)
{
- return (state > CPUHP_AP_OFFLINE && state < CPUHP_AP_ONLINE);
+ return (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE);
}
static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
Index: b/kernel/smp.c
===================================================================
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -569,6 +569,7 @@ void __init smp_init(void)
unsigned int cpu;
idle_threads_init();
+ cpuhp_threads_init();
/* FIXME: This should be done in userspace --RR */
for_each_present_cpu(cpu) {
Index: b/kernel/smpboot.h
===================================================================
--- a/kernel/smpboot.h
+++ b/kernel/smpboot.h
@@ -17,4 +17,6 @@ int smpboot_create_threads(unsigned int
int smpboot_park_threads(unsigned int cpu);
int smpboot_unpark_threads(unsigned int cpu);
+void __init cpuhp_threads_init(void);
+
#endif
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Thomas Gleixner <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-01 21:00 +0100 |
| Subject | [tip:smp/hotplug] cpu/hotplug: Create hotplug threads |
| Message-ID | <r7YCE-5hG-33@gated-at.bofh.it> |
| In reply to | #1344572 |
Commit-ID: 4cb28ced23c4f222ff4e3f39898017e52161a9c9
Gitweb: http://git.kernel.org/tip/4cb28ced23c4f222ff4e3f39898017e52161a9c9
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Fri, 26 Feb 2016 18:43:38 +0000
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 1 Mar 2016 20:36:56 +0100
cpu/hotplug: Create hotplug threads
In order to let the hotplugged cpu take care of the setup/teardown, we need a
seperate hotplug thread.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: Rik van Riel <riel@redhat.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20160226182341.454541272@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/cpu.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
kernel/smp.c | 1 +
kernel/smpboot.h | 2 +
3 files changed, 147 insertions(+), 1 deletion(-)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 9572ca0..9048c33 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -22,6 +22,7 @@
#include <linux/lockdep.h>
#include <linux/tick.h>
#include <linux/irq.h>
+#include <linux/smpboot.h>
#include <trace/events/power.h>
#define CREATE_TRACE_POINTS
@@ -33,10 +34,24 @@
* cpuhp_cpu_state - Per cpu hotplug state storage
* @state: The current cpu state
* @target: The target state
+ * @thread: Pointer to the hotplug thread
+ * @should_run: Thread should execute
+ * @cb_stat: The state for a single callback (install/uninstall)
+ * @cb: Single callback function (install/uninstall)
+ * @result: Result of the operation
+ * @done: Signal completion to the issuer of the task
*/
struct cpuhp_cpu_state {
enum cpuhp_state state;
enum cpuhp_state target;
+#ifdef CONFIG_SMP
+ struct task_struct *thread;
+ bool should_run;
+ enum cpuhp_state cb_state;
+ int (*cb)(unsigned int cpu);
+ int result;
+ struct completion done;
+#endif
};
static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
@@ -394,6 +409,134 @@ static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
return ret;
}
+/*
+ * The cpu hotplug threads manage the bringup and teardown of the cpus
+ */
+static void cpuhp_create(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+ init_completion(&st->done);
+}
+
+static int cpuhp_should_run(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+
+ return st->should_run;
+}
+
+/* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */
+static int cpuhp_ap_offline(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ enum cpuhp_state target = max((int)st->target, CPUHP_AP_ONLINE);
+
+ return cpuhp_down_callbacks(cpu, st, cpuhp_ap_states, target);
+}
+
+/* Execute the online startup callbacks. Used to be CPU_ONLINE */
+static int cpuhp_ap_online(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ return cpuhp_up_callbacks(cpu, st, cpuhp_ap_states, st->target);
+}
+
+/*
+ * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke
+ * callbacks when a state gets [un]installed at runtime.
+ */
+static void cpuhp_thread_fun(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
+ int ret = 0;
+
+ /*
+ * Paired with the mb() in cpuhp_kick_ap_work and
+ * cpuhp_invoke_ap_callback, so the work set is consistent visible.
+ */
+ smp_mb();
+ if (!st->should_run)
+ return;
+
+ st->should_run = false;
+
+ /* Single callback invocation for [un]install ? */
+ if (st->cb) {
+ if (st->cb_state < CPUHP_AP_ONLINE) {
+ local_irq_disable();
+ ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb);
+ local_irq_enable();
+ } else {
+ ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb);
+ }
+ } else {
+ /* Regular hotplug work */
+ if (st->state < st->target)
+ ret = cpuhp_ap_online(cpu, st);
+ else if (st->state > st->target)
+ ret = cpuhp_ap_offline(cpu, st);
+ }
+ st->result = ret;
+ complete(&st->done);
+}
+
+/* Invoke a single callback on a remote cpu */
+static int cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state,
+ int (*cb)(unsigned int))
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ st->cb_state = state;
+ st->cb = cb;
+ /*
+ * Make sure the above stores are visible before should_run becomes
+ * true. Paired with the mb() above in cpuhp_thread_fun()
+ */
+ smp_mb();
+ st->should_run = true;
+ wake_up_process(st->thread);
+ wait_for_completion(&st->done);
+ return st->result;
+}
+
+/* Regular hotplug invocation of the AP hotplug thread */
+static int cpuhp_kick_ap_work(unsigned int cpu)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ enum cpuhp_state state = st->state;
+
+ trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work);
+ st->result = 0;
+ st->cb = NULL;
+ /*
+ * Make sure the above stores are visible before should_run becomes
+ * true. Paired with the mb() above in cpuhp_thread_fun()
+ */
+ smp_mb();
+ st->should_run = true;
+ wake_up_process(st->thread);
+ wait_for_completion(&st->done);
+ trace_cpuhp_exit(cpu, st->state, state, st->result);
+ return st->result;
+}
+
+static struct smp_hotplug_thread cpuhp_threads = {
+ .store = &cpuhp_state.thread,
+ .create = &cpuhp_create,
+ .thread_should_run = cpuhp_should_run,
+ .thread_fn = cpuhp_thread_fun,
+ .thread_comm = "cpuhp/%u",
+ .selfparking = true,
+};
+
+void __init cpuhp_threads_init(void)
+{
+ BUG_ON(smpboot_register_percpu_thread(&cpuhp_threads));
+ kthread_unpark(this_cpu_read(cpuhp_state.thread));
+}
+
#ifdef CONFIG_HOTPLUG_CPU
EXPORT_SYMBOL(register_cpu_notifier);
EXPORT_SYMBOL(__register_cpu_notifier);
@@ -997,7 +1140,7 @@ static int cpuhp_cb_check(enum cpuhp_state state)
static bool cpuhp_is_ap_state(enum cpuhp_state state)
{
- return (state > CPUHP_AP_OFFLINE && state < CPUHP_AP_ONLINE);
+ return (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE);
}
static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
diff --git a/kernel/smp.c b/kernel/smp.c
index d903c02..822ffb1 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -569,6 +569,7 @@ void __init smp_init(void)
unsigned int cpu;
idle_threads_init();
+ cpuhp_threads_init();
/* FIXME: This should be done in userspace --RR */
for_each_present_cpu(cpu) {
diff --git a/kernel/smpboot.h b/kernel/smpboot.h
index 6b5f020..485b81c 100644
--- a/kernel/smpboot.h
+++ b/kernel/smpboot.h
@@ -17,4 +17,6 @@ int smpboot_create_threads(unsigned int cpu);
int smpboot_park_threads(unsigned int cpu);
int smpboot_unpark_threads(unsigned int cpu);
+void __init cpuhp_threads_init(void);
+
#endif
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-26 19:50 +0100 |
| Subject | [patch 09/20] cpu/hotplug: Add sysfs state interface |
| Message-ID | <r6vCH-7sv-45@gated-at.bofh.it> |
| In reply to | #1344561 |
Add a sysfs interface so we can actually see in which state the cpus are in.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/cpu.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 98 insertions(+)
Index: b/kernel/cpu.c
===================================================================
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -56,6 +56,7 @@ struct cpuhp_step {
bool skip_onerr;
};
+static DEFINE_MUTEX(cpuhp_state_mutex);
static struct cpuhp_step cpuhp_bp_states[];
static struct cpuhp_step cpuhp_ap_states[];
@@ -955,6 +956,103 @@ static struct cpuhp_step cpuhp_ap_states
},
};
+static bool cpuhp_is_ap_state(enum cpuhp_state state)
+{
+ return (state > CPUHP_AP_OFFLINE && state < CPUHP_AP_ONLINE);
+}
+
+static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
+{
+ struct cpuhp_step *sp;
+
+ sp = cpuhp_is_ap_state(state) ? cpuhp_ap_states : cpuhp_bp_states;
+ return sp + state;
+}
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU)
+static ssize_t show_cpuhp_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);
+
+ return sprintf(buf, "%d\n", st->state);
+}
+static DEVICE_ATTR(state, 0444, show_cpuhp_state, NULL);
+
+static ssize_t show_cpuhp_target(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);
+
+ return sprintf(buf, "%d\n", st->target);
+}
+static DEVICE_ATTR(target, 0444, show_cpuhp_target, NULL);
+
+static struct attribute *cpuhp_cpu_attrs[] = {
+ &dev_attr_state.attr,
+ &dev_attr_target.attr,
+ NULL
+};
+
+static struct attribute_group cpuhp_cpu_attr_group = {
+ .attrs = cpuhp_cpu_attrs,
+ .name = "hotplug",
+ NULL
+};
+
+static ssize_t show_cpuhp_states(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t cur, res = 0;
+ int i;
+
+ mutex_lock(&cpuhp_state_mutex);
+ for (i = 0; i <= CPUHP_ONLINE; i++) {
+ struct cpuhp_step *sp = cpuhp_get_step(i);
+
+ if (sp->name) {
+ cur = sprintf(buf, "%3d: %s\n", i, sp->name);
+ buf += cur;
+ res += cur;
+ }
+ }
+ mutex_unlock(&cpuhp_state_mutex);
+ return res;
+}
+static DEVICE_ATTR(states, 0444, show_cpuhp_states, NULL);
+
+static struct attribute *cpuhp_cpu_root_attrs[] = {
+ &dev_attr_states.attr,
+ NULL
+};
+
+static struct attribute_group cpuhp_cpu_root_attr_group = {
+ .attrs = cpuhp_cpu_root_attrs,
+ .name = "hotplug",
+ NULL
+};
+
+static int __init cpuhp_sysfs_init(void)
+{
+ int cpu, ret;
+
+ ret = sysfs_create_group(&cpu_subsys.dev_root->kobj,
+ &cpuhp_cpu_root_attr_group);
+ if (ret)
+ return ret;
+
+ for_each_possible_cpu(cpu) {
+ struct device *dev = get_cpu_device(cpu);
+
+ ret = sysfs_create_group(&dev->kobj, &cpuhp_cpu_attr_group);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+device_initcall(cpuhp_sysfs_init);
+#endif
+
/*
* cpu_bit_bitmap[] is a special, "compressed" data structure that
* represents all NR_CPUS bits binary values of 1<<nr.
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Thomas Gleixner <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-01 21:00 +0100 |
| Subject | [tip:smp/hotplug] cpu/hotplug: Add sysfs state interface |
| Message-ID | <r7YCE-5hG-37@gated-at.bofh.it> |
| In reply to | #1344573 |
Commit-ID: 98f8cdce1db580b99fce823a48eea2cb2bdb261e
Gitweb: http://git.kernel.org/tip/98f8cdce1db580b99fce823a48eea2cb2bdb261e
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Fri, 26 Feb 2016 18:43:31 +0000
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 1 Mar 2016 20:36:55 +0100
cpu/hotplug: Add sysfs state interface
Add a sysfs interface so we can actually see in which state the cpus are in.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: Rik van Riel <riel@redhat.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20160226182340.942257522@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/cpu.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index a00f8f6..1979b89 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -56,6 +56,7 @@ struct cpuhp_step {
bool skip_onerr;
};
+static DEFINE_MUTEX(cpuhp_state_mutex);
static struct cpuhp_step cpuhp_bp_states[];
static struct cpuhp_step cpuhp_ap_states[];
@@ -955,6 +956,105 @@ static struct cpuhp_step cpuhp_ap_states[] = {
},
};
+static bool cpuhp_is_ap_state(enum cpuhp_state state)
+{
+ return (state > CPUHP_AP_OFFLINE && state < CPUHP_AP_ONLINE);
+}
+
+static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
+{
+ struct cpuhp_step *sp;
+
+ sp = cpuhp_is_ap_state(state) ? cpuhp_ap_states : cpuhp_bp_states;
+ return sp + state;
+}
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU)
+static ssize_t show_cpuhp_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);
+
+ return sprintf(buf, "%d\n", st->state);
+}
+static DEVICE_ATTR(state, 0444, show_cpuhp_state, NULL);
+
+static ssize_t show_cpuhp_target(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);
+
+ return sprintf(buf, "%d\n", st->target);
+}
+static DEVICE_ATTR(target, 0444, show_cpuhp_target, NULL);
+
+static struct attribute *cpuhp_cpu_attrs[] = {
+ &dev_attr_state.attr,
+ &dev_attr_target.attr,
+ NULL
+};
+
+static struct attribute_group cpuhp_cpu_attr_group = {
+ .attrs = cpuhp_cpu_attrs,
+ .name = "hotplug",
+ NULL
+};
+
+static ssize_t show_cpuhp_states(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t cur, res = 0;
+ int i;
+
+ mutex_lock(&cpuhp_state_mutex);
+ for (i = 0; i <= CPUHP_ONLINE; i++) {
+ struct cpuhp_step *sp = cpuhp_get_step(i);
+
+ if (sp->name) {
+ cur = sprintf(buf, "%3d: %s\n", i, sp->name);
+ buf += cur;
+ res += cur;
+ }
+ }
+ mutex_unlock(&cpuhp_state_mutex);
+ return res;
+}
+static DEVICE_ATTR(states, 0444, show_cpuhp_states, NULL);
+
+static struct attribute *cpuhp_cpu_root_attrs[] = {
+ &dev_attr_states.attr,
+ NULL
+};
+
+static struct attribute_group cpuhp_cpu_root_attr_group = {
+ .attrs = cpuhp_cpu_root_attrs,
+ .name = "hotplug",
+ NULL
+};
+
+static int __init cpuhp_sysfs_init(void)
+{
+ int cpu, ret;
+
+ ret = sysfs_create_group(&cpu_subsys.dev_root->kobj,
+ &cpuhp_cpu_root_attr_group);
+ if (ret)
+ return ret;
+
+ for_each_possible_cpu(cpu) {
+ struct device *dev = get_cpu_device(cpu);
+
+ if (!dev)
+ continue;
+ ret = sysfs_create_group(&dev->kobj, &cpuhp_cpu_attr_group);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+device_initcall(cpuhp_sysfs_init);
+#endif
+
/*
* cpu_bit_bitmap[] is a special, "compressed" data structure that
* represents all NR_CPUS bits binary values of 1<<nr.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-03-02 13:50 +0100 |
| Subject | Re: [tip:smp/hotplug] cpu/hotplug: Add sysfs state interface |
| Message-ID | <r8eo2-7DD-19@gated-at.bofh.it> |
| In reply to | #1346982 |
On Tue, Mar 01, 2016 at 11:54:37AM -0800, tip-bot for Thomas Gleixner wrote: > Commit-ID: 98f8cdce1db580b99fce823a48eea2cb2bdb261e > Gitweb: http://git.kernel.org/tip/98f8cdce1db580b99fce823a48eea2cb2bdb261e > Author: Thomas Gleixner <tglx@linutronix.de> > AuthorDate: Fri, 26 Feb 2016 18:43:31 +0000 > Committer: Thomas Gleixner <tglx@linutronix.de> > CommitDate: Tue, 1 Mar 2016 20:36:55 +0100 > > cpu/hotplug: Add sysfs state interface > > Add a sysfs interface so we can actually see in which state the cpus are in. I feel this Changelog can use a few extra lines to explain the ABI ramifications and why this lives here and not in drivers/base/cpu.c where the rest of the cpu_subsys muck lives.
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-26 19:50 +0100 |
| Subject | [patch 06/20] cpu/hotplug: Convert to a state machine for the control processor |
| Message-ID | <r6vCH-7sv-47@gated-at.bofh.it> |
| In reply to | #1344561 |
Move the split out steps into a callback array and let the cpu_up/down
code iterate through the array functions. For now most of the
callbacks are asymmetric to resemble the current hotplug maze.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpu.h | 9 -
include/linux/cpuhotplug.h | 13 ++
init/main.c | 15 ---
kernel/cpu.c | 204 +++++++++++++++++++++++++++++++++++++++------
4 files changed, 195 insertions(+), 46 deletions(-)
create mode 100644 include/linux/cpuhotplug.h
Index: b/include/linux/cpu.h
===================================================================
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -16,6 +16,7 @@
#include <linux/node.h>
#include <linux/compiler.h>
#include <linux/cpumask.h>
+#include <linux/cpuhotplug.h>
struct device;
struct device_node;
@@ -27,6 +28,9 @@ struct cpu {
struct device dev;
};
+extern void boot_cpu_init(void);
+extern void boot_cpu_state_init(void);
+
extern int register_cpu(struct cpu *cpu, int num);
extern struct device *get_cpu_device(unsigned cpu);
extern bool cpu_is_hotpluggable(unsigned cpu);
@@ -267,11 +271,6 @@ static inline int disable_nonboot_cpus(v
static inline void enable_nonboot_cpus(void) {}
#endif /* !CONFIG_PM_SLEEP_SMP */
-enum cpuhp_state {
- CPUHP_OFFLINE,
- CPUHP_ONLINE,
-};
-
void cpu_startup_entry(enum cpuhp_state state);
void cpu_idle_poll_ctrl(bool enable);
Index: b/include/linux/cpuhotplug.h
===================================================================
--- /dev/null
+++ b/include/linux/cpuhotplug.h
@@ -0,0 +1,13 @@
+#ifndef __CPUHOTPLUG_H
+#define __CPUHOTPLUG_H
+
+enum cpuhp_state {
+ CPUHP_OFFLINE,
+ CPUHP_CREATE_THREADS,
+ CPUHP_NOTIFY_PREPARE,
+ CPUHP_BRINGUP_CPU,
+ CPUHP_NOTIFY_ONLINE,
+ CPUHP_ONLINE,
+};
+
+#endif
Index: b/init/main.c
===================================================================
--- a/init/main.c
+++ b/init/main.c
@@ -452,20 +452,6 @@ void __init parse_early_param(void)
done = 1;
}
-/*
- * Activate the first processor.
- */
-
-static void __init boot_cpu_init(void)
-{
- int cpu = smp_processor_id();
- /* Mark the boot cpu "present", "online" etc for SMP and UP case */
- set_cpu_online(cpu, true);
- set_cpu_active(cpu, true);
- set_cpu_present(cpu, true);
- set_cpu_possible(cpu, true);
-}
-
void __init __weak smp_setup_processor_id(void)
{
}
@@ -530,6 +516,7 @@ asmlinkage __visible void __init start_k
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
+ boot_cpu_state_init();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
build_all_zonelists(NULL, NULL);
Index: b/kernel/cpu.c
===================================================================
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -22,10 +22,64 @@
#include <linux/lockdep.h>
#include <linux/tick.h>
#include <linux/irq.h>
+
#include <trace/events/power.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/cpuhp.h>
#include "smpboot.h"
+/**
+ * cpuhp_cpu_state - Per cpu hotplug state storage
+ * @state: The current cpu state
+ * @target: The target state
+ */
+struct cpuhp_cpu_state {
+ enum cpuhp_state state;
+ enum cpuhp_state target;
+};
+
+static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
+
+/**
+ * cpuhp_step - Hotplug state machine step
+ * @name: Name of the step
+ * @startup: Startup function of the step
+ * @teardown: Teardown function of the step
+ * @skip_onerr: Do not invoke the functions on error rollback
+ * Will go away once the notifiers are gone
+ */
+struct cpuhp_step {
+ const char *name;
+ int (*startup)(unsigned int cpu);
+ int (*teardown)(unsigned int cpu);
+ bool skip_onerr;
+};
+
+static struct cpuhp_step cpuhp_bp_states[];
+
+/**
+ * cpuhp_invoke_callback _ Invoke the callbacks for a given state
+ * @cpu: The cpu for which the callback should be invoked
+ * @step: The step in the state machine
+ * @cb: The callback function to invoke
+ *
+ * Called from cpu hotplug and from the state register machinery
+ */
+static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state step,
+ int (*cb)(unsigned int))
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ int ret = 0;
+
+ if (cb) {
+ trace_cpuhp_enter(cpu, st->target, step, cb);
+ ret = cb(cpu);
+ trace_cpuhp_exit(cpu, st->state, step, ret);
+ }
+ return ret;
+}
+
#ifdef CONFIG_SMP
/* Serializes the updates to cpu_online_mask, cpu_present_mask */
static DEFINE_MUTEX(cpu_add_remove_lock);
@@ -454,10 +508,29 @@ static int notify_dead(unsigned int cpu)
return 0;
}
+#else
+#define notify_down_prepare NULL
+#define takedown_cpu NULL
+#define notify_dead NULL
+#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ for (st->state++; st->state < st->target; st->state++) {
+ struct cpuhp_step *step = cpuhp_bp_states + st->state;
+
+ if (!step->skip_onerr)
+ cpuhp_invoke_callback(cpu, st->state, step->startup);
+ }
+}
+
/* Requires cpu_add_remove_lock to be held */
static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
{
- int err;
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ int prev_state, ret = 0;
+ bool hasdied = false;
if (num_online_cpus() == 1)
return -EBUSY;
@@ -469,20 +542,25 @@ static int __ref _cpu_down(unsigned int
cpuhp_tasks_frozen = tasks_frozen;
- err = notify_down_prepare(cpu);
- if (err)
- goto out_release;
- err = takedown_cpu(cpu);
- if (err)
- goto out_release;
-
- notify_dead(cpu);
+ prev_state = st->state;
+ st->target = CPUHP_OFFLINE;
+ for (; st->state > st->target; st->state--) {
+ struct cpuhp_step *step = cpuhp_bp_states + st->state;
+
+ ret = cpuhp_invoke_callback(cpu, st->state, step->teardown);
+ if (ret) {
+ st->target = prev_state;
+ undo_cpu_down(cpu, st);
+ break;
+ }
+ }
+ hasdied = prev_state != st->state && st->state == CPUHP_OFFLINE;
-out_release:
cpu_hotplug_done();
- if (!err)
+ /* This post dead nonsense must die */
+ if (!ret && hasdied)
cpu_notify_nofail(CPU_POST_DEAD, cpu);
- return err;
+ return ret;
}
int cpu_down(unsigned int cpu)
@@ -537,11 +615,22 @@ void smpboot_thread_init(void)
register_cpu_notifier(&smpboot_thread_notifier);
}
+static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ for (st->state--; st->state > st->target; st->state--) {
+ struct cpuhp_step *step = cpuhp_bp_states + st->state;
+
+ if (!step->skip_onerr)
+ cpuhp_invoke_callback(cpu, st->state, step->teardown);
+ }
+}
+
/* Requires cpu_add_remove_lock to be held */
static int _cpu_up(unsigned int cpu, int tasks_frozen)
{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
struct task_struct *idle;
- int ret;
+ int prev_state, ret = 0;
cpu_hotplug_begin();
@@ -550,6 +639,7 @@ static int _cpu_up(unsigned int cpu, int
goto out;
}
+ /* Let it fail before we try to bring the cpu up */
idle = idle_thread_get(cpu);
if (IS_ERR(idle)) {
ret = PTR_ERR(idle);
@@ -558,22 +648,22 @@ static int _cpu_up(unsigned int cpu, int
cpuhp_tasks_frozen = tasks_frozen;
- ret = smpboot_create_threads(cpu);
- if (ret)
- goto out;
-
- ret = notify_prepare(cpu);
- if (ret)
- goto out;
-
- ret = bringup_cpu(cpu);
- if (ret)
- goto out;
-
- notify_online(cpu);
+ prev_state = st->state;
+ st->target = CPUHP_ONLINE;
+ while (st->state < st->target) {
+ struct cpuhp_step *step;
+
+ st->state++;
+ step = cpuhp_bp_states + st->state;
+ ret = cpuhp_invoke_callback(cpu, st->state, step->startup);
+ if (ret) {
+ st->target = prev_state;
+ undo_cpu_up(cpu, st);
+ break;
+ }
+ }
out:
cpu_hotplug_done();
-
return ret;
}
@@ -767,6 +857,44 @@ void notify_cpu_starting(unsigned int cp
#endif /* CONFIG_SMP */
+/* Boot processor state steps */
+static struct cpuhp_step cpuhp_bp_states[] = {
+ [CPUHP_OFFLINE] = {
+ .name = "offline",
+ .startup = NULL,
+ .teardown = NULL,
+ },
+#ifdef CONFIG_SMP
+ [CPUHP_CREATE_THREADS]= {
+ .name = "threads:create",
+ .startup = smpboot_create_threads,
+ .teardown = NULL,
+ },
+ [CPUHP_NOTIFY_PREPARE] = {
+ .name = "notify:prepare",
+ .startup = notify_prepare,
+ .teardown = notify_dead,
+ .skip_onerr = true,
+ },
+ [CPUHP_BRINGUP_CPU] = {
+ .name = "cpu:bringup",
+ .startup = bringup_cpu,
+ .teardown = takedown_cpu,
+ .skip_onerr = true,
+ },
+ [CPUHP_NOTIFY_ONLINE] = {
+ .name = "notify:online",
+ .startup = notify_online,
+ .teardown = notify_down_prepare,
+ },
+#endif
+ [CPUHP_ONLINE] = {
+ .name = "online",
+ .startup = NULL,
+ .teardown = NULL,
+ },
+};
+
/*
* cpu_bit_bitmap[] is a special, "compressed" data structure that
* represents all NR_CPUS bits binary values of 1<<nr.
@@ -826,3 +954,25 @@ void init_cpu_online(const struct cpumas
{
cpumask_copy(&__cpu_online_mask, src);
}
+
+/*
+ * Activate the first processor.
+ */
+void __init boot_cpu_init(void)
+{
+ int cpu = smp_processor_id();
+
+ /* Mark the boot cpu "present", "online" etc for SMP and UP case */
+ set_cpu_online(cpu, true);
+ set_cpu_active(cpu, true);
+ set_cpu_present(cpu, true);
+ set_cpu_possible(cpu, true);
+}
+
+/*
+ * Must be called _AFTER_ setting up the per_cpu areas
+ */
+void __init boot_cpu_state_init(void)
+{
+ per_cpu_ptr(&cpuhp_state, smp_processor_id())->state = CPUHP_ONLINE;
+}
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Thomas Gleixner <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-01 21:00 +0100 |
| Subject | [tip:smp/hotplug] cpu/hotplug: Convert to a state machine for the control processor |
| Message-ID | <r7YCD-5hG-25@gated-at.bofh.it> |
| In reply to | #1344574 |
Commit-ID: cff7d378d3fdbb53db9b6e2578b14855f401cd41
Gitweb: http://git.kernel.org/tip/cff7d378d3fdbb53db9b6e2578b14855f401cd41
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Fri, 26 Feb 2016 18:43:28 +0000
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 1 Mar 2016 20:36:54 +0100
cpu/hotplug: Convert to a state machine for the control processor
Move the split out steps into a callback array and let the cpu_up/down
code iterate through the array functions. For now most of the
callbacks are asymmetric to resemble the current hotplug maze.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: Rik van Riel <riel@redhat.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20160226182340.671816690@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpu.h | 9 +-
include/linux/cpuhotplug.h | 13 +++
init/main.c | 15 +---
kernel/cpu.c | 202 +++++++++++++++++++++++++++++++++++++++------
4 files changed, 194 insertions(+), 45 deletions(-)
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index f2fb549..78989f2 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -16,6 +16,7 @@
#include <linux/node.h>
#include <linux/compiler.h>
#include <linux/cpumask.h>
+#include <linux/cpuhotplug.h>
struct device;
struct device_node;
@@ -27,6 +28,9 @@ struct cpu {
struct device dev;
};
+extern void boot_cpu_init(void);
+extern void boot_cpu_state_init(void);
+
extern int register_cpu(struct cpu *cpu, int num);
extern struct device *get_cpu_device(unsigned cpu);
extern bool cpu_is_hotpluggable(unsigned cpu);
@@ -267,11 +271,6 @@ static inline int disable_nonboot_cpus(void) { return 0; }
static inline void enable_nonboot_cpus(void) {}
#endif /* !CONFIG_PM_SLEEP_SMP */
-enum cpuhp_state {
- CPUHP_OFFLINE,
- CPUHP_ONLINE,
-};
-
void cpu_startup_entry(enum cpuhp_state state);
void cpu_idle_poll_ctrl(bool enable);
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
new file mode 100644
index 0000000..d55c9e6
--- /dev/null
+++ b/include/linux/cpuhotplug.h
@@ -0,0 +1,13 @@
+#ifndef __CPUHOTPLUG_H
+#define __CPUHOTPLUG_H
+
+enum cpuhp_state {
+ CPUHP_OFFLINE,
+ CPUHP_CREATE_THREADS,
+ CPUHP_NOTIFY_PREPARE,
+ CPUHP_BRINGUP_CPU,
+ CPUHP_NOTIFY_ONLINE,
+ CPUHP_ONLINE,
+};
+
+#endif
diff --git a/init/main.c b/init/main.c
index 58c9e37..c2ea723 100644
--- a/init/main.c
+++ b/init/main.c
@@ -452,20 +452,6 @@ void __init parse_early_param(void)
done = 1;
}
-/*
- * Activate the first processor.
- */
-
-static void __init boot_cpu_init(void)
-{
- int cpu = smp_processor_id();
- /* Mark the boot cpu "present", "online" etc for SMP and UP case */
- set_cpu_online(cpu, true);
- set_cpu_active(cpu, true);
- set_cpu_present(cpu, true);
- set_cpu_possible(cpu, true);
-}
-
void __init __weak smp_setup_processor_id(void)
{
}
@@ -530,6 +516,7 @@ asmlinkage __visible void __init start_kernel(void)
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
+ boot_cpu_state_init();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
build_all_zonelists(NULL, NULL);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 0b5d259..3018519 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -22,10 +22,64 @@
#include <linux/lockdep.h>
#include <linux/tick.h>
#include <linux/irq.h>
+
#include <trace/events/power.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/cpuhp.h>
#include "smpboot.h"
+/**
+ * cpuhp_cpu_state - Per cpu hotplug state storage
+ * @state: The current cpu state
+ * @target: The target state
+ */
+struct cpuhp_cpu_state {
+ enum cpuhp_state state;
+ enum cpuhp_state target;
+};
+
+static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
+
+/**
+ * cpuhp_step - Hotplug state machine step
+ * @name: Name of the step
+ * @startup: Startup function of the step
+ * @teardown: Teardown function of the step
+ * @skip_onerr: Do not invoke the functions on error rollback
+ * Will go away once the notifiers are gone
+ */
+struct cpuhp_step {
+ const char *name;
+ int (*startup)(unsigned int cpu);
+ int (*teardown)(unsigned int cpu);
+ bool skip_onerr;
+};
+
+static struct cpuhp_step cpuhp_bp_states[];
+
+/**
+ * cpuhp_invoke_callback _ Invoke the callbacks for a given state
+ * @cpu: The cpu for which the callback should be invoked
+ * @step: The step in the state machine
+ * @cb: The callback function to invoke
+ *
+ * Called from cpu hotplug and from the state register machinery
+ */
+static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state step,
+ int (*cb)(unsigned int))
+{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ int ret = 0;
+
+ if (cb) {
+ trace_cpuhp_enter(cpu, st->target, step, cb);
+ ret = cb(cpu);
+ trace_cpuhp_exit(cpu, st->state, step, ret);
+ }
+ return ret;
+}
+
#ifdef CONFIG_SMP
/* Serializes the updates to cpu_online_mask, cpu_present_mask */
static DEFINE_MUTEX(cpu_add_remove_lock);
@@ -454,10 +508,29 @@ static int notify_dead(unsigned int cpu)
return 0;
}
+#else
+#define notify_down_prepare NULL
+#define takedown_cpu NULL
+#define notify_dead NULL
+#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ for (st->state++; st->state < st->target; st->state++) {
+ struct cpuhp_step *step = cpuhp_bp_states + st->state;
+
+ if (!step->skip_onerr)
+ cpuhp_invoke_callback(cpu, st->state, step->startup);
+ }
+}
+
/* Requires cpu_add_remove_lock to be held */
static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
{
- int err;
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
+ int prev_state, ret = 0;
+ bool hasdied = false;
if (num_online_cpus() == 1)
return -EBUSY;
@@ -469,20 +542,25 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
cpuhp_tasks_frozen = tasks_frozen;
- err = notify_down_prepare(cpu);
- if (err)
- goto out_release;
- err = takedown_cpu(cpu);
- if (err)
- goto out_release;
+ prev_state = st->state;
+ st->target = CPUHP_OFFLINE;
+ for (; st->state > st->target; st->state--) {
+ struct cpuhp_step *step = cpuhp_bp_states + st->state;
- notify_dead(cpu);
+ ret = cpuhp_invoke_callback(cpu, st->state, step->teardown);
+ if (ret) {
+ st->target = prev_state;
+ undo_cpu_down(cpu, st);
+ break;
+ }
+ }
+ hasdied = prev_state != st->state && st->state == CPUHP_OFFLINE;
-out_release:
cpu_hotplug_done();
- if (!err)
+ /* This post dead nonsense must die */
+ if (!ret && hasdied)
cpu_notify_nofail(CPU_POST_DEAD, cpu);
- return err;
+ return ret;
}
int cpu_down(unsigned int cpu)
@@ -537,11 +615,22 @@ void smpboot_thread_init(void)
register_cpu_notifier(&smpboot_thread_notifier);
}
+static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
+{
+ for (st->state--; st->state > st->target; st->state--) {
+ struct cpuhp_step *step = cpuhp_bp_states + st->state;
+
+ if (!step->skip_onerr)
+ cpuhp_invoke_callback(cpu, st->state, step->teardown);
+ }
+}
+
/* Requires cpu_add_remove_lock to be held */
static int _cpu_up(unsigned int cpu, int tasks_frozen)
{
+ struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
struct task_struct *idle;
- int ret;
+ int prev_state, ret = 0;
cpu_hotplug_begin();
@@ -550,6 +639,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
goto out;
}
+ /* Let it fail before we try to bring the cpu up */
idle = idle_thread_get(cpu);
if (IS_ERR(idle)) {
ret = PTR_ERR(idle);
@@ -558,22 +648,22 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
cpuhp_tasks_frozen = tasks_frozen;
- ret = smpboot_create_threads(cpu);
- if (ret)
- goto out;
-
- ret = notify_prepare(cpu);
- if (ret)
- goto out;
-
- ret = bringup_cpu(cpu);
- if (ret)
- goto out;
-
- notify_online(cpu);
+ prev_state = st->state;
+ st->target = CPUHP_ONLINE;
+ while (st->state < st->target) {
+ struct cpuhp_step *step;
+
+ st->state++;
+ step = cpuhp_bp_states + st->state;
+ ret = cpuhp_invoke_callback(cpu, st->state, step->startup);
+ if (ret) {
+ st->target = prev_state;
+ undo_cpu_up(cpu, st);
+ break;
+ }
+ }
out:
cpu_hotplug_done();
-
return ret;
}
@@ -767,6 +857,44 @@ void notify_cpu_starting(unsigned int cpu)
#endif /* CONFIG_SMP */
+/* Boot processor state steps */
+static struct cpuhp_step cpuhp_bp_states[] = {
+ [CPUHP_OFFLINE] = {
+ .name = "offline",
+ .startup = NULL,
+ .teardown = NULL,
+ },
+#ifdef CONFIG_SMP
+ [CPUHP_CREATE_THREADS]= {
+ .name = "threads:create",
+ .startup = smpboot_create_threads,
+ .teardown = NULL,
+ },
+ [CPUHP_NOTIFY_PREPARE] = {
+ .name = "notify:prepare",
+ .startup = notify_prepare,
+ .teardown = notify_dead,
+ .skip_onerr = true,
+ },
+ [CPUHP_BRINGUP_CPU] = {
+ .name = "cpu:bringup",
+ .startup = bringup_cpu,
+ .teardown = takedown_cpu,
+ .skip_onerr = true,
+ },
+ [CPUHP_NOTIFY_ONLINE] = {
+ .name = "notify:online",
+ .startup = notify_online,
+ .teardown = notify_down_prepare,
+ },
+#endif
+ [CPUHP_ONLINE] = {
+ .name = "online",
+ .startup = NULL,
+ .teardown = NULL,
+ },
+};
+
/*
* cpu_bit_bitmap[] is a special, "compressed" data structure that
* represents all NR_CPUS bits binary values of 1<<nr.
@@ -826,3 +954,25 @@ void init_cpu_online(const struct cpumask *src)
{
cpumask_copy(&__cpu_online_mask, src);
}
+
+/*
+ * Activate the first processor.
+ */
+void __init boot_cpu_init(void)
+{
+ int cpu = smp_processor_id();
+
+ /* Mark the boot cpu "present", "online" etc for SMP and UP case */
+ set_cpu_online(cpu, true);
+ set_cpu_active(cpu, true);
+ set_cpu_present(cpu, true);
+ set_cpu_possible(cpu, true);
+}
+
+/*
+ * Must be called _AFTER_ setting up the per_cpu areas
+ */
+void __init boot_cpu_state_init(void)
+{
+ per_cpu_ptr(&cpuhp_state, smp_processor_id())->state = CPUHP_ONLINE;
+}
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-03-02 12:30 +0100 |
| Subject | Re: [tip:smp/hotplug] cpu/hotplug: Convert to a state machine for the control processor |
| Message-ID | <r8d8B-6UP-1@gated-at.bofh.it> |
| In reply to | #1346978 |
On Tue, Mar 01, 2016 at 11:53:25AM -0800, tip-bot for Thomas Gleixner wrote:
> @@ -558,22 +648,22 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
>
> cpuhp_tasks_frozen = tasks_frozen;
>
> + prev_state = st->state;
> + st->target = CPUHP_ONLINE;
> + while (st->state < st->target) {
> + struct cpuhp_step *step;
> +
> + st->state++;
> + step = cpuhp_bp_states + st->state;
> + ret = cpuhp_invoke_callback(cpu, st->state, step->startup);
> + if (ret) {
> + st->target = prev_state;
> + undo_cpu_up(cpu, st);
> + break;
> + }
> + }
All your other state loops use for().
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-26 19:50 +0100 |
| Subject | [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6vCH-7sv-49@gated-at.bofh.it> |
| In reply to | #1344561 |
Make the RCU CPU_DYING_IDLE callback an explicit function call, so it gets
invoked at the proper place.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpu.h | 4 +---
include/linux/notifier.h | 2 ++
include/linux/rcupdate.h | 4 +---
kernel/cpu.c | 1 +
kernel/rcu/tree.c | 26 +++++++++++++++-----------
kernel/sched/idle.c | 2 --
6 files changed, 20 insertions(+), 19 deletions(-)
Index: b/include/linux/cpu.h
===================================================================
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -101,9 +101,7 @@ enum {
* Called on the new cpu, just before
* enabling interrupts. Must not sleep,
* must not fail */
-#define CPU_DYING_IDLE 0x000B /* CPU (unsigned)v dying, reached
- * idle loop. */
-#define CPU_BROKEN 0x000C /* CPU (unsigned)v did not die properly,
+#define CPU_BROKEN 0x000B /* CPU (unsigned)v did not die properly,
* perhaps due to preemption. */
/* Used for CPU hotplug events occurring while tasks are frozen due to a suspend
Index: b/include/linux/notifier.h
===================================================================
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -47,6 +47,8 @@
* runtime initialization.
*/
+struct notifier_block;
+
typedef int (*notifier_fn_t)(struct notifier_block *nb,
unsigned long action, void *data);
Index: b/include/linux/rcupdate.h
===================================================================
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -332,9 +332,7 @@ void rcu_init(void);
void rcu_sched_qs(void);
void rcu_bh_qs(void);
void rcu_check_callbacks(int user);
-struct notifier_block;
-int rcu_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu);
+void rcu_report_dead(unsigned int cpu);
#ifndef CONFIG_TINY_RCU
void rcu_end_inkernel_boot(void);
Index: b/kernel/cpu.c
===================================================================
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void)
BUG_ON(st->state != CPUHP_AP_OFFLINE);
st->state = CPUHP_AP_IDLE_DEAD;
complete(&st->done);
+ rcu_report_dead(smp_processor_id());
}
#else
Index: b/kernel/rcu/tree.c
===================================================================
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -4247,6 +4247,21 @@ static void rcu_prepare_cpu(int cpu)
rcu_init_percpu_data(cpu, rsp);
}
+#ifdef CONFIG_HOTPLUG_CPU
+void rcu_report_dead(unsigned int cpu)
+{
+ struct rcu_state *rsp;
+
+ /* QS for any half-done expedited RCU-sched GP. */
+ preempt_disable();
+ rcu_report_exp_rdp(&rcu_sched_state,
+ this_cpu_ptr(rcu_sched_state.rda), true);
+ preempt_enable();
+ for_each_rcu_flavor(rsp)
+ rcu_cleanup_dying_idle_cpu(cpu, rsp);
+}
+#endif
+
/*
* Handle CPU online/offline notification events.
*/
@@ -4278,17 +4293,6 @@ int rcu_cpu_notify(struct notifier_block
for_each_rcu_flavor(rsp)
rcu_cleanup_dying_cpu(rsp);
break;
- case CPU_DYING_IDLE:
- /* QS for any half-done expedited RCU-sched GP. */
- preempt_disable();
- rcu_report_exp_rdp(&rcu_sched_state,
- this_cpu_ptr(rcu_sched_state.rda), true);
- preempt_enable();
-
- for_each_rcu_flavor(rsp) {
- rcu_cleanup_dying_idle_cpu(cpu, rsp);
- }
- break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
Index: b/kernel/sched/idle.c
===================================================================
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -220,8 +220,6 @@ static void cpu_idle_loop(void)
rmb();
if (cpu_is_offline(smp_processor_id())) {
- rcu_cpu_notify(NULL, CPU_DYING_IDLE,
- (void *)(long)smp_processor_id());
cpuhp_report_idle_dead();
arch_cpu_idle_dead();
}
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-02-27 03:20 +0100 |
| Subject | Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6CE9-4i7-3@gated-at.bofh.it> |
| In reply to | #1344575 |
On Fri, Feb 26, 2016 at 06:43:44PM -0000, Thomas Gleixner wrote:
> Make the RCU CPU_DYING_IDLE callback an explicit function call, so it gets
> invoked at the proper place.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
A question below...
> ---
> include/linux/cpu.h | 4 +---
> include/linux/notifier.h | 2 ++
> include/linux/rcupdate.h | 4 +---
> kernel/cpu.c | 1 +
> kernel/rcu/tree.c | 26 +++++++++++++++-----------
> kernel/sched/idle.c | 2 --
> 6 files changed, 20 insertions(+), 19 deletions(-)
>
> Index: b/include/linux/cpu.h
> ===================================================================
> --- a/include/linux/cpu.h
> +++ b/include/linux/cpu.h
> @@ -101,9 +101,7 @@ enum {
> * Called on the new cpu, just before
> * enabling interrupts. Must not sleep,
> * must not fail */
> -#define CPU_DYING_IDLE 0x000B /* CPU (unsigned)v dying, reached
> - * idle loop. */
> -#define CPU_BROKEN 0x000C /* CPU (unsigned)v did not die properly,
> +#define CPU_BROKEN 0x000B /* CPU (unsigned)v did not die properly,
> * perhaps due to preemption. */
>
> /* Used for CPU hotplug events occurring while tasks are frozen due to a suspend
> Index: b/include/linux/notifier.h
> ===================================================================
> --- a/include/linux/notifier.h
> +++ b/include/linux/notifier.h
> @@ -47,6 +47,8 @@
> * runtime initialization.
> */
>
> +struct notifier_block;
> +
> typedef int (*notifier_fn_t)(struct notifier_block *nb,
> unsigned long action, void *data);
>
> Index: b/include/linux/rcupdate.h
> ===================================================================
> --- a/include/linux/rcupdate.h
> +++ b/include/linux/rcupdate.h
> @@ -332,9 +332,7 @@ void rcu_init(void);
> void rcu_sched_qs(void);
> void rcu_bh_qs(void);
> void rcu_check_callbacks(int user);
> -struct notifier_block;
> -int rcu_cpu_notify(struct notifier_block *self,
> - unsigned long action, void *hcpu);
> +void rcu_report_dead(unsigned int cpu);
>
> #ifndef CONFIG_TINY_RCU
> void rcu_end_inkernel_boot(void);
> Index: b/kernel/cpu.c
> ===================================================================
> --- a/kernel/cpu.c
> +++ b/kernel/cpu.c
> @@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void)
> BUG_ON(st->state != CPUHP_AP_OFFLINE);
> st->state = CPUHP_AP_IDLE_DEAD;
> complete(&st->done);
What prevents the other CPU from killing this CPU at this point, so
that this CPU does not tell RCU that it is dead?
I agree that the odds should be low, but there are all manner of things
that might delay a CPU for just a little bit too long...
Or am I missing something subtle here?
Thanx, Paul
> + rcu_report_dead(smp_processor_id());
> }
>
> #else
> Index: b/kernel/rcu/tree.c
> ===================================================================
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -4247,6 +4247,21 @@ static void rcu_prepare_cpu(int cpu)
> rcu_init_percpu_data(cpu, rsp);
> }
>
> +#ifdef CONFIG_HOTPLUG_CPU
> +void rcu_report_dead(unsigned int cpu)
> +{
> + struct rcu_state *rsp;
> +
> + /* QS for any half-done expedited RCU-sched GP. */
> + preempt_disable();
> + rcu_report_exp_rdp(&rcu_sched_state,
> + this_cpu_ptr(rcu_sched_state.rda), true);
> + preempt_enable();
> + for_each_rcu_flavor(rsp)
> + rcu_cleanup_dying_idle_cpu(cpu, rsp);
> +}
> +#endif
> +
> /*
> * Handle CPU online/offline notification events.
> */
> @@ -4278,17 +4293,6 @@ int rcu_cpu_notify(struct notifier_block
> for_each_rcu_flavor(rsp)
> rcu_cleanup_dying_cpu(rsp);
> break;
> - case CPU_DYING_IDLE:
> - /* QS for any half-done expedited RCU-sched GP. */
> - preempt_disable();
> - rcu_report_exp_rdp(&rcu_sched_state,
> - this_cpu_ptr(rcu_sched_state.rda), true);
> - preempt_enable();
> -
> - for_each_rcu_flavor(rsp) {
> - rcu_cleanup_dying_idle_cpu(cpu, rsp);
> - }
> - break;
> case CPU_DEAD:
> case CPU_DEAD_FROZEN:
> case CPU_UP_CANCELED:
> Index: b/kernel/sched/idle.c
> ===================================================================
> --- a/kernel/sched/idle.c
> +++ b/kernel/sched/idle.c
> @@ -220,8 +220,6 @@ static void cpu_idle_loop(void)
> rmb();
>
> if (cpu_is_offline(smp_processor_id())) {
> - rcu_cpu_notify(NULL, CPU_DYING_IDLE,
> - (void *)(long)smp_processor_id());
> cpuhp_report_idle_dead();
> arch_cpu_idle_dead();
> }
>
>
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-02-27 03:30 +0100 |
| Subject | Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6CNQ-4m4-5@gated-at.bofh.it> |
| In reply to | #1344888 |
On Fri, Feb 26, 2016 at 06:14:29PM -0800, Paul E. McKenney wrote:
> On Fri, Feb 26, 2016 at 06:43:44PM -0000, Thomas Gleixner wrote:
> > Make the RCU CPU_DYING_IDLE callback an explicit function call, so it gets
> > invoked at the proper place.
> >
> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
>
> A question below...
>
> > ---
> > include/linux/cpu.h | 4 +---
> > include/linux/notifier.h | 2 ++
> > include/linux/rcupdate.h | 4 +---
> > kernel/cpu.c | 1 +
> > kernel/rcu/tree.c | 26 +++++++++++++++-----------
> > kernel/sched/idle.c | 2 --
> > 6 files changed, 20 insertions(+), 19 deletions(-)
> >
> > Index: b/include/linux/cpu.h
> > ===================================================================
> > --- a/include/linux/cpu.h
> > +++ b/include/linux/cpu.h
> > @@ -101,9 +101,7 @@ enum {
> > * Called on the new cpu, just before
> > * enabling interrupts. Must not sleep,
> > * must not fail */
> > -#define CPU_DYING_IDLE 0x000B /* CPU (unsigned)v dying, reached
> > - * idle loop. */
> > -#define CPU_BROKEN 0x000C /* CPU (unsigned)v did not die properly,
> > +#define CPU_BROKEN 0x000B /* CPU (unsigned)v did not die properly,
> > * perhaps due to preemption. */
> >
> > /* Used for CPU hotplug events occurring while tasks are frozen due to a suspend
> > Index: b/include/linux/notifier.h
> > ===================================================================
> > --- a/include/linux/notifier.h
> > +++ b/include/linux/notifier.h
> > @@ -47,6 +47,8 @@
> > * runtime initialization.
> > */
> >
> > +struct notifier_block;
> > +
> > typedef int (*notifier_fn_t)(struct notifier_block *nb,
> > unsigned long action, void *data);
> >
> > Index: b/include/linux/rcupdate.h
> > ===================================================================
> > --- a/include/linux/rcupdate.h
> > +++ b/include/linux/rcupdate.h
> > @@ -332,9 +332,7 @@ void rcu_init(void);
> > void rcu_sched_qs(void);
> > void rcu_bh_qs(void);
> > void rcu_check_callbacks(int user);
> > -struct notifier_block;
> > -int rcu_cpu_notify(struct notifier_block *self,
> > - unsigned long action, void *hcpu);
> > +void rcu_report_dead(unsigned int cpu);
> >
> > #ifndef CONFIG_TINY_RCU
> > void rcu_end_inkernel_boot(void);
> > Index: b/kernel/cpu.c
> > ===================================================================
> > --- a/kernel/cpu.c
> > +++ b/kernel/cpu.c
> > @@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void)
> > BUG_ON(st->state != CPUHP_AP_OFFLINE);
> > st->state = CPUHP_AP_IDLE_DEAD;
> > complete(&st->done);
>
> What prevents the other CPU from killing this CPU at this point, so
> that this CPU does not tell RCU that it is dead?
>
> I agree that the odds should be low, but there are all manner of things
> that might delay a CPU for just a little bit too long...
>
> Or am I missing something subtle here?
Just in case I am not missing anything...
One approach is to go back to the spinning, but to do rcu_report_dead()
just before kicking the other CPU. This would also fix some issues with
use of RCU of the offline path, so would definitely be better than my
earlier approach of notifying RCU from within the idle loop.
This assumes that all the offline paths have been consolidated into
this path. (Yes, I was too lazy and cowardly to consolidate them all
last I touched this code, but perhaps that has happened elsewise?)
Thanx, Paul
> > + rcu_report_dead(smp_processor_id());
> > }
> >
> > #else
> > Index: b/kernel/rcu/tree.c
> > ===================================================================
> > --- a/kernel/rcu/tree.c
> > +++ b/kernel/rcu/tree.c
> > @@ -4247,6 +4247,21 @@ static void rcu_prepare_cpu(int cpu)
> > rcu_init_percpu_data(cpu, rsp);
> > }
> >
> > +#ifdef CONFIG_HOTPLUG_CPU
> > +void rcu_report_dead(unsigned int cpu)
> > +{
> > + struct rcu_state *rsp;
> > +
> > + /* QS for any half-done expedited RCU-sched GP. */
> > + preempt_disable();
> > + rcu_report_exp_rdp(&rcu_sched_state,
> > + this_cpu_ptr(rcu_sched_state.rda), true);
> > + preempt_enable();
> > + for_each_rcu_flavor(rsp)
> > + rcu_cleanup_dying_idle_cpu(cpu, rsp);
> > +}
> > +#endif
> > +
> > /*
> > * Handle CPU online/offline notification events.
> > */
> > @@ -4278,17 +4293,6 @@ int rcu_cpu_notify(struct notifier_block
> > for_each_rcu_flavor(rsp)
> > rcu_cleanup_dying_cpu(rsp);
> > break;
> > - case CPU_DYING_IDLE:
> > - /* QS for any half-done expedited RCU-sched GP. */
> > - preempt_disable();
> > - rcu_report_exp_rdp(&rcu_sched_state,
> > - this_cpu_ptr(rcu_sched_state.rda), true);
> > - preempt_enable();
> > -
> > - for_each_rcu_flavor(rsp) {
> > - rcu_cleanup_dying_idle_cpu(cpu, rsp);
> > - }
> > - break;
> > case CPU_DEAD:
> > case CPU_DEAD_FROZEN:
> > case CPU_UP_CANCELED:
> > Index: b/kernel/sched/idle.c
> > ===================================================================
> > --- a/kernel/sched/idle.c
> > +++ b/kernel/sched/idle.c
> > @@ -220,8 +220,6 @@ static void cpu_idle_loop(void)
> > rmb();
> >
> > if (cpu_is_offline(smp_processor_id())) {
> > - rcu_cpu_notify(NULL, CPU_DYING_IDLE,
> > - (void *)(long)smp_processor_id());
> > cpuhp_report_idle_dead();
> > arch_cpu_idle_dead();
> > }
> >
> >
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-27 08:50 +0100 |
| Subject | Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6HNv-88y-1@gated-at.bofh.it> |
| In reply to | #1344892 |
On Fri, 26 Feb 2016, Paul E. McKenney wrote: > > > --- a/kernel/cpu.c > > > +++ b/kernel/cpu.c > > > @@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void) > > > BUG_ON(st->state != CPUHP_AP_OFFLINE); > > > st->state = CPUHP_AP_IDLE_DEAD; > > > complete(&st->done); > > > > What prevents the other CPU from killing this CPU at this point, so > > that this CPU does not tell RCU that it is dead? > > > > I agree that the odds should be low, but there are all manner of things > > that might delay a CPU for just a little bit too long... > > > > Or am I missing something subtle here? No. The reason why I moved the rcu call past the complete is, that otherwise complete() complains about rcu being dead already. Hmm, but you are right. In theory the other side could allow physical removal before it actually told rcu that it's gone. > Just in case I am not missing anything... > > One approach is to go back to the spinning, but to do rcu_report_dead() > just before kicking the other CPU. This would also fix some issues with > use of RCU of the offline path, so would definitely be better than my > earlier approach of notifying RCU from within the idle loop. > > This assumes that all the offline paths have been consolidated into > this path. (Yes, I was too lazy and cowardly to consolidate them all > last I touched this code, but perhaps that has happened elsewise?) The question is whether the rcu dead notification has to happen instantaniously and needs to be done on the dead cpu. If we can avoid both, then there is a very simple solution. Thanks, tglx
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-02-27 12:10 +0100 |
| Subject | Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6KV4-1Yg-11@gated-at.bofh.it> |
| In reply to | #1344936 |
On Sat, Feb 27, 2016 at 08:47:41AM +0100, Thomas Gleixner wrote: > On Fri, 26 Feb 2016, Paul E. McKenney wrote: > > > > --- a/kernel/cpu.c > > > > +++ b/kernel/cpu.c > > > > @@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void) > > > > BUG_ON(st->state != CPUHP_AP_OFFLINE); > > > > st->state = CPUHP_AP_IDLE_DEAD; > > > > complete(&st->done); > > > > > > What prevents the other CPU from killing this CPU at this point, so > > > that this CPU does not tell RCU that it is dead? > > > > > > I agree that the odds should be low, but there are all manner of things > > > that might delay a CPU for just a little bit too long... > > > > > > Or am I missing something subtle here? > > No. The reason why I moved the rcu call past the complete is, that otherwise > complete() complains about rcu being dead already. Hmm, but you are right. In > theory the other side could allow physical removal before it actually told rcu > that it's gone. There is one case where this is OK, and that is where the outgoing CPU puts itself to sleep (or whatever) without help from the other CPU. > > Just in case I am not missing anything... > > > > One approach is to go back to the spinning, but to do rcu_report_dead() > > just before kicking the other CPU. This would also fix some issues with > > use of RCU of the offline path, so would definitely be better than my > > earlier approach of notifying RCU from within the idle loop. > > > > This assumes that all the offline paths have been consolidated into > > this path. (Yes, I was too lazy and cowardly to consolidate them all > > last I touched this code, but perhaps that has happened elsewise?) > > The question is whether the rcu dead notification has to happen > instantaniously and needs to be done on the dead cpu. If we can avoid both, > then there is a very simple solution. Hmmm... The rcu_cleanup_dying_idle_cpu() can be invoked from the surviving CPU, -as- -long- -as- nothing in the intervening code path waits for a grace period. The wakeup path itself had better not wait for a grace period, of course. The concern would be that the task running on the surviving CPU might be waiting for a grace period before sleeping -- which used to be possible due to the CPU-hotplug notifiers that it might be executing before getting to RCU's CPU-hotplug notifiers. The rcu_report_exp_rdp() is considerably more scary. At first glance, it looks OK, but I will need to stare at it for a bit. Of course, if the task running on the surviving CPU can be waiting for a grace period, one of two problems can happen: o RCU times out the outgoing CPU before it has really left. This is the current state, and needs to change. The dying idle stuff was half of the needed change, the other half being on the incoming side. o Deadlock -- the outgoing CPU won't respond to RCU, so the task running on the surviving CPU never wakes up from its wait on a grace period. So if rcu_report_exp_rdp() turns out to be OK -and- if the outgoing task never waits on a grace period during the CPU-shutdown process, this might work. Of course, my ability to test this sufficiently viciously is currently blocked by the lost-wakeup problem I am currently chasing. (Hey, at least I finally get ftrace output! Completely baffling output, but so it goes...) :-/ Thanx, Paul
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-27 12:40 +0100 |
| Subject | Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6Lo6-2g0-5@gated-at.bofh.it> |
| In reply to | #1344986 |
On Sat, 27 Feb 2016, Paul E. McKenney wrote: > On Sat, Feb 27, 2016 at 08:47:41AM +0100, Thomas Gleixner wrote: > > On Fri, 26 Feb 2016, Paul E. McKenney wrote: > > > > > --- a/kernel/cpu.c > > > > > +++ b/kernel/cpu.c > > > > > @@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void) > > > > > BUG_ON(st->state != CPUHP_AP_OFFLINE); > > > > > st->state = CPUHP_AP_IDLE_DEAD; > > > > > complete(&st->done); > > > > > > > > What prevents the other CPU from killing this CPU at this point, so > > > > that this CPU does not tell RCU that it is dead? > > > > > > > > I agree that the odds should be low, but there are all manner of things > > > > that might delay a CPU for just a little bit too long... > > > > > > > > Or am I missing something subtle here? > > > > No. The reason why I moved the rcu call past the complete is, that otherwise > > complete() complains about rcu being dead already. Hmm, but you are right. In > > theory the other side could allow physical removal before it actually told rcu > > that it's gone. > > There is one case where this is OK, and that is where the outgoing CPU > puts itself to sleep (or whatever) without help from the other CPU. That's the case. It's the last call before the outgoing CPU goes into arch_cpu_idle_dead(). There is no involvement of the controlling CPU at this point. It just wants to know, that the outgoing one is dead finally. Thanks, tglx
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-02-27 17:40 +0100 |
| Subject | Re: [patch 20/20] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r6Q4q-5OJ-15@gated-at.bofh.it> |
| In reply to | #1344992 |
On Sat, Feb 27, 2016 at 12:30:33PM +0100, Thomas Gleixner wrote: > On Sat, 27 Feb 2016, Paul E. McKenney wrote: > > On Sat, Feb 27, 2016 at 08:47:41AM +0100, Thomas Gleixner wrote: > > > On Fri, 26 Feb 2016, Paul E. McKenney wrote: > > > > > > --- a/kernel/cpu.c > > > > > > +++ b/kernel/cpu.c > > > > > > @@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void) > > > > > > BUG_ON(st->state != CPUHP_AP_OFFLINE); > > > > > > st->state = CPUHP_AP_IDLE_DEAD; > > > > > > complete(&st->done); > > > > > > > > > > What prevents the other CPU from killing this CPU at this point, so > > > > > that this CPU does not tell RCU that it is dead? > > > > > > > > > > I agree that the odds should be low, but there are all manner of things > > > > > that might delay a CPU for just a little bit too long... > > > > > > > > > > Or am I missing something subtle here? > > > > > > No. The reason why I moved the rcu call past the complete is, that otherwise > > > complete() complains about rcu being dead already. Hmm, but you are right. In > > > theory the other side could allow physical removal before it actually told rcu > > > that it's gone. > > > > There is one case where this is OK, and that is where the outgoing CPU > > puts itself to sleep (or whatever) without help from the other CPU. > > That's the case. It's the last call before the outgoing CPU goes into > arch_cpu_idle_dead(). There is no involvement of the controlling CPU at this > point. It just wants to know, that the outgoing one is dead finally. Ah, so you have gotten rid of all the things like arm's and xtensa's platform_cpu_kill(), where the surviving CPU does things like stopping the outgoing CPU's clock? That would make things simpler! Thanx, Paul
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Thomas Gleixner <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-01 21:00 +0100 |
| Subject | [tip:smp/hotplug] rcu: Make CPU_DYING_IDLE an explicit call |
| Message-ID | <r7YCE-5hG-53@gated-at.bofh.it> |
| In reply to | #1344575 |
Commit-ID: 27d50c7eeb0f03c3d3ca72aac4d2dd487ca1f3f0
Gitweb: http://git.kernel.org/tip/27d50c7eeb0f03c3d3ca72aac4d2dd487ca1f3f0
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Fri, 26 Feb 2016 18:43:44 +0000
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 1 Mar 2016 20:36:58 +0100
rcu: Make CPU_DYING_IDLE an explicit call
Make the RCU CPU_DYING_IDLE callback an explicit function call, so it gets
invoked at the proper place.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: Rik van Riel <riel@redhat.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20160226182341.870167933@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/cpu.h | 4 +--
include/linux/notifier.h | 2 ++
include/linux/rcupdate.h | 4 +--
kernel/cpu.c | 1 +
kernel/rcu/tree.c | 70 +++++++++++++++++++++++++-----------------------
kernel/sched/idle.c | 2 --
6 files changed, 42 insertions(+), 41 deletions(-)
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 91a48d1..f9b1fab 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -101,9 +101,7 @@ enum {
* Called on the new cpu, just before
* enabling interrupts. Must not sleep,
* must not fail */
-#define CPU_DYING_IDLE 0x000B /* CPU (unsigned)v dying, reached
- * idle loop. */
-#define CPU_BROKEN 0x000C /* CPU (unsigned)v did not die properly,
+#define CPU_BROKEN 0x000B /* CPU (unsigned)v did not die properly,
* perhaps due to preemption. */
/* Used for CPU hotplug events occurring while tasks are frozen due to a suspend
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index d14a4c3..4149868 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -47,6 +47,8 @@
* runtime initialization.
*/
+struct notifier_block;
+
typedef int (*notifier_fn_t)(struct notifier_block *nb,
unsigned long action, void *data);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 14e6f47..fc46fe3 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -332,9 +332,7 @@ void rcu_init(void);
void rcu_sched_qs(void);
void rcu_bh_qs(void);
void rcu_check_callbacks(int user);
-struct notifier_block;
-int rcu_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu);
+void rcu_report_dead(unsigned int cpu);
#ifndef CONFIG_TINY_RCU
void rcu_end_inkernel_boot(void);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 0e8c07f..ff8059b 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -762,6 +762,7 @@ void cpuhp_report_idle_dead(void)
BUG_ON(st->state != CPUHP_AP_OFFLINE);
st->state = CPUHP_AP_IDLE_DEAD;
complete(&st->done);
+ rcu_report_dead(smp_processor_id());
}
#else
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index e41dd41..85b4134 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -2607,28 +2607,6 @@ static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf)
}
/*
- * The CPU is exiting the idle loop into the arch_cpu_idle_dead()
- * function. We now remove it from the rcu_node tree's ->qsmaskinit
- * bit masks.
- */
-static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp)
-{
- unsigned long flags;
- unsigned long mask;
- struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
- struct rcu_node *rnp = rdp->mynode; /* Outgoing CPU's rdp & rnp. */
-
- if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
- return;
-
- /* Remove outgoing CPU from mask in the leaf rcu_node structure. */
- mask = rdp->grpmask;
- raw_spin_lock_irqsave_rcu_node(rnp, flags); /* Enforce GP memory-order guarantee. */
- rnp->qsmaskinitnext &= ~mask;
- raw_spin_unlock_irqrestore(&rnp->lock, flags);
-}
-
-/*
* The CPU has been completely removed, and some other CPU is reporting
* this fact from process context. Do the remainder of the cleanup,
* including orphaning the outgoing CPU's RCU callbacks, and also
@@ -4247,6 +4225,43 @@ static void rcu_prepare_cpu(int cpu)
rcu_init_percpu_data(cpu, rsp);
}
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * The CPU is exiting the idle loop into the arch_cpu_idle_dead()
+ * function. We now remove it from the rcu_node tree's ->qsmaskinit
+ * bit masks.
+ */
+static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp)
+{
+ unsigned long flags;
+ unsigned long mask;
+ struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
+ struct rcu_node *rnp = rdp->mynode; /* Outgoing CPU's rdp & rnp. */
+
+ if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
+ return;
+
+ /* Remove outgoing CPU from mask in the leaf rcu_node structure. */
+ mask = rdp->grpmask;
+ raw_spin_lock_irqsave_rcu_node(rnp, flags); /* Enforce GP memory-order guarantee. */
+ rnp->qsmaskinitnext &= ~mask;
+ raw_spin_unlock_irqrestore(&rnp->lock, flags);
+}
+
+void rcu_report_dead(unsigned int cpu)
+{
+ struct rcu_state *rsp;
+
+ /* QS for any half-done expedited RCU-sched GP. */
+ preempt_disable();
+ rcu_report_exp_rdp(&rcu_sched_state,
+ this_cpu_ptr(rcu_sched_state.rda), true);
+ preempt_enable();
+ for_each_rcu_flavor(rsp)
+ rcu_cleanup_dying_idle_cpu(cpu, rsp);
+}
+#endif
+
/*
* Handle CPU online/offline notification events.
*/
@@ -4278,17 +4293,6 @@ int rcu_cpu_notify(struct notifier_block *self,
for_each_rcu_flavor(rsp)
rcu_cleanup_dying_cpu(rsp);
break;
- case CPU_DYING_IDLE:
- /* QS for any half-done expedited RCU-sched GP. */
- preempt_disable();
- rcu_report_exp_rdp(&rcu_sched_state,
- this_cpu_ptr(rcu_sched_state.rda), true);
- preempt_enable();
-
- for_each_rcu_flavor(rsp) {
- rcu_cleanup_dying_idle_cpu(cpu, rsp);
- }
- break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 8abbe89..bd12c6c 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -220,8 +220,6 @@ static void cpu_idle_loop(void)
rmb();
if (cpu_is_offline(smp_processor_id())) {
- rcu_cpu_notify(NULL, CPU_DYING_IDLE,
- (void *)(long)smp_processor_id());
cpuhp_report_idle_dead();
arch_cpu_idle_dead();
}
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | linux.kernel
csiph-web