mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/sched: call cpu_disable_scheduler() via cpu notifier
cpu_disable_scheduler() is being called from __cpu_disable() today. There is no need to execute it on the cpu just being disabled, so use the CPU_DEAD case of the cpu notifier chain. Moving the call out of stop_machine() context is fine, as we just need to hold the domain RCU lock and need the scheduler percpu data to be still allocated. Add another hook for CPU_DOWN_PREPARE to bail out early in case cpu_disable_scheduler() would fail. This will avoid crashes in rare cases for cpu hotplug or suspend. Signed-off-by: Juergen Gross <jgross@suse.com> Acked-by: Julien Grall <julien.grall@arm.com> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
1 parent
7f6658d9cb
commit
9b28696502
3 files changed
+29
-12
No files matched your search
@@ -386,8 +386,6 @@ void __cpu_disable(void)
|
||||
/* It's now safe to remove this processor from the online map */
|
||||
cpumask_clear_cpu(cpu, &cpu_online_map);
|
||||
|
||||
if ( cpu_disable_scheduler(cpu) )
|
||||
BUG();
|
||||
smp_mb();
|
||||
|
||||
/* Return to caller; eventually the IPI mechanism will unwind and the
|
||||
|
||||
@@ -1221,9 +1221,6 @@ void __cpu_disable(void)
|
||||
cpumask_clear_cpu(cpu, &cpu_online_map);
|
||||
fixup_irqs(&cpu_online_map, 1);
|
||||
fixup_eoi();
|
||||
|
||||
if ( cpu_disable_scheduler(cpu) )
|
||||
BUG();
|
||||
}
|
||||
|
||||
void __cpu_die(unsigned int cpu)
|
||||
|
||||
+29
-7
@@ -773,8 +773,9 @@ void restore_vcpu_affinity(struct domain *d)
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used by cpu_hotplug code from stop_machine context
|
||||
* This function is used by cpu_hotplug code via cpu notifier chain
|
||||
* and from cpupools to switch schedulers on a cpu.
|
||||
* Caller must get domlist_read_lock.
|
||||
*/
|
||||
int cpu_disable_scheduler(unsigned int cpu)
|
||||
{
|
||||
@@ -789,12 +790,6 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
if ( c == NULL )
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We'd need the domain RCU lock, but:
|
||||
* - when we are called from cpupool code, it's acquired there already;
|
||||
* - when we are called for CPU teardown, we're in stop-machine context,
|
||||
* so that's not be a problem.
|
||||
*/
|
||||
for_each_domain_in_cpupool ( d, c )
|
||||
{
|
||||
for_each_vcpu ( d, v )
|
||||
@@ -893,6 +888,24 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cpu_disable_scheduler_check(unsigned int cpu)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
struct cpupool *c;
|
||||
|
||||
c = per_cpu(cpupool, cpu);
|
||||
if ( c == NULL )
|
||||
return 0;
|
||||
|
||||
for_each_domain_in_cpupool ( d, c )
|
||||
for_each_vcpu ( d, v )
|
||||
if ( v->affinity_broken )
|
||||
return -EADDRINUSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In general, this must be called with the scheduler lock held, because the
|
||||
* adjust_affinity hook may want to modify the vCPU state. However, when the
|
||||
@@ -1734,7 +1747,16 @@ static int cpu_schedule_callback(
|
||||
case CPU_UP_PREPARE:
|
||||
rc = cpu_schedule_up(cpu);
|
||||
break;
|
||||
case CPU_DOWN_PREPARE:
|
||||
rcu_read_lock(&domlist_read_lock);
|
||||
rc = cpu_disable_scheduler_check(cpu);
|
||||
rcu_read_unlock(&domlist_read_lock);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
rcu_read_lock(&domlist_read_lock);
|
||||
rc = cpu_disable_scheduler(cpu);
|
||||
BUG_ON(rc);
|
||||
rcu_read_unlock(&domlist_read_lock);
|
||||
SCHED_OP(sched, deinit_pdata, sd->sched_priv, cpu);
|
||||
/* Fallthrough */
|
||||
case CPU_UP_CANCELED:
|
||||
|
||||