From: Sairaj Kodilkar <sarunkod@amd.com>
To: "H. Peter Anvin" <hpa@zytor.com>, Borislav Petkov <bp@alien8.de>,
"Dave Hansen" <dave.hansen@linux.intel.com>,
Ingo Molnar <mingo@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>,
Thomas Gleixner <tglx@kernel.org>, <kvm@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <x86@kernel.org>
Cc: <vasant.hegde@amd.com>, <suravee.suthikulpanit@amd.com>,
Sairaj Kodilkar <sarunkod@amd.com>
Subject: [PATCH] x86/kvm: Use RCU for svm_vm_data_hash
Date: Wed, 11 Nov 2026 15:32:46 +0530 [thread overview]
Message-ID: <20261111100246.4425-1-sarunkod@amd.com> (raw)
GALOG notifier iterates svm_vm_data_hash to find the `struct kvm_vcpu`
for the given vm id and vcpu id. Holding spinlock is not ideal here since
it allows only a single reader to iterate over the hash. This degrades
performance when interrupt rate is high and large number of readers are
waiting for the spinlock. Hence replace spinlock with the RCU.
Signed-off-by: Sairaj Kodilkar <sarunkod@amd.com>
---
Tested on a 2-socket AMD EPYC 9965 host against the same kernel without
this change:
- 12 VMs, each with 32 vCPUs and one passed-through NVMe device
- vCPUs pinned NUMA-local, at 1:1, 1:2, 1:3 and 1:4 pCPU:vCPU
- fio in each guest: randread, bs=4k, iodepth=32, numjobs=32,
ioengine=libaio, direct=1, 60s
Time spent in the hash lookup in avic_ga_log_notifier(), measured with
a temporary tracepoint around the lookup, averaged over 12 VMs and
3 runs:
| mean | p99 |
|------------------------|----------------------|
pCPU:vCPU | spinlock | RCU | spinlock | RCU |
-------------|-----------|------------|-----------|----------|
1:1 | 409.8 ns | 132.6 ns | 960 ns | 750 ns |
1:2 | 977.3 ns | 21.9 ns | 3530 ns | 30 ns |
1:3 | 747.5 ns | 23.7 ns | 2150 ns | 40 ns |
1:4 | 614.8 ns | 23.5 ns | 1610 ns | 40 ns |
Total IOPS was unchanged at every ratio.
---
arch/x86/kvm/svm/avic.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 96ca39c0045f..9e2c11d60798 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -250,7 +250,6 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm)
*/
static int avic_ga_log_notifier(u32 ga_tag)
{
- unsigned long flags;
struct kvm_svm *kvm_svm;
struct kvm_vcpu *vcpu = NULL;
u32 vm_id = AVIC_GATAG_TO_VMID(ga_tag);
@@ -259,14 +258,14 @@ static int avic_ga_log_notifier(u32 ga_tag)
pr_debug("SVM: %s: vm_id=%#x, vcpu_idx=%#x\n", __func__, vm_id, vcpu_idx);
trace_kvm_avic_ga_log(vm_id, vcpu_idx);
- spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
- hash_for_each_possible(svm_vm_data_hash, kvm_svm, hnode, vm_id) {
+ rcu_read_lock();
+ hash_for_each_possible_rcu(svm_vm_data_hash, kvm_svm, hnode, vm_id) {
if (kvm_svm->avic_vm_id != vm_id)
continue;
vcpu = kvm_get_vcpu(&kvm_svm->kvm, vcpu_idx);
break;
}
- spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+ rcu_read_unlock();
/* Note:
* At this point, the IOMMU should have already set the pending
@@ -319,13 +318,14 @@ 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;
+ unsigned long flags;
lockdep_assert_held(&kvm->lock);
if (kvm_svm->avic_vm_id)
return;
- guard(spinlock_irqsave)(&svm_vm_data_hash_lock);
+ spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
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 */
@@ -340,7 +340,8 @@ static void avic_add_vm_to_ga_log_list(struct kvm *kvm)
}
}
kvm_svm->avic_vm_id = vm_id;
- hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id);
+ hash_add_rcu(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)
@@ -369,13 +370,14 @@ int avic_vcpu_precreate(struct kvm *kvm)
void avic_vm_pre_destroy(struct kvm *kvm)
{
struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+ unsigned long flags;
if (WARN_ON_ONCE(!enable_apicv) || !kvm_svm->avic_vm_id)
return;
- guard(spinlock_irqsave)(&svm_vm_data_hash_lock);
-
- hash_del(&kvm_svm->hnode);
+ spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+ hash_del_rcu(&kvm_svm->hnode);
+ spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
}
void avic_vm_destroy(struct kvm *kvm)
--
2.34.1
reply other threads:[~2026-11-11 10:03 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261111100246.4425-1-sarunkod@amd.com \
--to=sarunkod@amd.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=suravee.suthikulpanit@amd.com \
--cc=tglx@kernel.org \
--cc=vasant.hegde@amd.com \
--cc=x86@kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®