From: Wei-Lin Chang <weilin.chang@arm.com>
To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-kernel@vger.kernel.org
Cc: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
Fuad Tabba <fuad.tabba@linux.dev>,
Joey Gouly <joey.gouly@arm.com>,
Steffen Eiden <seiden@linux.ibm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Itaru Kitayama <itaru.kitayama@fujitsu.com>,
Wang Han <wanghan@linux.alibaba.com>,
Shuai Xue <xueshuai@linux.alibaba.com>,
"Lorenzo Stoakes (ARM)" <ljs@kernel.org>,
Wei-Lin Chang <weilin.chang@arm.com>
Subject: [PATCH v6 4/7] KVM: arm64: nv: Track guest stage-2 mapping removal
Date: Tue, 15 Sep 2026 16:43:02 +0100 [thread overview]
Message-ID: <20260915154305.3852871-5-weilin.chang@arm.com> (raw)
In-Reply-To: <20260915154305.3852871-1-weilin.chang@arm.com>
kvm_stage2_unmap_range() is the helper to remove mappings from the
stage-2 page tables. It is called during guest TLBI handling, memslot
removal, nested mmu reuse, etc.
Teach it about the guest stage-2 tracking trees and remove mappings from
there when shadow mappings are removed. This keeps the tracking trees
from having stale mappings pile up.
Don't remove tracked mappings from the interval trees if they only
partially overlap the removal range. For instance we can have a 4K
shadow mapping tracked as a 2M range in the interval trees. It would be
wrong to remove the tracked 2M range when a guest TLBI doesn't touch the
4K mapped.
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
---
arch/arm64/include/asm/kvm_host.h | 5 ++++-
arch/arm64/include/asm/kvm_nested.h | 2 ++
arch/arm64/kvm/mmu.c | 23 +++++++++++++++++--
arch/arm64/kvm/nested.c | 34 +++++++++++++++++++++++++++++
4 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 365ec57d6d7a..f12883a42081 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -340,7 +340,10 @@ struct kvm_arch {
size_t nested_mmus_size;
int nested_mmus_next;
- /* Guest s2 tracking trees access serialization. */
+ /*
+ * Serializes guest s2 tracking trees access when the mmu_lock
+ * is only held for read.
+ */
spinlock_t guest_s2_tracking_lock;
/* Interrupt controller */
diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
index 2d71f686064a..954f532bc11b 100644
--- a/arch/arm64/include/asm/kvm_nested.h
+++ b/arch/arm64/include/asm/kvm_nested.h
@@ -81,6 +81,8 @@ extern void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
extern void kvm_record_guest_s2_mapping(struct kvm_s2_mmu *mmu, gpa_t canonical_ipa,
gpa_t nested_ipa, size_t map_size,
struct kvm_guest_s2_mapping *mapping);
+extern void kvm_remove_guest_s2_mappings(struct kvm_s2_mmu *mmu,
+ gpa_t nipa, size_t size);
extern void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu);
extern void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 9bc799553ce9..c46e92d67f04 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -314,6 +314,19 @@ static void invalidate_icache_guest_page(void *va, size_t size)
* we then fully enforce cacheability of RAM, no matter what the guest
* does.
*/
+
+static int kvm_pgtable_stage2_unmap_tracked(struct kvm_pgtable *pgt, u64 addr, u64 size)
+{
+ int ret;
+
+ ret = kvm_pgtable_stage2_unmap(pgt, addr, size);
+ if (ret)
+ return ret;
+
+ kvm_remove_guest_s2_mappings(pgt->mmu, addr, size);
+ return 0;
+}
+
/**
* __unmap_stage2_range -- Clear stage2 page table entries to unmap a range
* @mmu: The KVM stage-2 MMU pointer
@@ -331,11 +344,17 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64
{
struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
phys_addr_t end = start + size;
+ int (*fn)(struct kvm_pgtable *, u64, u64);
lockdep_assert_held_write(&kvm->mmu_lock);
WARN_ON(size & ~PAGE_MASK);
- WARN_ON(stage2_apply_range(mmu, start, end, KVM_PGT_FN(kvm_pgtable_stage2_unmap),
- may_block));
+
+ if (kvm_is_nested_s2_mmu(kvm, mmu))
+ fn = kvm_pgtable_stage2_unmap_tracked;
+ else
+ fn = KVM_PGT_FN(kvm_pgtable_stage2_unmap);
+
+ WARN_ON(stage2_apply_range(mmu, start, end, fn, may_block));
}
void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index d9acff507fd2..92a9a32f9f2b 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -897,6 +897,40 @@ void kvm_record_guest_s2_mapping(struct kvm_s2_mmu *mmu, gpa_t canonical_ipa,
interval_tree_insert(&mapping->canonical, &kvm->arch.mmu.guest_s2_mappings);
}
+void kvm_remove_guest_s2_mappings(struct kvm_s2_mmu *mmu, gpa_t nipa,
+ size_t size)
+{
+ struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
+ struct interval_tree_node *node, *next;
+ struct kvm_guest_s2_mapping *mapping;
+ gpa_t nipa_end = nipa + size - 1;
+
+ /*
+ * Guest s2 tracking interval trees are only accessed while holding the
+ * mmu_lock, hence we don't have to take guest_s2_tracking_lock if the
+ * mmu_lock is held for write.
+ */
+ lockdep_assert_held_write(&kvm->mmu_lock);
+
+ node = interval_tree_iter_first(&mmu->guest_s2_mappings, nipa, nipa_end);
+ while (node) {
+ next = interval_tree_iter_next(node, nipa, nipa_end);
+ mapping = container_of(node, struct kvm_guest_s2_mapping,
+ nested);
+ /*
+ * Tracking must be conservative on removal, only remove
+ * mappings that are within the unmap range.
+ */
+ if (nipa <= mapping->nested.start && nipa_end >= mapping->nested.last) {
+ interval_tree_remove(&mapping->nested, &mmu->guest_s2_mappings);
+ interval_tree_remove(&mapping->canonical,
+ &kvm->arch.mmu.guest_s2_mappings);
+ kfree(mapping);
+ }
+ node = next;
+ }
+}
+
void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu)
{
/* CnP being set denotes an invalid entry */
--
2.43.0
next prev parent reply other threads:[~2026-09-15 15:43 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-15 15:42 [PATCH v6 0/7] KVM: arm64: nv: Implement nested stage-2 reverse map Wei-Lin Chang
2026-09-15 15:42 ` [PATCH v6 1/7] KVM: arm64: Use a variable for the canonical IPA in kvm_s2_fault_map() Wei-Lin Chang
2026-09-15 15:43 ` [PATCH v6 2/7] KVM: arm64: nv: Introduce guest stage-2 tracking structures Wei-Lin Chang
2026-09-15 15:43 ` [PATCH v6 3/7] KVM: arm64: nv: Track guest stage-2 mapping creation Wei-Lin Chang
2026-09-15 15:43 ` Wei-Lin Chang [this message]
2026-09-15 15:43 ` [PATCH v6 5/7] KVM: arm64: nv: Avoid full shadow stage-2 unmap Wei-Lin Chang
2026-09-15 15:43 ` [PATCH v6 6/7] KVM: arm64: nv: Drop kvm_s2_mmu pointer from kvm_guest_s2_mapping Wei-Lin Chang
2026-09-15 15:43 ` [PATCH v6 7/7] KVM: arm64: Refactor kvm_unmap_gfn_range() with common variables Wei-Lin Chang
2026-09-15 21:49 ` [PATCH v6 0/7] KVM: arm64: nv: Implement nested stage-2 reverse map Itaru Kitayama
2026-09-15 23:22 ` Wei-Lin Chang
2026-09-15 23:27 ` Itaru Kitayama
2026-09-16 7:08 ` Marc Zyngier
2026-09-17 6:51 ` Itaru Kitayama
2026-09-17 7:56 ` Marc Zyngier
2026-09-17 21:46 ` Itaru Kitayama
2026-09-17 13:10 ` Wei-Lin Chang
2026-09-15 22:49 ` Oliver Upton
2026-09-16 4:58 ` Itaru Kitayama
2026-09-16 7:04 ` Marc Zyngier
2026-09-16 10:08 ` Wei-Lin Chang
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=20260915154305.3852871-5-weilin.chang@arm.com \
--to=weilin.chang@arm.com \
--cc=catalin.marinas@arm.com \
--cc=fuad.tabba@linux.dev \
--cc=itaru.kitayama@fujitsu.com \
--cc=joey.gouly@arm.com \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=seiden@linux.ibm.com \
--cc=suzuki.poulose@arm.com \
--cc=wanghan@linux.alibaba.com \
--cc=will@kernel.org \
--cc=xueshuai@linux.alibaba.com \
--cc=yuzenghui@huawei.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
all inboxes | Powered by JetHome®