diff --git a/xen/common/sched_credit2.c b/xen/common/sched_credit2.c index ce0e146241..2ce738dcd9 100644 --- a/xen/common/sched_credit2.c +++ b/xen/common/sched_credit2.c @@ -1946,13 +1946,43 @@ static void csched2_vcpu_migrate( const struct scheduler *ops, struct vcpu *vc, unsigned int new_cpu) { + struct domain *d = vc->domain; struct csched2_vcpu * const svc = CSCHED2_VCPU(vc); struct csched2_runqueue_data *trqd; + s_time_t now = NOW(); /* Check if new_cpu is valid */ ASSERT(cpumask_test_cpu(new_cpu, &CSCHED2_PRIV(ops)->initialized)); ASSERT(cpumask_test_cpu(new_cpu, vc->cpu_hard_affinity)); + /* + * Being passed a target pCPU which is outside of our cpupool is only + * valid if we are shutting down (or doing ACPI suspend), and we are + * moving everyone to BSP, no matter whether or not BSP is inside our + * cpupool. + * + * And since there indeed is the chance that it is not part of it, all + * we must do is remove _and_ unassign the vCPU from any runqueue, as + * well as updating v->processor with the target, so that the suspend + * process can continue. + * + * It will then be during resume that a new, meaningful, value for + * v->processor will be chosen, and during actual domain unpause that + * the vCPU will be assigned to and added to the proper runqueue. + */ + if ( unlikely(!cpumask_test_cpu(new_cpu, cpupool_domain_cpumask(d))) ) + { + ASSERT(system_state == SYS_STATE_suspend); + if ( __vcpu_on_runq(svc) ) + { + __runq_remove(svc); + update_load(ops, svc->rqd, NULL, -1, now); + } + __runq_deassign(svc); + vc->processor = new_cpu; + return; + } + trqd = RQD(ops, new_cpu); /* @@ -1964,7 +1994,7 @@ csched2_vcpu_migrate( * pointing to a pcpu where we can't run any longer. */ if ( trqd != svc->rqd ) - migrate(ops, svc, trqd, NOW()); + migrate(ops, svc, trqd, now); else vc->processor = new_cpu; } diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 5b444c4425..36ff2e93c4 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -633,8 +633,11 @@ void vcpu_force_reschedule(struct vcpu *v) void restore_vcpu_affinity(struct domain *d) { + unsigned int cpu = smp_processor_id(); struct vcpu *v; + ASSERT(system_state == SYS_STATE_resume); + for_each_vcpu ( d, v ) { spinlock_t *lock = vcpu_schedule_lock_irq(v); @@ -643,18 +646,34 @@ void restore_vcpu_affinity(struct domain *d) { cpumask_copy(v->cpu_hard_affinity, v->cpu_hard_affinity_saved); v->affinity_broken = 0; + } - if ( v->processor == smp_processor_id() ) + /* + * During suspend (in cpu_disable_scheduler()), we moved every vCPU + * to BSP (which, as of now, is pCPU 0), as a temporary measure to + * allow the nonboot processors to have their data structure freed + * and go to sleep. But nothing guardantees that the BSP is a valid + * pCPU for a particular domain. + * + * Therefore, here, before actually unpausing the domains, we should + * set v->processor of each of their vCPUs to something that will + * make sense for the scheduler of the cpupool in which they are in. + */ + cpumask_and(cpumask_scratch_cpu(cpu), v->cpu_hard_affinity, + cpupool_domain_cpumask(v->domain)); + v->processor = cpumask_any(cpumask_scratch_cpu(cpu)); + + if ( v->processor == cpu ) { set_bit(_VPF_migrating, &v->pause_flags); - vcpu_schedule_unlock_irq(lock, v); + spin_unlock_irq(lock);; vcpu_sleep_nosync(v); vcpu_migrate(v); } else { - vcpu_schedule_unlock_irq(lock, v); + spin_unlock_irq(lock); } }