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 <tabba@google.com>, 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>, Lorenzo Stoakes <ljs@kernel.org>,
Itaru Kitayama <itaru.kitayama@fujitsu.com>,
Wei-Lin Chang <weilin.chang@arm.com>
Subject: [PATCH v5 0/6] KVM: arm64: nv: Implement nested stage-2 reverse map (new data structure)
Date: Mon, 10 Aug 2026 21:50:32 +0100 [thread overview]
Message-ID: <20260810205038.118843-1-weilin.chang@arm.com> (raw)
Hi,
This is v5 of optimizing the shadow s2 mmu unmapping during MMU
notifiers.
This time, a major overhaul is done to the implementation. After
receiving some suggestions from Marc, I have identified that using the
interval tree to store the guest stage-2 mappings solves many problems
compared to using the maple tree.
Interval Tree vs Maple Tree
===========================
First of all, interval trees are capable of storing overlapping ranges,
which is helpful when the L1 hypervisor maps something like:
nested IPA [x, x+4K) -> canonical IPA [a, a+4K)
nested IPA [y, y+2M) -> canonical IPA [a, a+2M)
No problems with storing that in the interval tree with different nodes.
We can avoid the maple tree UNKNOWN_IPA mechanism as a compromise.
Second, ideally we would want to save the canonical IPA <-> nested IPA
mapping in both directions to allow MMU notifier unmap speed up, and
stale shadow mapping removals. If we use the maple tree, we'll have to
have 2 separate trees, and make sure they store the same mappings, which
isn't simple given the first point.
On the other hand, by using this pattern:
/* Record of a guest stage-2 mapping. */
struct kvm_guest_s2_mapping {
struct interval_tree_node canonical; // CIPA range of the mapping
struct interval_tree_node nested; // NIPA range of the mapping
struct kvm_s2_mmu *nested_mmu; // mmu of the NIPA space
};
and equip each mmu with an interval tree storing mapping records
corresponding to the IPA space it represents, we can insert the
respective nodes into the canonical IPA tree, and the corresponding
nested IPA tree. This makes it trivial to find the range of the other
IPA space from a range in one IPA space.
Diagram to help understanding:
struct kvm_guest_s2_mapping mapping1, mapping2;
---------------------> mapping2.canonical
| mapping1.canonical
| ^ (both stored in canonical mmu's tree)
| |
--*****-----------------------*****----------- CIPA
\\\\\ ||||| mapping1.nested_mmu
\\\\\ \\\\\ |
\\\\\ \\\\\ v
------\\\\\---------------------*****--------- NIPA #1 (nested mmu #1)
\\\\\ |
\\\\\ -> mapping1.nested
\\\\\ (stored in nested mmu #1's tree)
\\\\\
-----------*****------------------------------ NIPA #2 (nested mmu #2)
| ^
-> mapping2.nested |
(stored in nested mmu #2's tree) mapping2.nested_mmu
Third, maple tree does its own memory allocation. In the KVM stage-2
fault path we only find out what the mapping ranges are after taking the
KVM MMU lock, and the maple tree has to know the range and entry to be
stored to preallocate, therefore in our case the maple tree is forced to
only use GFP_NOWAIT, which isn't the best. With the interval tree the
user does the memory management, and we can just allocate before taking
the locks.
Locking
=======
The guest_s2_tracking_lock serializes accesses to the tracking interval
trees. It is taken after the mmu_lock. However in reality it is only
taken after we take the read mmu_lock in the stage-2 fault path, as
other accesses have the write mmu_lock already. This saves us some
manual lock/unlocks.
vCPU Stage-2 Fault Scalability Reduction
========================================
KVM/arm64 is able to handle stage-2 faults from multiple vCPUs in
parallel, thanks to the engineering done to the s2 pgtable code. However
to safely insert mappings into the interval trees we have to serialize
using the guest_s2_tracking_lock. We trade some performance in stage-2
fault for faster MMU notifier unmaps, and keeping the unaffected shadow
mappings.
Memory Usage
============
Each interval tree node is 48 bytes, and a kvm_guest_s2_mapping is 104
bytes, residing in 128-byte slab objects. Each shadow stage-2 fault
requires one kvm_guest_s2_mapping instance. This is 32MB for a fully 4KB
mapped 1GB region, and 64KB for a 2MB mapped 1GB region.
Series Structure
================
Patch 1: Preparatory refactoring.
Patch 2: Introduce data structures for guest stage-2 tracking.
Patch 3-4: Guest stage-2 tracking addition and removal
Patch 5: Avoid full unmap during MMU notifier unmap using the tracked
guest stage-2 mapping information.
Patch 6: Minor clean up.
As this is a complete rework, I will omit the change log this time.
Series is based on v7.2-rc5.
Thanks!
Link to v4: https://lore.kernel.org/kvmarm/20260714115926.2044757-1-weilin.chang@arm.com/
Wei-Lin Chang (6):
KVM: arm64: Use a variable for the canonical IPA in kvm_s2_fault_map()
KVM: arm64: nv: Introduce guest stage-2 tracking structures
KVM: arm64: nv: Track guest stage-2 mapping creation
KVM: arm64: nv: Track guest stage-2 mapping removal
KVM: arm64: nv: Avoid full shadow stage-2 unmap
KVM: arm64: Refactor kvm_unmap_gfn_range() with common variables
arch/arm64/include/asm/kvm_host.h | 20 ++++++
arch/arm64/include/asm/kvm_nested.h | 7 ++
arch/arm64/kvm/mmu.c | 105 ++++++++++++++++++++++++----
arch/arm64/kvm/nested.c | 95 +++++++++++++++++++++++++
4 files changed, 215 insertions(+), 12 deletions(-)
--
2.43.0
next reply other threads:[~2026-08-10 20:52 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 20:50 Wei-Lin Chang [this message]
2026-08-10 20:50 ` [PATCH v5 1/6] KVM: arm64: Use a variable for the canonical IPA in kvm_s2_fault_map() Wei-Lin Chang
2026-08-10 20:50 ` [PATCH v5 2/6] KVM: arm64: nv: Introduce guest stage-2 tracking structures Wei-Lin Chang
2026-08-10 20:50 ` [PATCH v5 3/6] KVM: arm64: nv: Track guest stage-2 mapping creation Wei-Lin Chang
2026-08-10 20:50 ` [PATCH v5 4/6] KVM: arm64: nv: Track guest stage-2 mapping removal Wei-Lin Chang
2026-08-10 20:50 ` [PATCH v5 5/6] KVM: arm64: nv: Avoid full shadow stage-2 unmap Wei-Lin Chang
2026-08-10 20:50 ` [PATCH v5 6/6] KVM: arm64: Refactor kvm_unmap_gfn_range() with common variables 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=20260810205038.118843-1-weilin.chang@arm.com \
--to=weilin.chang@arm.com \
--cc=catalin.marinas@arm.com \
--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=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=seiden@linux.ibm.com \
--cc=suzuki.poulose@arm.com \
--cc=tabba@google.com \
--cc=will@kernel.org \
--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