Re: [PATCH 1/2] xen/sched: core: skip missing vcpu slots in sched_move_domain()
Juergen Gross <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <[email protected]> |
On 18.08.26 12:35, Andrew Cooper wrote: > On 18/08/2026 11:13 am, Jürgen Groß wrote: >> On 18.08.26 12:04, Andrew Cooper wrote: >>> On 18/08/2026 8:53 am, Furkan Çalışkan wrote: >>>> On 8/18/26 10:11, Jürgen Groß wrote: >>>>> On 18.08.26 08:32, Furkan Caliskan wrote: >>>>>> 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 that all of >>>>>> its vcpu slots are populated, and skip it if any are missing. The >>>>>> rest of the function walks the vcpus that actually exist, via >>>>>> for_each_vcpu() rather than n_units, so skipping a unit here >>>>>> does not leave anything else out of sync. >>>>>> >>>>>> Signed-off-by: Furkan Caliskan <[email protected]> >>>>>> --- >>>>>> xen/common/sched/core.c | 19 +++++++++++++++++++ >>>>>> 1 file changed, 19 insertions(+) >>>>>> >>>>>> diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c >>>>>> index d3a0a97e1d..d542c76543 100644 >>>>>> --- a/xen/common/sched/core.c >>>>>> +++ b/xen/common/sched/core.c >>>>>> @@ -745,6 +745,25 @@ int sched_move_domain(struct domain *d, >>>>>> struct cpupool *c) >>>>>> for ( unit_idx = 0; unit_idx < n_units; unit_idx++ ) >>>>>> { >>>>>> + /* >>>>>> + * Skip this unit if any of its vcpus is missing. Bounded by >>>>>> + * max_vcpus. >>>>>> + */ >>>>>> + 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 ) >>>>>> + continue; >>>>> I don't think this is correct. >>>>> >>>>> If there are some vcpus in the unit you will loose them (i.e. make >>>>> them no >>>>> longer be able to be scheduled), right? >>>>> >>>>> For a dying domain this might be okay, but not for one still >>>>> active. So I think >>>>> you should at least verify the domain is dying, otherwise >>>>> sched_move_domain() >>>>> should just fail. >>>>> >>>>> An alternative might be to fix the NULL dereferencing where needed, >>>>> but this >>>>> could become tedious. >>>>> >>>>> >>>>> Juergen >>>> Right. My initial attempt only checked 'd->vcpu[unit_idx*gran]' >>>> for the head vCPU. The crash happens when unit->vcpu_list is set >>>> to d->vcpu[unit_idx*gran] (which is NULL) and passed to >>>> 'alloc_udata()', >>>> causing a NULL dereference. >>>> >>>> I expanded the loop over 'gran' to handle core-scheduling cases where a >>>> subsequent vCPU fails mid-unit, but as you pointed out, that drops the >>>> whole unit for active domain. >>>> >>>> I'll update the patch to check d->is_dying to skip incomplete units >>>> only for dying domains, and have sched_move_domain() fail if an active >>>> domain has missing vCPUs >>> >>> I'm afraid that wont fix everything. >> >> Why not? > > domU's in this situation do not have is_dying set. Please clarify what you mean with "this situation". sched_move_domain() is being called either due to an admin action ("xl cpupool-migrate"), or during domain_kill() in order to move the domain to cpupool0 for avoiding a zombie domain blocking cpupool removal. The first case is allowed to fail, which the suggested fix would do, while the second case is happening only after DOMDYING_dying has been set for the domain. Juergen
OpenPGP_0xB0DE9DD628BF132F.asc
(application/pgp-keys, 3.6 KB)
-----BEGIN PGP PUBLIC KEY BLOCK----- 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 kt+z4drzFUyEjLM1vVvIMjkUoJs= =eeAB -----END PGP PUBLIC KEY BLOCK-----
OpenPGP_signature.asc
(application/pgp-signature, 495 B)
-----BEGIN PGP SIGNATURE----- wsB5BAABCAAjFiEEhRJncuj2BJSl0Jf3sN6d1ii/Ey8FAmqEOEUFAwAAAAAACgkQsN6d1ii/Ey/5 2QgAir7+RRdj7Ppt76PZ+PY/ynyBAS2m+1QjvErVZlp6atv8ZcyUy6irqmaf16M/YDLxM7/t+QFc lDIiqZKDoH1CWOgp7QDg8ZsP45Zj/4MyRaScucfCGzLH9bOqX+UPzPe31f8LmFCXKOyHE16m7kGt WfNnJAwMsEvmr6GPAPJrpdN223F7wL7T1XHL9iGG5Df56YXxh4L7wQk1XmlFRAOWdBJZIsZzwoFr 6cs9wTSs1Zivt+upHUxACS5YFCREcdUP5S0Y+UmivObcwD/B18nZwNULBOxTfXHs5CZ8NcJcSRZu SqlrmWuvo7Dn5B9Gq/bKyEEy66UfvpA58k6HPpt5GA== =poQi -----END PGP SIGNATURE-----