From: Sean Christopherson <seanjc@google.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Naveen N Rao <naveen@kernel.org>, Xiao Wu <xiaowu.417@qq.com>
Subject: [PATCH v2 2/3] KVM: SVM: Do all per-VM AVIC initialization during vCPU precreation phase
Date: Tue, 30 Jun 2026 14:01:55 -0700 [thread overview]
Message-ID: <20260630210156.457151-3-seanjc@google.com> (raw)
In-Reply-To: <20260630210156.457151-1-seanjc@google.com>
Move all per-VM AVIC initialization from VM creation to vCPU pre-creation,
i.e. defer allocating the logical ID table and adding the VM to the GA Log
list until vCPUs are created. This will allow removing the VM from the GA
Log list before vCPUs are destroyed without needing yet another kvm_x86_ops
hook (.vm_pre_destroy() is very intentionally called if and only if VM
creation fully succeeds).
As a bonus, this re-unites physical and logic table allocation, and avoids
allocating a logical table in the unlikely scenario that userspace creates
a VM without an in-kernel local APIC.
Another bonus to hooking .vcpu_precreate() is that there is no need to
unwind on failure, as the VM has already been created, i.e. KVM will run
through all phases of VM destruction. In fact, unwinding is undesirable,
as KVM tries to keep VM-wide behavior idempotent/sticky across creaton of
multiple vCPUs.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/svm/avic.c | 94 +++++++++++++++++++++++++----------------
arch/x86/kvm/svm/svm.c | 6 ---
2 files changed, 57 insertions(+), 43 deletions(-)
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 4a0a2dbd1687..d71a2fed1a08 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -308,47 +308,32 @@ static int avic_alloc_physical_id_table(struct kvm *kvm)
return 0;
}
-int avic_vcpu_precreate(struct kvm *kvm)
+static int avic_alloc_logical_id_table(struct kvm *kvm)
{
- if (!irqchip_in_kernel(kvm) || WARN_ON_ONCE(!enable_apicv))
- return 0;
-
- return avic_alloc_physical_id_table(kvm);
-}
-
-void avic_vm_destroy(struct kvm *kvm)
-{
- unsigned long flags;
- struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
-
- if (!enable_apicv)
- return;
-
- free_page((unsigned long)kvm_svm->avic_logical_id_table);
- free_pages((unsigned long)kvm_svm->avic_physical_id_table,
- avic_get_physical_id_table_order(kvm));
-
- spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
- hash_del(&kvm_svm->hnode);
- spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
-}
-
-int avic_vm_init(struct kvm *kvm)
-{
- unsigned long flags;
- int err = -ENOMEM;
struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
- struct kvm_svm *k2;
- u32 vm_id;
- if (!enable_apicv)
+ if (kvm_svm->avic_logical_id_table)
return 0;
kvm_svm->avic_logical_id_table = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
if (!kvm_svm->avic_logical_id_table)
- goto free_avic;
+ return -ENOMEM;
- spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+ return 0;
+}
+
+static void avic_add_vm_to_ga_log_list(struct kvm *kvm)
+{
+ struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+ struct kvm_svm *k2;
+ u32 vm_id;
+
+ lockdep_assert_held(&kvm->lock);
+
+ if (kvm_svm->avic_vm_id)
+ return;
+
+ guard(spinlock_irqsave)(&svm_vm_data_hash_lock);
again:
vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
if (vm_id == 0) { /* id is 1-based, zero is not okay */
@@ -364,13 +349,48 @@ int avic_vm_init(struct kvm *kvm)
}
kvm_svm->avic_vm_id = vm_id;
hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id);
- spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+}
+int avic_vcpu_precreate(struct kvm *kvm)
+{
+ int r;
+
+ if (!irqchip_in_kernel(kvm) || WARN_ON_ONCE(!enable_apicv))
+ return 0;
+
+ /*
+ * Don't unwind on failure, all actions must be idempotent with respect
+ * to creating multiple vCPUs, i.e. must persist until the VM is destroyed.
+ */
+ r = avic_alloc_physical_id_table(kvm);
+ if (r)
+ return r;
+
+ r = avic_alloc_logical_id_table(kvm);
+ if (r)
+ return r;
+
+ avic_add_vm_to_ga_log_list(kvm);
return 0;
+}
-free_avic:
- avic_vm_destroy(kvm);
- return err;
+void avic_vm_destroy(struct kvm *kvm)
+{
+ unsigned long flags;
+ struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+
+ if (!enable_apicv)
+ return;
+
+ free_page((unsigned long)kvm_svm->avic_logical_id_table);
+ free_pages((unsigned long)kvm_svm->avic_physical_id_table,
+ avic_get_physical_id_table_order(kvm));
+
+ if (kvm_svm->avic_vm_id) {
+ spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+ hash_del(&kvm_svm->hnode);
+ spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+ }
}
static phys_addr_t avic_get_backing_page_address(struct vcpu_svm *svm)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index a7d141f7e76c..7f3a815d737f 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -5297,12 +5297,6 @@ static int svm_vm_init(struct kvm *kvm)
if (!pause_filter_count || !pause_filter_thresh)
kvm_disable_exits(kvm, KVM_X86_DISABLE_EXITS_PAUSE);
- if (enable_apicv) {
- int ret = avic_vm_init(kvm);
- if (ret)
- return ret;
- }
-
svm_srso_vm_init();
return 0;
}
--
2.55.0.rc0.799.gd6f94ed593-goog
next prev parent reply other threads:[~2026-06-30 21:02 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-30 21:01 [PATCH v2 0/3] KVM: SVM: Fix a (very) unlikely UAF for GA Log IRQs Sean Christopherson
2026-06-30 21:01 ` [PATCH v2 1/3] KVM: SVM: Make kvm_x86_ops.vcpu_precreate() hook fully AVIC specific Sean Christopherson
2026-06-30 21:01 ` Sean Christopherson [this message]
2026-06-30 21:18 ` [PATCH v2 2/3] KVM: SVM: Do all per-VM AVIC initialization during vCPU precreation phase sashiko-bot
2026-06-30 21:20 ` Sean Christopherson
2026-06-30 21:01 ` [PATCH v2 3/3] KVM: SVM: Remove VM from the GA Log notifier list before VM destruction Sean Christopherson
2026-06-30 21:15 ` sashiko-bot
2026-06-30 21:27 ` Sean Christopherson
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=20260630210156.457151-3-seanjc@google.com \
--to=seanjc@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=naveen@kernel.org \
--cc=pbonzini@redhat.com \
--cc=xiaowu.417@qq.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox