diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c index ee24cc28f6..17e7f52169 100644 --- a/xen/common/sched/core.c +++ b/xen/common/sched/core.c @@ -745,6 +745,38 @@ int sched_move_domain(struct domain *d, struct cpupool *c) for ( unit_idx = 0; unit_idx < n_units; unit_idx++ ) { + /* + * A vcpu slot can be missing if creation failed partway + * through. A dying domain is being torn down regardless, so + * skip the unit -- but a domain that isn't dying still needs + * every vcpu it has schedulable, so fail instead of silently + * dropping some of them. + */ + bool vcpu_failed = false; + + for ( unsigned int i = 0; + i < gran && unit_idx * gran + i < d->max_vcpus; i++ ) + { + if ( !d->vcpu[unit_idx * gran + i] ) + { + vcpu_failed = true; + break; + } + } + + if ( vcpu_failed ) + { + if ( !d->is_dying ) + { + sched_move_domain_cleanup(c->sched, new_units, domdata); + rcu_read_unlock(&sched_res_rculock); + + return -EINVAL; + } + + continue; + } + unit = sched_alloc_unit_mem(); if ( unit ) {