From: "Jürgen Groß" <jgross@suse.com>
To: Furkan Caliskan <frn1furkan10@gmail.com>, xen-devel@lists.xenproject.org
Cc: jbeulich@suse.com, andrew.cooper3@citrix.com, dfaggioli@suse.com,
gwd@xenproject.org, roger@xenproject.org,
anthony.perard@vates.tech, julien@xen.org,
bertrand.marquis@arm.com, michal.orzel@amd.com,
Volodymyr_Babchuk@epam.com, teddy.astie@vates.tech
Subject: Re: [PATCH v3 1/2] xen/common: add vcpus_create() and keep max_vcpus in sync
Date: Mon, 31 Aug 2026 10:13:20 +0200 [thread overview]
Message-ID: <33c1d613-054e-4940-a14d-9e47e673286b@suse.com> (raw)
In-Reply-To: <20260831051637.5029-2-frn1furkan10@gmail.com>
[-- Attachment #1.1.1: Type: text/plain, Size: 5083 bytes --]
On 31.08.26 07:16, Furkan Caliskan wrote:
> Every vcpu_create() call site that builds more than one vcpu loops
> over ids up to d->max_vcpus and stops on the first failure, but none
> of them roll max_vcpus back to match. This leaves d->vcpu[i] == NULL
> for ids below max_vcpus, which anything walking d->vcpu[] can then
> dereference. This is what caused the crash: sched_move_domain()
> walks every vcpu slot up to max_vcpus without checking for empty
> ones, so when a domain built in a non-default cpupool had vcpu
> creation fail partway through, domain_kill() later moving it back
> to the default cpupool handed one of its empty slots straight to
> the new cpupool's scheduler, causing a NULL-pointer dereference
> inside sched_alloc_udata().
>
> Add vcpus_create(d): creates every vcpu of d up to max_vcpus and
> rolls max_vcpus back to the failed id on error. This keeps
> d->vcpu[i] is non-NULL for all i < d->max_vcpus, instead of guarding
> every reader of d->vcpu[] agains holes individually.
>
> Convert every site that builds vcpus in a loop to call this function
> instead.
>
> Fixes: 61649709421a ("xen/domain: Allocate d->vcpu[] in domain_create()")
> Suggested-by: Juergen Gross <jgross@suse.com>
> Signed-off-by: Furkan Caliskan <frn1furkan10@gmail.com>
> ---
> v3:
> - Reworked per Juergen's suggestion: instead of guarding
> sched_move_domain() against a missing vcpu slot, keep d->max_vcpus
> in sync with the vcpus actually created. Added vcpus_create() and
> converted every vcpu_create() loop to use it.
> - Reverted the sched_move_domain() check from v2, now unneeded.
> ---
> xen/arch/arm/domain_build.c | 15 +++++++--------
> xen/arch/x86/mm/mem_sharing.c | 11 ++---------
> xen/common/domain.c | 24 ++++++++++++++++++++++++
> xen/common/domctl.c | 19 ++++---------------
> xen/common/sched/core.c | 7 +++----
> xen/include/xen/domain.h | 1 +
> 6 files changed, 41 insertions(+), 36 deletions(-)
>
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index 72d5316180..e08ee21ee5 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -1774,6 +1774,7 @@ static void __init find_gnttab_region(struct domain *d,
> int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
> {
> unsigned int i;
> + int rc;
> struct vcpu *v = d->vcpu[0];
> struct cpu_user_regs *regs = &v->arch.cpu_info->guest_cpu_user_regs;
>
> @@ -1842,17 +1843,15 @@ int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
> }
> #endif
>
> - for ( i = 1; i < d->max_vcpus; i++ )
> + if ( (rc = vcpus_create(d)) )
> {
> - if ( vcpu_create(d, i) == NULL )
> - {
> - printk("Failed to allocate d%dv%d\n", d->domain_id, i);
> - return -ENOMEM;
> - }
> + printk("Failed to allocate d%dv%d\n", d->domain_id, d->max_vcpus);
> + return rc;
> + }
>
> - if ( is_64bit_domain(d) )
> + if ( is_64bit_domain(d) )
> + for ( i = 1; i < d->max_vcpus; i++ )
> vcpu_switch_to_aarch64_mode(d->vcpu[i]);
> - }
>
> domain_update_node_affinity(d);
>
> diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
> index 5c7a0ff30e..cd7f747c80 100644
> --- a/xen/arch/x86/mm/mem_sharing.c
> +++ b/xen/arch/x86/mm/mem_sharing.c
> @@ -1612,21 +1612,14 @@ int mem_sharing_fork_page(struct domain *d, gfn_t gfn, bool unsharing)
>
> static int bring_up_vcpus(struct domain *cd, struct domain *d)
> {
> - unsigned int i;
> int ret = -EINVAL;
>
> if ( d->max_vcpus != cd->max_vcpus ||
> (ret = cpupool_move_domain(cd, d->cpupool)) )
> return ret;
>
> - for ( i = 0; i < cd->max_vcpus; i++ )
> - {
> - if ( !d->vcpu[i] || cd->vcpu[i] )
> - continue;
> -
> - if ( !vcpu_create(cd, i) )
> - return -EINVAL;
> - }
> + if ( (ret = vcpus_create(cd)) )
> + return ret;
>
> domain_update_node_affinity(cd);
> return 0;
> diff --git a/xen/common/domain.c b/xen/common/domain.c
> index e16f1ac383..a0a3e51b15 100644
> --- a/xen/common/domain.c
> +++ b/xen/common/domain.c
> @@ -539,6 +539,30 @@ struct vcpu *vcpu_create(struct domain *d, unsigned int vcpu_id)
> return NULL;
> }
>
> +/*
> + * Create every not yet existing vcpu of d, up to d->max_vcpus. On failure,
> + * d->max_vcpus is rolled back to the id that failed, keeping d->vcpu[i]
> + * non-NULL for all i < d->max_vcpus.
> + */
> +int vcpus_create(struct domain *d)
> +{
> + unsigned int i;
> +
> + for ( i = 0; i < d->max_vcpus; i++ )
> + {
> + if ( d->vcpu[i] )
> + continue;
> +
> + if ( vcpu_create(d, i) == NULL )
> + {
> + d->max_vcpus = i;
> + return -EINVAL;
I think this should be -ENOMEM.
Juergen
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
next prev parent reply other threads:[~2026-08-31 8:13 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 5:16 [PATCH v3 0/2] xen/sched: fix crashes when vcpu creation fails Furkan Caliskan
2026-08-31 5:16 ` [PATCH v3 1/2] xen/common: add vcpus_create() and keep max_vcpus in sync Furkan Caliskan
2026-08-31 8:13 ` Jürgen Groß [this message]
2026-08-31 9:13 ` Furkan Çalışkan
2026-08-31 9:32 ` [PATCH v4] " Furkan Caliskan
2026-08-31 9:45 ` [PATCH v3 1/2] " Andrew Cooper
2026-08-31 12:59 ` Jürgen Groß
2026-09-01 7:22 ` Jan Beulich
2026-09-01 8:07 ` Jürgen Groß
2026-09-01 8:15 ` Jan Beulich
2026-09-01 8:24 ` Jürgen Groß
2026-09-01 8:36 ` Jan Beulich
2026-09-01 9:03 ` Jürgen Groß
2026-08-31 5:16 ` [PATCH v3 2/2] xen/sched: core: kill unarmed timers on sched_init_vcpu() failure Furkan Caliskan
2026-08-31 8:15 ` Jürgen Groß
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=33c1d613-054e-4940-a14d-9e47e673286b@suse.com \
--to=jgross@suse.com \
--cc=Volodymyr_Babchuk@epam.com \
--cc=andrew.cooper3@citrix.com \
--cc=anthony.perard@vates.tech \
--cc=bertrand.marquis@arm.com \
--cc=dfaggioli@suse.com \
--cc=frn1furkan10@gmail.com \
--cc=gwd@xenproject.org \
--cc=jbeulich@suse.com \
--cc=julien@xen.org \
--cc=michal.orzel@amd.com \
--cc=roger@xenproject.org \
--cc=teddy.astie@vates.tech \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.