From: sashiko-bot@kernel.org
To: "Paolo Bonzini" <pbonzini@redhat.com>, kvm@vger.kernel.org
Subject: Re: [PATCH 24/45] KVM: Introduce a generation number for memory attributes
Date: Mon, 02 Nov 2026 18:20:29 +0000 [thread overview]
Message-ID: <sashiko-outbox-193927@kernel.org> (raw)
In-Reply-To: <20261102174512.8903-8-pbonzini@redhat.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] KVM: RCU stall in kvm_range_has_any_vm_memory_attributes() via xas_next()
- [Medium] KVM: unconditional generation bump and error-path sync in kvm_set_vm_mem_attributes()
- [Low] KVM: loongarch: missing closing parenthesis in kvm_check_gen() conditions
- [Low] KVM: stale attrs_generation on error in __kvm_gfn_to_hva_cache_init()
--
commit c500cbe0be12ea140c87b086c8905238fbefe1ea
Author: Nicolas Saenz Julienne <nsaenz@amazon.com>
KVM: Introduce a generation number for memory attributes
This commit introduces a generation number for VM memory attributes so that
KVM components using gfn_to_hva_cache and gfn_to_pfn_cache can detect memory
attribute updates and synchronize via KVM SRCU when attributes requiring
synchronization are modified.
Link: https://patch.msgid.link/20260918135030.171564-22-pbonzini@redhat.com
> diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
> index c3e71ef983bcb..6301e726a536f 100644
> --- a/arch/loongarch/kvm/vcpu.c
> +++ b/arch/loongarch/kvm/vcpu.c
> @@ -163,7 +163,8 @@ static void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
> return;
>
> gpa &= KVM_STEAL_PHYS_MASK;
> - if (unlikely(!kvm_check_gen(vcpu->kvm, ghc->generation) || gpa != ghc->gpa ||
> + if (unlikely(!kvm_check_gen(vcpu->kvm, ghc->slots_generation, ghc->attrs_generation) ||
> + gpa != ghc->gpa ||
> kvm_is_error_hva(ghc->hva) || !ghc->memslot) {
> if (kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, gpa, sizeof(*st))) {
> ghc->gpa = INVALID_GPA;
> @@ -1817,7 +1818,8 @@ static void kvm_vcpu_set_pv_preempted(struct kvm_vcpu *vcpu)
>
> gpa &= KVM_STEAL_PHYS_MASK;
> ghc = &vcpu->arch.st.cache;
> - if (unlikely(!kvm_check_gen(vcpu->kvm, ghc->generation) || gpa != ghc->gpa ||
> + if (unlikely(!kvm_check_gen(vcpu->kvm, ghc->slots_generation, ghc->attrs_generation) ||
> + gpa != ghc->gpa ||
> kvm_is_error_hva(ghc->hva) || !ghc->memslot) {
[Severity: Low]
As reported by Sashiko on v2 [1], does this fail to build on LoongArch due to
a missing closing parenthesis in both kvm_update_stolen_time() and
kvm_vcpu_set_pv_preempted()?
Both conditions open two parentheses at if (unlikely( before calling
!kvm_check_gen(vcpu->kvm, ghc->slots_generation, ghc->attrs_generation), but
only close one parenthesis after !ghc->memslot before the opening brace.
[ ... ]
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index da12f4d43c911..6aa6a0a55b070 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
[ ... ]
> @@ -2558,6 +2559,53 @@ bool kvm_range_has_vm_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
> return true;
> }
>
> +/*
> + * Returns true if _any_ gfns in the range [@start, @end) have attributes that
> + * match _any_ bit in @mask.
> + */
> +bool kvm_range_has_any_vm_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
> + unsigned long mask)
> +{
> + XA_STATE(xas, &kvm->mem_attrs.array, start);
> + void *entry;
> +
> + mask &= kvm_supported_vm_mem_attributes(kvm);
> + if (!mask)
> + return false;
> +
> + if (end == start + 1)
> + return !!(kvm_get_vm_memory_attributes(kvm, start) & mask);
> +
> + guard(rcu)();
> + for (;;) {
> + do {
> + entry = xas_next(&xas);
> + } while (xas_retry(&xas, entry));
> +
> + if (xas.xa_node == XAS_BOUNDS || xas.xa_index >= end)
> + break;
> +
> + if (xa_to_value(entry) & mask)
> + return true;
> + }
[Severity: High]
Can kvm_range_has_any_vm_memory_attributes() trigger an RCU CPU stall or soft
lockup when userspace invokes KVM_SET_MEMORY_ATTRIBUTES over a large sparse or
unassigned GFN range?
Unassigned GFNs are represented as NULL entries in kvm->mem_attrs.array, where
xa_to_value(NULL) is 0, so NULL entries do not match mask and do not terminate
the loop. However, the loop uses xas_next(&xas), which increments xas.xa_index
by 1 on every call across NULL slots and empty xa_node subtrees whenever the
XArray has an entry at an index >= end keeping xas.xa_node from reaching
XAS_BOUNDS.
Because the entire loop runs inside guard(rcu)() without rescheduling,
scanning a large sparse range will step through every empty GFN index one by
one while holding the RCU read lock. Should this use xas_next_entry(&xas,
end - 1) or xas_for_each(&xas, entry, end - 1) to skip empty slots?
> +
> + return false;
> +}
> +
> +#define KVM_MEMORY_ATTRIBUTE_NEEDS_SYNC_MASK KVM_MEMORY_ATTRIBUTE_PROT
> +
> +static bool kvm_range_memory_attributes_need_sync(struct kvm *kvm,
> + gfn_t start, gfn_t end,
> + unsigned long attributes)
> +{
> + u64 mask = KVM_MEMORY_ATTRIBUTE_NEEDS_SYNC_MASK;
> +
> + if (attributes & mask)
> + return true;
> +
> + return kvm_range_has_any_vm_memory_attributes(kvm, start, end, mask);
> +}
> +
> static __always_inline void kvm_handle_gfn_range(struct kvm *kvm,
> struct kvm_mmu_notifier_range *range)
> {
> @@ -2648,20 +2696,25 @@ static int kvm_set_vm_mem_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
> .on_lock = kvm_mmu_invalidate_end,
> .may_block = true,
> };
> + bool sync = false;
> unsigned long i;
> void *entry;
> int r = 0;
>
> entry = attributes ? xa_mk_value(attributes) : NULL;
>
> - trace_kvm_set_vm_mem_attributes(start, end, attributes);
> -
> mutex_lock(&kvm->slots_lock);
>
> /* Nothing to do if the entire range has the desired attributes. */
> if (kvm_range_has_vm_memory_attributes(kvm, start, end, ~0, attributes))
> goto out_unlock;
>
> + sync = kvm_range_memory_attributes_need_sync(kvm, start, end,
> + attributes);
> +
> + trace_kvm_set_vm_mem_attributes(start, end, attributes, sync,
> + kvm->mem_attrs.generation + 1);
> +
> /*
> * Reserve memory ahead of time to avoid having to deal with failures
> * partway through setting the new attributes. Storing NULL never
> @@ -2684,10 +2737,16 @@ static int kvm_set_vm_mem_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
> cond_resched();
> }
>
> + /* Pairs with acquire in kvm_mem_attributes_generation() */
> + smp_store_release(&kvm->mem_attrs.generation,
> + kvm->mem_attrs.generation + 1);
> +
> kvm_handle_gfn_range(kvm, &post_set_range);
>
> out_unlock:
> mutex_unlock(&kvm->slots_lock);
> + if (sync)
> + synchronize_srcu_expedited(&kvm->srcu);
[Severity: Medium]
Should kvm->mem_attrs.generation only be incremented when sync is true, and
should synchronize_srcu_expedited() be skipped if xa_reserve() fails?
The commit message notes that for memory attributes that do not require
synchronization, the attributes generation will always remain unchanged.
However, kvm_set_vm_mem_attributes() unconditionally increments
kvm->mem_attrs.generation via smp_store_release() even when sync is false,
which invalidates all gfn_to_hva_cache and gfn_to_pfn_cache entries across the
VM (and causes non-refreshing cache checks such as
kvm_steal_time_set_preempted() to bail out) when toggling attributes like
KVM_MEMORY_ATTRIBUTE_PRIVATE.
In addition, because sync is computed and trace_kvm_set_vm_mem_attributes() is
called with kvm->mem_attrs.generation + 1 before the xa_reserve() loop:
for (i = start; entry && i < end; i++) {
r = xa_reserve(&kvm->mem_attrs.array, i, GFP_KERNEL_ACCOUNT);
if (r)
goto out_unlock;
cond_resched();
}
if xa_reserve() fails and jumps to out_unlock while sync is true,
kvm_set_vm_mem_attributes() still runs synchronize_srcu_expedited(&kvm->srcu)
even though no attributes or generation numbers were updated.
[ ... ]
> @@ -3582,7 +3641,8 @@ int kvm_vcpu_write_guest(struct kvm_vcpu *vcpu, gpa_t gpa, const void *data,
> }
> EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_write_guest);
>
> -static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots,
> +static int __kvm_gfn_to_hva_cache_init(struct kvm *kvm,
> + struct kvm_memslots *slots,
> struct gfn_to_hva_cache *ghc,
> gpa_t gpa, unsigned long len)
> {
> @@ -3592,8 +3652,8 @@ static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots,
> gfn_t nr_pages_needed = end_gfn - start_gfn + 1;
> gfn_t nr_pages_avail;
>
> - /* Update ghc->generation before performing any error checks. */
> - ghc->generation = slots->generation;
> + /* Update ghc->slots_generation before performing any error checks. */
> + ghc->slots_generation = slots->generation;
>
> if (start_gfn > end_gfn) {
> ghc->hva = KVM_HVA_ERR_BAD;
> @@ -3612,6 +3672,8 @@ static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots,
> return -EFAULT;
> }
>
> + ghc->attrs_generation = kvm_mem_attributes_generation(kvm);
[Severity: Low]
Should ghc->attrs_generation be updated alongside ghc->slots_generation before
the error checks in __kvm_gfn_to_hva_cache_init()?
ghc->slots_generation is updated before checking start_gfn > end_gfn or
running the gfn_to_hva_many() loop so that when an invalid GPA sets ghc->hva
to KVM_HVA_ERR_BAD, subsequent calls to kvm_read_guest_offset_cached() or
kvm_write_guest_offset_cached() pass kvm_memslots_check_gen() and immediately
hit the fast-path kvm_is_error_hva(ghc->hva) check.
Because ghc->attrs_generation is only updated after those error returns (which
remains the case after the follow-up commit "KVM: Take memory protections into
account for accesses with cached gfn->hva"), if a cached range fails in the
memslot lookup loop after kvm->mem_attrs.generation has advanced,
ghc->attrs_generation remains stale and every subsequent cached access will
repeatedly fail kvm_memslots_check_gen() and re-run
__kvm_gfn_to_hva_cache_init().
[1] https://lore.kernel.org/r/20260918081543.139871-19-pbonzini@redhat.com
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261102174130.8779-1-pbonzini@redhat.com?part=24
next prev parent reply other threads:[~2026-11-02 18:20 UTC|newest]
Thread overview: 71+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 17:40 [PATCH v4 00/45] KVM: x86: Introduce memory protection attributes Paolo Bonzini
2026-11-02 17:40 ` [PATCH 01/45] KVM: nVMX/nSVM: check unconditionally whether CR3 is valid Paolo Bonzini
2026-11-02 18:05 ` sashiko-bot
2026-11-02 17:40 ` [PATCH 02/45] KVM: x86/hyperv: do not overwrite hc->ingpa for SIGNAL_EVENT hypercall Paolo Bonzini
2026-11-02 17:40 ` [PATCH 03/45] KVM: x86: apply nGPA->GPA translation to KVM_HC_CLOCK_PAIRING Paolo Bonzini
2026-11-02 17:40 ` [PATCH 04/45] KVM: x86/emulate: Check TSS busy-bit writes during task switches Paolo Bonzini
2026-11-02 18:22 ` sashiko-bot
2026-11-02 17:40 ` [PATCH 05/45] KVM: loongarch: do full validity check on the gfn-to-hva cache Paolo Bonzini
2026-11-02 17:40 ` [PATCH 06/45] KVM: selftests: Test address translation for Hyper-V direct L2 hypercalls Paolo Bonzini
2026-11-02 17:40 ` [PATCH 07/45] KVM: selftests: Take into account mixed memory fault flags Paolo Bonzini
2026-11-02 17:50 ` sashiko-bot
2026-11-02 17:40 ` [PATCH 08/45] selftests: kvm: drop TEST_ASSERT_SUPPORTED_ATTRIBUTES Paolo Bonzini
2026-11-02 17:40 ` [PATCH 09/45] KVM: Define and communicate KVM_EXIT_MEMORY_FAULT RWX flags to userspace Paolo Bonzini
2026-11-02 17:55 ` sashiko-bot
2026-11-02 17:40 ` [PATCH 10/45] KVM: x86: Introduce memory fault on invalid hypercalls reads/writes Paolo Bonzini
2026-11-02 17:40 ` [PATCH 11/45] KVM: selftests: test hypercall memory fault exits Paolo Bonzini
2026-11-02 17:58 ` sashiko-bot
2026-11-02 17:40 ` [PATCH 12/45] KVM: x86/mmu: intersect writability from __kvm_faultin_pfn with fault->map_writable Paolo Bonzini
2026-11-02 17:40 ` [PATCH 13/45] KVM: x86/mmu: Extend map_writable to a full ACC_* mask Paolo Bonzini
2026-11-02 17:40 ` [PATCH 14/45] KVM: x86/mmu: Init memslot hugepage information for non-private_mem VMs too Paolo Bonzini
2026-11-02 17:40 ` [PATCH 15/45] KVM: VMX: return error from kvm_set_cr* Paolo Bonzini
2026-11-02 17:41 ` [PATCH 16/45] KVM: adjust for presence of more than one attribute Paolo Bonzini
2026-11-02 18:03 ` sashiko-bot
2026-11-02 17:44 ` [PATCH 17/45] KVM: Introduce NR/NW/NX memory attributes Paolo Bonzini
2026-11-02 18:04 ` sashiko-bot
2026-11-03 9:25 ` kernel test robot
2026-11-02 17:44 ` [PATCH 18/45] KVM: Include memory protections in result of gfn->hva conversion Paolo Bonzini
2026-11-02 17:44 ` [PATCH 19/45] KVM: Introduce kvm_fetch_guest_page() and use it for x86 Paolo Bonzini
2026-11-02 17:44 ` [PATCH 20/45] KVM: Take memory protections into account for memory read/write/fetch Paolo Bonzini
2026-11-02 17:44 ` [PATCH 21/45] KVM: Take memory protections into account for __kvm_vcpu_map Paolo Bonzini
2026-11-02 17:44 ` [PATCH 22/45] KVM: Encapsulate memattrs array into anonymous struct Paolo Bonzini
2026-11-02 17:44 ` [PATCH 23/45] KVM: Introduce kvm_check_gen()/kvm_memslots_check_gen() Paolo Bonzini
2026-11-02 18:04 ` sashiko-bot
2026-11-03 18:07 ` kernel test robot
2026-11-02 17:44 ` [PATCH 24/45] KVM: Introduce a generation number for memory attributes Paolo Bonzini
2026-11-02 18:20 ` sashiko-bot [this message]
2026-11-03 14:11 ` kernel test robot
2026-11-02 17:44 ` [PATCH 25/45] KVM: Take memory protections into account for accesses with cached gfn->hva Paolo Bonzini
2026-11-02 18:14 ` sashiko-bot
2026-11-02 17:44 ` [PATCH 26/45] KVM: pfncache: Fail to refresh if it contains memory protections Paolo Bonzini
2026-11-02 18:09 ` sashiko-bot
2026-11-02 17:44 ` [PATCH 27/45] KVM: x86/mmu: Do not prefetch sptes on gfns backed by memory attributes Paolo Bonzini
2026-11-02 17:44 ` [PATCH 28/45] KVM: x86/mmu: Take memory protection attributes into account during faults Paolo Bonzini
2026-11-02 18:26 ` sashiko-bot
2026-11-02 17:44 ` [PATCH 29/45] KVM: x86/emulate: change return value of emulator_io_permitted to int Paolo Bonzini
2026-11-02 17:44 ` [PATCH 30/45] KVM: x86/emulate: Propagate memory faults to userspace Paolo Bonzini
2026-11-02 18:32 ` sashiko-bot
2026-11-02 17:44 ` [PATCH 31/45] KVM: x86: "Handle" failed decode when skipping instructions Paolo Bonzini
2026-11-02 18:18 ` sashiko-bot
2026-11-02 17:44 ` [PATCH 32/45] KVM: vmx/sgx: make return value of sgx_gva_to_gpa consistent with its callers Paolo Bonzini
2026-11-02 17:45 ` [PATCH 33/45] KVM: x86: Allow page fault fixup to return errors Paolo Bonzini
2026-11-02 17:45 ` [PATCH 34/45] KVM: x86/mmu: Adjust gva_to_gpa to allow returning an error Paolo Bonzini
2026-11-02 18:19 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 35/45] KVM: x86/mmu: Propagate errors from nested GPA translation Paolo Bonzini
2026-11-02 17:45 ` [PATCH 36/45] KVM: x86: Propagate memory faults through load_pdptrs() Paolo Bonzini
2026-11-02 18:29 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 37/45] KVM: x86/mmu: Issue memory fault exit if walk failed due to memory attribute Paolo Bonzini
2026-11-02 18:32 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 38/45] KVM: x86: mark VM as dead after KVM_SET_SREGS fails to load PDPTRs Paolo Bonzini
2026-11-02 18:28 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 39/45] KVM: VMX: mark VM dead on shadow VMCS or eVMCS access failures Paolo Bonzini
2026-11-02 18:40 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 40/45] KVM: let kvm_arch_post_set_memory_attributes drop mmu_lock Paolo Bonzini
2026-11-02 17:45 ` [PATCH 41/45] KVM: x86/mmu: Obsolete all roots if memattr contains gPTEs Paolo Bonzini
2026-11-02 17:45 ` [PATCH 42/45] KVM: x86: selftests: Introduce memory protection attributes test Paolo Bonzini
2026-11-02 18:43 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 43/45] KVM: x86: selftests: Introduce memory attributes PTE test Paolo Bonzini
2026-11-02 17:45 ` [PATCH 44/45] KVM: x86: selftests: Introduce memory attributes side-channel tests Paolo Bonzini
2026-11-02 18:41 ` sashiko-bot
2026-11-02 17:45 ` [PATCH 45/45] KVM: x86: split out parts of load_pdptrs Paolo Bonzini
2026-11-03 14:40 ` [syzbot ci] Re: KVM: x86: Introduce memory protection attributes syzbot ci
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=sashiko-outbox-193927@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=sashiko-reviews@lists.linux.dev \
/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