HOTPLUG: Add CPU_DYING notifier
KVM wants a notification when a cpu is about to die, so it can disable hardware extensions, but at a time when user processes cannot be scheduled on the cpu, so it doesn't try to use virtualization extensions after they have been disabled. This adds a CPU_DYING notification. The notification is called in atomic context on the doomed cpu. Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
e495606dd0
commit
db912f9639
|
@ -196,6 +196,8 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
|||
#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */
|
||||
#define CPU_LOCK_ACQUIRE 0x0008 /* Acquire all hotcpu locks */
|
||||
#define CPU_LOCK_RELEASE 0x0009 /* Release all hotcpu locks */
|
||||
#define CPU_DYING 0x000A /* CPU (unsigned)v not running any task,
|
||||
* not handling interrupts, soon dead */
|
||||
|
||||
/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
|
||||
* operation in progress
|
||||
|
@ -208,6 +210,7 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
|||
#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
|
||||
#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
|
||||
#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN)
|
||||
#define CPU_DYING_FROZEN (CPU_DYING | CPU_TASKS_FROZEN)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_NOTIFIER_H */
|
||||
|
|
16
kernel/cpu.c
16
kernel/cpu.c
|
@ -103,11 +103,19 @@ static inline void check_for_tasks(int cpu)
|
|||
write_unlock_irq(&tasklist_lock);
|
||||
}
|
||||
|
||||
struct take_cpu_down_param {
|
||||
unsigned long mod;
|
||||
void *hcpu;
|
||||
};
|
||||
|
||||
/* Take this CPU down. */
|
||||
static int take_cpu_down(void *unused)
|
||||
static int take_cpu_down(void *_param)
|
||||
{
|
||||
struct take_cpu_down_param *param = _param;
|
||||
int err;
|
||||
|
||||
raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
|
||||
param->hcpu);
|
||||
/* Ensure this CPU doesn't handle any more interrupts. */
|
||||
err = __cpu_disable();
|
||||
if (err < 0)
|
||||
|
@ -127,6 +135,10 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
|
|||
cpumask_t old_allowed, tmp;
|
||||
void *hcpu = (void *)(long)cpu;
|
||||
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
|
||||
struct take_cpu_down_param tcd_param = {
|
||||
.mod = mod,
|
||||
.hcpu = hcpu,
|
||||
};
|
||||
|
||||
if (num_online_cpus() == 1)
|
||||
return -EBUSY;
|
||||
|
@ -153,7 +165,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
|
|||
set_cpus_allowed(current, tmp);
|
||||
|
||||
mutex_lock(&cpu_bitmask_lock);
|
||||
p = __stop_machine_run(take_cpu_down, NULL, cpu);
|
||||
p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
|
||||
mutex_unlock(&cpu_bitmask_lock);
|
||||
|
||||
if (IS_ERR(p) || cpu_online(cpu)) {
|
||||
|
|
Loading…
Reference in New Issue