[PATCH 13/24] KVM: Introduce kvm_check_gen()/kvm_memslots_check_gen()
From: Paolo Bonzini
Date: Thu Jul 16 2026 - 14:17:30 EST
In many cases, retrieving kvm_memslots is followed by a check on
the generation of the slots. Introduce a helper function that
either does the check alone, or compounds it with returning the
struct kvm_memslots* to the caller.
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
arch/x86/kvm/x86.c | 10 ++--------
include/linux/kvm_host.h | 12 ++++++++++++
virt/kvm/kvm_main.c | 8 ++++----
virt/kvm/pfncache.c | 10 ++++------
4 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e2240f817c22..58f544df47e1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2032,7 +2032,6 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
{
struct gfn_to_hva_cache *ghc = &vcpu->arch.st.cache;
struct kvm_steal_time __user *st;
- struct kvm_memslots *slots;
gpa_t gpa = vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS;
u64 steal;
u32 version;
@@ -2048,9 +2047,7 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
if (WARN_ON_ONCE(current->mm != vcpu->kvm->mm))
return;
- slots = kvm_memslots(vcpu->kvm);
-
- if (unlikely(slots->generation != ghc->generation ||
+ if (unlikely(!kvm_check_gen(vcpu->kvm, ghc->generation) ||
gpa != ghc->gpa ||
kvm_is_error_hva(ghc->hva) || !ghc->memslot)) {
/* We rely on the fact that it fits in a single page. */
@@ -2601,7 +2598,6 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
{
struct gfn_to_hva_cache *ghc = &vcpu->arch.st.cache;
struct kvm_steal_time __user *st;
- struct kvm_memslots *slots;
static const u8 preempted = KVM_VCPU_PREEMPTED;
gpa_t gpa = vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS;
@@ -2628,9 +2624,7 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
if (unlikely(current->mm != vcpu->kvm->mm))
return;
- slots = kvm_memslots(vcpu->kvm);
-
- if (unlikely(slots->generation != ghc->generation ||
+ if (unlikely(!kvm_check_gen(vcpu->kvm, ghc->generation) ||
gpa != ghc->gpa ||
kvm_is_error_hva(ghc->hva) || !ghc->memslot))
return;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 341f2e97f3cb..122af87d6f9a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -2559,6 +2559,18 @@ static inline bool kvm_mem_attributes_may_exec(u64 attrs)
return !(attrs & KVM_MEMORY_ATTRIBUTE_NX);
}
+static inline bool kvm_memslots_check_gen(struct kvm *kvm, u64 slots_generation, struct kvm_memslots **p_slots)
+{
+ struct kvm_memslots *slots = *p_slots = kvm_memslots(kvm);
+ return slots->generation == slots_generation;
+}
+
+static inline bool kvm_check_gen(struct kvm *kvm, u64 slots_generation)
+{
+ struct kvm_memslots *slots;
+ return kvm_memslots_check_gen(kvm, slots_generation, &slots);
+}
+
#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
#define KVM_MEMORY_ATTRIBUTE_PROT \
(KVM_MEMORY_ATTRIBUTE_NR | KVM_MEMORY_ATTRIBUTE_NW | KVM_MEMORY_ATTRIBUTE_NX)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 20113069562e..1afaec56ecb3 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3502,14 +3502,14 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
void *data, unsigned int offset,
unsigned long len)
{
- struct kvm_memslots *slots = kvm_memslots(kvm);
+ struct kvm_memslots *slots;
int r;
gpa_t gpa = ghc->gpa + offset;
if (WARN_ON_ONCE(len + offset > ghc->len))
return -EINVAL;
- if (slots->generation != ghc->generation) {
+ if (unlikely(!kvm_memslots_check_gen(kvm, ghc->generation, &slots))) {
if (__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len))
return -EFAULT;
}
@@ -3540,14 +3540,14 @@ int kvm_read_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
void *data, unsigned int offset,
unsigned long len)
{
- struct kvm_memslots *slots = kvm_memslots(kvm);
+ struct kvm_memslots *slots;
int r;
gpa_t gpa = ghc->gpa + offset;
if (WARN_ON_ONCE(len + offset > ghc->len))
return -EINVAL;
- if (slots->generation != ghc->generation) {
+ if (unlikely(!kvm_memslots_check_gen(kvm, ghc->generation, &slots))) {
if (__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len))
return -EFAULT;
}
diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c
index 728d2c1b488a..e09703d249bb 100644
--- a/virt/kvm/pfncache.c
+++ b/virt/kvm/pfncache.c
@@ -72,8 +72,6 @@ static bool kvm_gpc_is_valid_len(gpa_t gpa, unsigned long uhva,
bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len)
{
- struct kvm_memslots *slots = kvm_memslots(gpc->kvm);
-
if (!gpc->active)
return false;
@@ -81,7 +79,7 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len)
* If the page was cached from a memslot, make sure the memslots have
* not been re-configured.
*/
- if (!kvm_is_error_gpa(gpc->gpa) && gpc->generation != slots->generation)
+ if (!kvm_is_error_gpa(gpc->gpa) && !kvm_check_gen(gpc->kvm, gpc->generation))
return false;
if (kvm_is_error_hva(gpc->uhva))
@@ -290,12 +288,12 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned l
if (gpc->uhva != old_uhva)
hva_change = true;
} else {
- struct kvm_memslots *slots = kvm_memslots(gpc->kvm);
+ struct kvm_memslots *slots;
page_offset = offset_in_page(gpa);
- if (gpc->gpa != gpa || gpc->generation != slots->generation ||
- kvm_is_error_hva(gpc->uhva)) {
+ if (!kvm_memslots_check_gen(gpc->kvm, gpc->generation, &slots) ||
+ gpc->gpa != gpa || kvm_is_error_hva(gpc->uhva)) {
gfn_t gfn = gpa_to_gfn(gpa);
gpc->gpa = gpa;
--
2.52.0