]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: x86/mmu: Check all address spaces before skipping unsync
authorJinu Kim <kimjw04271234@gmail.com>
Tue, 21 Jul 2026 10:35:12 +0000 (19:35 +0900)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 28 Jul 2026 16:07:18 +0000 (18:07 +0200)
mmu_try_to_unsync_pages() skips the shadow-page lookup when the
supplied memslot allows a hugepage, because a shadow page would disallow
hugepages.  But hugepage metadata is per-address-space while shadow pages
are shared across all address spaces.  With SMM, the other address space
can therefore have a shadow page even when the supplied memslot allows a
hugepage.

Check the corresponding memslot in the other address space before
taking the fast path.  Skip the shadow-page lookup only when all address
spaces allow a hugepage.

Fixes: b3ae3ceb5569 ("KVM: x86/mmu: KVM: x86/mmu: Skip unsync when large pages are allowed")
Assisted-by: Codex:GPT-5
Signed-off-by: Jinu Kim <kimjw04271234@gmail.com>
[invert direction of the conditional. - Paolo]
Message-ID: <20260721103512.2136240-3-kimjw04271234@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/mmu/mmu.c

index 22cf222d30339e31c185e273ca8d7d5361ba18c6..66e69d2a41b3c5aef74864c69114c4240b090a18 100644 (file)
@@ -722,6 +722,26 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
        return &slot->arch.lpage_info[level - 2][idx];
 }
 
+static bool kvm_gfn_is_lpage_allowed(struct kvm *kvm,
+                                    const struct kvm_memory_slot *slot,
+                                    gfn_t gfn, int level)
+{
+       const struct kvm_memory_slot *other_slot;
+
+       BUILD_BUG_ON(KVM_MAX_NR_ADDRESS_SPACES > 2);
+
+       if (lpage_info_slot(gfn, slot, level)->disallow_lpage)
+               return false;
+
+       if (kvm_arch_nr_memslot_as_ids(kvm) > 1) {
+               other_slot = __gfn_to_memslot(__kvm_memslots(kvm, slot->as_id ^ 1), gfn);
+               if (other_slot && lpage_info_slot(gfn, other_slot, level)->disallow_lpage)
+                       return false;
+       }
+
+       return true;
+}
+
 /*
  * The most significant bit in disallow_lpage tracks whether or not memory
  * attributes are mixed, i.e. not identical for all gfns at the current level.
@@ -2968,7 +2988,7 @@ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot,
         * write-protected (see above), thus if the gfn can be mapped with a
         * hugepage and isn't write-tracked, it can't have a shadow page.
         */
-       if (!lpage_info_slot(gfn, slot, PG_LEVEL_2M)->disallow_lpage)
+       if (kvm_gfn_is_lpage_allowed(kvm, slot, gfn, PG_LEVEL_2M))
                return 0;
 
        /*