* [PATCH v2 1/7] KVM: Reject attempts to lock all vCPUs if vCPU creation is in-progress
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 2/7] KVM: arm64: vgic: Rely on vCPU creation check in "trylock all vCPUs" Sean Christopherson
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
Reject locking of all vCPUs if vCPU creation is in-progress, i.e. if the
number of "created" vCPUs doesn't match the number of "onlined" vCPUs.
It's simply not possible to guarantee that KVM has truly locked all vCPUs
if one or more vCPUs are actively being created. Holding kvm->lock does
prevent in-flight vCPUs from being fully onlined, but it's infeasible for
common KVM to know whether or not that provides sufficient protection.
In practice, this is likely a minor bug fix for the ARM and RISC-V usage of
kvm_trylock_all_vcpus(), and a glorified nop for everything else. E.g.
ARM's kvm_timer_vcpu_init() can race kvm_vm_ioctl_set_counter_offset() with
respect to observing KVM_ARCH_FLAG_VM_COUNTER_OFFSET.
Opportunistically drop x86's existing manual checks on vCPU creation being
in-progress as all of x86's checks immediately precede or follow locking of
all vCPUs. Leave arm64 and RISC-V alone for the moment, as their checks
aren't as obviously redundant/equivalent.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/svm/sev.c | 10 ----------
arch/x86/kvm/vmx/tdx.c | 5 -----
virt/kvm/kvm_main.c | 6 ++++++
3 files changed, 6 insertions(+), 15 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 5705723f1f41..068f8a236a35 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -1125,9 +1125,6 @@ static int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
if (!sev_es_guest(kvm))
return -ENOTTY;
- if (kvm_is_vcpu_creation_in_progress(kvm))
- return -EBUSY;
-
ret = kvm_lock_all_vcpus(kvm);
if (ret)
return ret;
@@ -2115,10 +2112,6 @@ static int sev_check_source_vcpus(struct kvm *dst, struct kvm *src)
struct kvm_vcpu *src_vcpu;
unsigned long i;
- if (kvm_is_vcpu_creation_in_progress(src) ||
- kvm_is_vcpu_creation_in_progress(dst))
- return -EBUSY;
-
if (!sev_es_guest(src))
return 0;
@@ -2510,9 +2503,6 @@ static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
unsigned long i;
int ret;
- if (kvm_is_vcpu_creation_in_progress(kvm))
- return -EBUSY;
-
ret = kvm_lock_all_vcpus(kvm);
if (ret)
return ret;
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index b272c20586a7..58c255256e4c 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -2728,11 +2728,6 @@ static tdx_vm_state_guard_t tdx_acquire_vm_state_locks(struct kvm *kvm)
mutex_lock(&kvm->lock);
- if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus)) {
- r = -EBUSY;
- goto out_err;
- }
-
r = kvm_lock_all_vcpus(kvm);
if (r)
goto out_err;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 65eb26a0520d..78cc090435be 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1363,6 +1363,9 @@ int kvm_trylock_all_vcpus(struct kvm *kvm)
lockdep_assert_held(&kvm->lock);
+ if (kvm_is_vcpu_creation_in_progress(kvm))
+ return -EBUSY;
+
kvm_for_each_vcpu(i, vcpu, kvm)
if (!mutex_trylock_nest_lock(&vcpu->mutex, &kvm->lock))
goto out_unlock;
@@ -1386,6 +1389,9 @@ int kvm_lock_all_vcpus(struct kvm *kvm)
lockdep_assert_held(&kvm->lock);
+ if (kvm_is_vcpu_creation_in_progress(kvm))
+ return -EBUSY;
+
kvm_for_each_vcpu(i, vcpu, kvm) {
r = mutex_lock_killable_nest_lock(&vcpu->mutex, &kvm->lock);
if (r)
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 2/7] KVM: arm64: vgic: Rely on vCPU creation check in "trylock all vCPUs"
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 1/7] KVM: Reject attempts to lock all vCPUs if vCPU creation is in-progress Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 3/7] KVM: RISC-V: Use kvm_is_vcpu_creation_in_progress() instead of open-coded equivalent Sean Christopherson
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
Now that KVM's APIs for locking all vCPUs return -EBUSY if vCPU creation is
in-progress, drop the manual check for the same from vGIC creation, and
update the comments accordingly.
Note, while KVM arm64 guards many vGIC operations with its arch-specific
config_lock, holding kvm->lock is sufficient to guarantee a stable result
for "is vCPU creation in-progress". So, no functional change intended.
Note #2, the open coded check in vgic_init() is racy when called without
kvm->lock held, e.g. via vgic_lazy_init(). I.e. that check needs to stay
open coded to avoid triggering a lockdep assert. Whether or not the race
is "fine" is a problem for a different day.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/arm64/kvm/vgic/vgic-init.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 4012df6002ea..a58575df36e9 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -97,6 +97,9 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
/*
* - Acquiring the vCPU mutex for every *online* vCPU to prevent
* concurrent vCPU ioctls for vCPUs already visible to userspace.
+ * This also ensures KVM isn't in the middle of creating a vCPU,
+ * i.e. that there are no vCPUs that have been created but aren't
+ * yet fully online.
*/
ret = -EBUSY;
if (kvm_trylock_all_vcpus(kvm))
@@ -105,18 +108,11 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
/*
* - Taking the config_lock which protects VGIC data structures such
* as the per-vCPU arrays of private IRQs (SGIs, PPIs).
- */
- mutex_lock(&kvm->arch.config_lock);
-
- /*
- * - Bailing on the entire thing if a vCPU is in the middle of creation,
- * dropped the kvm->lock, but hasn't reached kvm_arch_vcpu_create().
*
* The whole combination of this guarantees that no vCPU can get into
* KVM with a VGIC configuration inconsistent with the VM's VGIC.
*/
- if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
- goto out_unlock;
+ mutex_lock(&kvm->arch.config_lock);
if (irqchip_in_kernel(kvm)) {
ret = -EEXIST;
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 3/7] KVM: RISC-V: Use kvm_is_vcpu_creation_in_progress() instead of open-coded equivalent
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 1/7] KVM: Reject attempts to lock all vCPUs if vCPU creation is in-progress Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 2/7] KVM: arm64: vgic: Rely on vCPU creation check in "trylock all vCPUs" Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 4/7] KVM: Protect all of kvm_vm_ioctl_create_vcpu() with kvm->lock Sean Christopherson
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
Use kvm_is_vcpu_creation_in_progress() instead of an open-coded equivalent
during AIA initialization. Unlike similar vGIC code in arm64, the relevant
RISC-V code runs under kvm->lock, i.e. can use the standard API without
hitting lockdep false positive.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/riscv/kvm/aia_device.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c
index efc7c0bcfba9..97833a04268a 100644
--- a/arch/riscv/kvm/aia_device.c
+++ b/arch/riscv/kvm/aia_device.c
@@ -237,7 +237,7 @@ static int aia_init(struct kvm *kvm)
return -EBUSY;
/* We might be in the middle of creating a VCPU? */
- if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
+ if (kvm_is_vcpu_creation_in_progress(kvm))
return -EBUSY;
/* Number of sources should be less than or equals number of IDs */
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 4/7] KVM: Protect all of kvm_vm_ioctl_create_vcpu() with kvm->lock
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
` (2 preceding siblings ...)
2026-09-21 17:44 ` [PATCH v2 3/7] KVM: RISC-V: Use kvm_is_vcpu_creation_in_progress() instead of open-coded equivalent Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 5/7] KVM: Move check for existing vCPU ID to the top of vCPU creation Sean Christopherson
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
When creating a vCPU, don't drop kvm->lock to when doing the bulk of actual
vCPU creation, as allowing multiple vCPUs to be created in parallel adds
significant complexity in KVM (as evidenced by the many related bugs), and
all known VMMs fully serialize vCPU creation. Remove all manually locking
of kvm->lock from kvm_arch_vcpu_{post,}create() for obvious reasons.
For many years, "everyone" has assumed that dropping kvm->lock was done for
performance reasons optimization, e.g. to allow userspace to create all
vCPUs concurrently for latency purposes. But as above, no known VMM does
that. Looking at the history of this code, before commit 11ec28047118
("KVM: Convert vm lock to a mutex"), kvm->lock was a spinlock. I.e. KVM
*had* to drop kvm->lock when doing the bulk of vCPU creation, otherwise KVM
couldn't do normal memory allocations. When kvm->lock got turned into a
mutex for unrelated reasons, no one took advantage updated of the change to
simplify vCPU creation. And 19 years later, everyone just assumed that KVM
continued to deal with the complexity for performance reasons.
Furthermore, naively parallelizing vCPU creation in userspace is likely a
net negative due to the overheads of task creation. Unless a VMM carefully
avoids the extra overhead related to parallelization, e.g. spawns each
vCPU's thread before creating the vCPU, creating vCPUs concurrently is a
net *negative* up until about ~64 vCPUs, after which the times are a wash.
The absolute speed of light _is_ faster if KVM doesn't hold kvm-lock, but
at vCPU counts of ~16 or less, it's probably in the noise when considering
total VM creation time, as the added latency is less than 1ms up until 16
or so vCPUs.
On top of all that, KVM has had a *lot* of fatal bugs (most often found by
syzkaller) related to vCPUs being created while trying to do per-VM
operations (basically, see every flow that locks all vCPUs). I.e. the
parallel vCPU creation "support" is actively harmful as the only "use case"
is for misbehaving userspace to exploit KVM bugs.
Serializing vCPU creation will allow reverting commit 97d65b544f48 ("KVM:
Check for duplicate vcpu_id as early as possible"), which had "minor" math
error: the worst case scenario isn't "256 bytes per VM", it's "256 unsigned
longs per VM", i.e. 2048 bytes per VM, which doubles the size of each VM
and pushes several architectures into order-1 allocations.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/powerpc/kvm/book3s_hv.c | 2 --
arch/s390/kvm/s390/s390.c | 5 +----
virt/kvm/kvm_main.c | 22 +++++-----------------
3 files changed, 6 insertions(+), 23 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 0409ac9e7b31..30f7095a156e 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -3058,7 +3058,6 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu)
init_waitqueue_head(&vcpu->arch.cpu_run);
- mutex_lock(&kvm->lock);
vcore = NULL;
err = -EINVAL;
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
@@ -3091,7 +3090,6 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu)
mutex_unlock(&kvm->arch.mmu_setup_lock);
}
}
- mutex_unlock(&kvm->lock);
if (!vcore)
return err;
diff --git a/arch/s390/kvm/s390/s390.c b/arch/s390/kvm/s390/s390.c
index eca4a4359ab2..cc628afbb850 100644
--- a/arch/s390/kvm/s390/s390.c
+++ b/arch/s390/kvm/s390/s390.c
@@ -3579,12 +3579,11 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
{
- mutex_lock(&vcpu->kvm->lock);
preempt_disable();
vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
vcpu->arch.sie_block->epdx = vcpu->kvm->arch.epdx;
preempt_enable();
- mutex_unlock(&vcpu->kvm->lock);
+
if (!kvm_is_ucontrol(vcpu->kvm)) {
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
sca_add_vcpu(vcpu);
@@ -3757,13 +3756,11 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu)
kvm_s390_vcpu_pci_setup(vcpu);
- mutex_lock(&vcpu->kvm->lock);
if (kvm_s390_pv_is_protected(vcpu->kvm)) {
rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc);
if (rc)
kvm_s390_vcpu_unsetup_cmma(vcpu);
}
- mutex_unlock(&vcpu->kvm->lock);
return rc;
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 78cc090435be..c17cc8dd371b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4165,6 +4165,8 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
struct kvm_vcpu *vcpu;
struct page *page;
+ guard(mutex)(&kvm->lock);
+
/*
* KVM tracks vCPU IDs as 'int', be kind to userspace and reject
* too-large values instead of silently truncating.
@@ -4177,26 +4179,18 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
if (id >= KVM_MAX_VCPU_IDS)
return -EINVAL;
- mutex_lock(&kvm->lock);
- if (kvm->created_vcpus >= kvm->max_vcpus) {
- mutex_unlock(&kvm->lock);
+ if (kvm->created_vcpus >= kvm->max_vcpus)
return -EINVAL;
- }
- if (test_bit(id, kvm->vcpu_ids)) {
- mutex_unlock(&kvm->lock);
+ if (test_bit(id, kvm->vcpu_ids))
return -EEXIST;
- }
r = kvm_arch_vcpu_precreate(kvm, id);
- if (r) {
- mutex_unlock(&kvm->lock);
+ if (r)
return r;
- }
kvm->created_vcpus++;
__set_bit(id, kvm->vcpu_ids);
- mutex_unlock(&kvm->lock);
vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT);
if (!vcpu) {
@@ -4227,8 +4221,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
goto arch_vcpu_destroy;
}
- mutex_lock(&kvm->lock);
-
if (WARN_ON_ONCE(kvm_get_vcpu_by_id(kvm, id))) {
r = -EEXIST;
goto unlock_vcpu_destroy;
@@ -4267,7 +4259,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
atomic_inc(&kvm->online_vcpus);
mutex_unlock(&vcpu->mutex);
- mutex_unlock(&kvm->lock);
kvm_arch_vcpu_postcreate(vcpu);
kvm_create_vcpu_debugfs(vcpu);
return r;
@@ -4278,7 +4269,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
xa_erase(&kvm->vcpu_array, vcpu->vcpu_idx);
unlock_vcpu_destroy:
vcpu->vcpu_idx = -1;
- mutex_unlock(&kvm->lock);
kvm_dirty_ring_free(&vcpu->dirty_ring);
arch_vcpu_destroy:
kvm_arch_vcpu_destroy(vcpu);
@@ -4287,10 +4277,8 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
vcpu_free:
kmem_cache_free(kvm_vcpu_cache, vcpu);
vcpu_decrement:
- mutex_lock(&kvm->lock);
kvm->created_vcpus--;
__clear_bit(id, kvm->vcpu_ids);
- mutex_unlock(&kvm->lock);
return r;
}
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 5/7] KVM: Move check for existing vCPU ID to the top of vCPU creation
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
` (3 preceding siblings ...)
2026-09-21 17:44 ` [PATCH v2 4/7] KVM: Protect all of kvm_vm_ioctl_create_vcpu() with kvm->lock Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 6/7] Revert "KVM: Check for duplicate vcpu_id as early as possible" Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 7/7] KVM: WARN if vCPU creation is in-progress when locking all vCPUs Sean Christopherson
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
Now that kvm->lock is held for the entirety of vCPU creation, check for a
conflicting vCPU ID at the begnning of vCPU creation, before the arch
precreate() hook is invoked. This will allow reverting commit 97d65b544f48
("KVM: Check for duplicate vcpu_id as early as possible"). For now, keep
the redundant vcpu_ids tracking as a sanity check.
No functional change intended (absent KVM bugs, checking vcpu_ids and
walking kvm_get_vcpu_by_id() should yield the same result).
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/kvm_main.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index c17cc8dd371b..d5524ac8c5cf 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4182,7 +4182,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
if (kvm->created_vcpus >= kvm->max_vcpus)
return -EINVAL;
- if (test_bit(id, kvm->vcpu_ids))
+ if (kvm_get_vcpu_by_id(kvm, id))
+ return -EEXIST;
+
+ if (WARN_ON_ONCE(test_bit(id, kvm->vcpu_ids)))
return -EEXIST;
r = kvm_arch_vcpu_precreate(kvm, id);
@@ -4221,11 +4224,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
goto arch_vcpu_destroy;
}
- if (WARN_ON_ONCE(kvm_get_vcpu_by_id(kvm, id))) {
- r = -EEXIST;
- goto unlock_vcpu_destroy;
- }
-
/*
* Set the vCPU's index *before* the vCPU is reachable by other tasks.
* Unwind the index back to -1 on failure so that KVM can use the index
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 6/7] Revert "KVM: Check for duplicate vcpu_id as early as possible"
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
` (4 preceding siblings ...)
2026-09-21 17:44 ` [PATCH v2 5/7] KVM: Move check for existing vCPU ID to the top of vCPU creation Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
2026-09-21 17:44 ` [PATCH v2 7/7] KVM: WARN if vCPU creation is in-progress when locking all vCPUs Sean Christopherson
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
Now that KVM uses kvm_get_vcpu_by_id() to check for an existing vCPU ID
before doing any meaningful work, which was made possible by holding
kvm->lock for the entirety of vCPU creation, revert the now-redundant
"early" vCPU ID tracking. The claims about the impact of kvm->vcpu_ids on
the memory footprint were a wee bit wrong: the worst case scenario isn't
256 bytes per VM, it's 256 "unsigned longs" per VM, i.e. 2048 bytes per VM.
Increasing the size of "struct kvm" by 2048 nearly doubled the total size
on many architectures, and tripped x86's KVM_SANITY_CHECK_VM_STRUCT_SIZE,
which was added to detect this *exact* scenario, where a single change
significantly increased the size of "struct kvm". I.e. attempting to build
KVM with CONFIG_DEBUG_KERNEL=n fails on x86 (the build failures got missed
because all build bots apparently test only CONFIG_DEBUG_KERNEL=y kernels,
and maintainers' test flows were similarly lacking).
This reverts commit 97d65b544f48b2ee49f6aea32145e3e7969955dc.
Fixes: 97d65b544f48 ("KVM: Check for duplicate vcpu_id as early as possible")
Reported-by: Jean-Christophe Guillain <jean-christophe@guillain.net>
Closes: https://lore.kernel.org/all/56a4bc35ee605588b7cc36c8e45c12b5f3b506cb.camel@guillain.net
Reported-by: Paweł S <spawel523@gmail.com>
Closes: https://lore.kernel.org/all/CABD%3DWFOS4j4hDv%2BpW-eEM9HAM2q2GY_iYdAG%2BqvYcUEinUrcQQ@mail.gmail.com
Tested-by: Jean-Christophe Guillain <jean-christophe@guillain.net>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
include/linux/kvm_host.h | 1 -
virt/kvm/kvm_main.c | 5 -----
2 files changed, 6 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 03bfc92864b6..6aab167bf482 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -791,7 +791,6 @@ struct kvm {
/* The current active memslot set for each address space */
struct kvm_memslots __rcu *memslots[KVM_MAX_NR_ADDRESS_SPACES];
struct xarray vcpu_array;
- DECLARE_BITMAP(vcpu_ids, KVM_MAX_VCPU_IDS);
/*
* Protected by slots_lock, but can be read outside if an
* incorrect answer is acceptable.
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index d5524ac8c5cf..985af39b980a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4185,15 +4185,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
if (kvm_get_vcpu_by_id(kvm, id))
return -EEXIST;
- if (WARN_ON_ONCE(test_bit(id, kvm->vcpu_ids)))
- return -EEXIST;
-
r = kvm_arch_vcpu_precreate(kvm, id);
if (r)
return r;
kvm->created_vcpus++;
- __set_bit(id, kvm->vcpu_ids);
vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT);
if (!vcpu) {
@@ -4276,7 +4272,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
kmem_cache_free(kvm_vcpu_cache, vcpu);
vcpu_decrement:
kvm->created_vcpus--;
- __clear_bit(id, kvm->vcpu_ids);
return r;
}
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 7/7] KVM: WARN if vCPU creation is in-progress when locking all vCPUs
2026-09-21 17:44 [PATCH v2 0/7] KVM: Serialize vCPU creation and revert vcpu_ids tracking Sean Christopherson
` (5 preceding siblings ...)
2026-09-21 17:44 ` [PATCH v2 6/7] Revert "KVM: Check for duplicate vcpu_id as early as possible" Sean Christopherson
@ 2026-09-21 17:44 ` Sean Christopherson
6 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-21 17:44 UTC (permalink / raw)
To: Madhavan Srinivasan, Anup Patel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Sean Christopherson, Paolo Bonzini, Kiryl Shutsemau,
Rick Edgecombe
Cc: Nicholas Piggin, Atish Patra, Alexandre Ghiti, Dave Hansen,
linuxppc-dev, kvm, kvm-riscv, linux-riscv, x86, linux-coco,
linux-kernel, Jean-Christophe Guillain, Paweł S
Now that KVM holds kvm->lock for the entirety of vCPU creation, from when
created_vcpus is incremented until the new vCPU is fully onlined, WARN if
the impossible happens and KVM somehow sees a discrepancy between the
number of vCPUs "created" and "onlined".
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/kvm_main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 985af39b980a..e66d9761ee49 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1363,7 +1363,7 @@ int kvm_trylock_all_vcpus(struct kvm *kvm)
lockdep_assert_held(&kvm->lock);
- if (kvm_is_vcpu_creation_in_progress(kvm))
+ if (WARN_ON_ONCE(kvm_is_vcpu_creation_in_progress(kvm)))
return -EBUSY;
kvm_for_each_vcpu(i, vcpu, kvm)
@@ -1389,7 +1389,7 @@ int kvm_lock_all_vcpus(struct kvm *kvm)
lockdep_assert_held(&kvm->lock);
- if (kvm_is_vcpu_creation_in_progress(kvm))
+ if (WARN_ON_ONCE(kvm_is_vcpu_creation_in_progress(kvm)))
return -EBUSY;
kvm_for_each_vcpu(i, vcpu, kvm) {
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread