mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/sched: core: skip missing vcpu slots in sched_move_domain()
sched_move_domain() derives the number of units to rebuild from d->max_vcpus, which is fixed at domain creation and never rolled back if vcpu_create() fails partway through building a domain. So d->vcpu[i] can be NULL for some i even though max_vcpus still counts it - this happens if sched_alloc_udata() returns NULL. The per-unit loop doesn't check for this: it sets unit->vcpu_list = d->vcpu[unit_id] (NULL) and hands that broken unit straight to the destination scheduler's alloc_udata(), which assumes vcpu_list is always valid and crashes Xen when it is not. Reproduced by building a domain in a non-default cpupool where vcpu creation fails partway through, then destroying it. domain_kill() moves the domain back to the default cpupool via sched_move_domain() before actually destroying it, crashing inside the destination scheduler's alloc_udata() (seen in Credit2's csched2_alloc_udata() -> is_idle_unit() -> NULL deref). Before building a unit in sched_move_domain(), check whether all vpcu slots belonging to that unit are populated. If any of its vpcus is missing: - For a dying domain, skip the unit allocation. - For an active domain, abort the move and return -EINVAL to prevent running with dropped vCPUs. Fixes:70fadc4163("xen/cpupool: support moving domain between cpupools with different granularity") Signed-off-by: Furkan Caliskan <frn1furkan10@gmail.com> Reviewed-by: Juergen Gross <jgross@suse.com> master commit:4835c078e5master date: 2026-09-21 09:54:12 +0200
This commit is contained in:
1 parent
9ee0c50a0e
commit
ad19295d65
1 file changed
+32
@@ -721,6 +721,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 )
|
||||
{
|
||||
|
||||