From: Fuad Tabba <tabba@google.com>
To: kvm@vger.kernel.org, kvmarm@lists.linux.dev,
linux-arm-kernel@lists.infradead.org
Cc: maz@kernel.org, oliver.upton@linux.dev, joey.gouly@arm.com,
suzuki.poulose@arm.com, yuzenghui@huawei.com,
catalin.marinas@arm.com, will@kernel.org, qperret@google.com,
vdonnefort@google.com, tabba@google.com
Subject: [PATCH v1 00/13] KVM: arm64: Refactor user_mem_abort() into a state-object model
Date: Fri, 6 Mar 2026 14:02:19 +0000 [thread overview]
Message-ID: <20260306140232.2193802-1-tabba@google.com> (raw)
As promised in my recent patch series fixing a couple of urgent bugs in
user_mem_abort() [1], here is the actual refactoring to finally clean up this
monolith.
If you look through the Fixes: history of user_mem_abort(), you will start to
see a very clear pattern of whack-a-mole caused by the sheer size and
complexity of the function. For example:
- We keep leaking struct page references on early error returns because the
cleanup logic is hard to track (e.g., 5f9466b50c1b and the atomic fault leak
I just fixed in the previous series).
- We have had uninitialized memcache pointers (157dbc4a321f) because the
initialization flow jumps around unpredictably.
- We have had subtle TOCTOU and locking boundary bugs (like 13ec9308a857 and
f587661f21eb) because we drop the mmap_read_lock midway through the function
but leave the vma pointer and mmu_seq floating around in the same lexical
scope, tempting people to use them.
The bulk of the work is in the first 6 patches, which perform a strict,
no-logic-change structural refactoring of user_mem_abort() into a clean,
sequential dispatcher.
We introduce a state object, struct kvm_s2_fault, which encapsulates
both the input parameters and the intermediate state. Then,
user_mem_abort() is broken down into focused, standalone helpers:
- kvm_s2_resolve_vma_size(): Determines the VMA shift and page size.
- kvm_s2_fault_pin_pfn(): Handles faulting in the physical page.
- kvm_s2_fault_get_vma_info(): A tightly-scoped sub-helper that isolates the
mmap_read_lock, VMA lookup, and metadata snapshotting.
- kvm_s2_fault_compute_prot(): Computes stage-2 protections and evaluates
permission/execution constraints.
- kvm_s2_fault_map(): Manages the KVM MMU lock, mmu_seq retry loops, MTE, and
the final stage-2 mapping.
This structural change makes the "danger zone" foolproof. By isolating
the mmap_read_lock region inside a tightly-scoped sub-helper
(kvm_s2_fault_get_vma_info), the vma pointer is confined. It snapshots
the required metadata into the kvm_s2_fault structure before dropping
the lock. Because the pointers scope ends when the sub-helper returns,
accessing a stale VMA in the mapping phase is not possible by design.
The remaining patches in are localized cleanup patches. With the logic
finally extracted into digestible helpers, these patches take the
opportunity to streamline struct initialization, drop redundant struct
variables, simplify nested math, and hoist validation checks (like MTE)
out of the lock-heavy mapping phase.
I think that there are still more opportunities to tidy things up some
more, but I'll stop here to see what you think.
Based on Linux 7.0-rc2 and my previous fixes series [1].
[1] https://lore.kernel.org/all/20260304162222.836152-1-tabba@google.com/
Cheers,
/fuad
Fuad Tabba (13):
KVM: arm64: Extract VMA size resolution in user_mem_abort()
KVM: arm64: Introduce struct kvm_s2_fault to user_mem_abort()
KVM: arm64: Extract PFN resolution in user_mem_abort()
KVM: arm64: Isolate mmap_read_lock inside new
kvm_s2_fault_get_vma_info() helper
KVM: arm64: Extract stage-2 permission logic in user_mem_abort()
KVM: arm64: Extract page table mapping in user_mem_abort()
KVM: arm64: Simplify nested VMA shift calculation
KVM: arm64: Remove redundant state variables from struct kvm_s2_fault
KVM: arm64: Simplify return logic in user_mem_abort()
KVM: arm64: Initialize struct kvm_s2_fault completely at declaration
KVM: arm64: Optimize early exit checks in kvm_s2_fault_pin_pfn()
KVM: arm64: Hoist MTE validation check out of MMU lock path
KVM: arm64: Clean up control flow in kvm_s2_fault_map()
arch/arm64/kvm/mmu.c | 379 +++++++++++++++++++++++++------------------
1 file changed, 224 insertions(+), 155 deletions(-)
base-commit: f9985be5e1985930c2d2cf2752e36bb145b3ff7c
--
2.53.0.473.g4a7958ca14-goog
next reply other threads:[~2026-03-06 14:02 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-06 14:02 Fuad Tabba [this message]
2026-03-06 14:02 ` [PATCH v1 01/13] KVM: arm64: Extract VMA size resolution in user_mem_abort() Fuad Tabba
2026-03-17 15:07 ` Joey Gouly
2026-03-06 14:02 ` [PATCH v1 02/13] KVM: arm64: Introduce struct kvm_s2_fault to user_mem_abort() Fuad Tabba
2026-03-17 16:00 ` Joey Gouly
2026-03-06 14:02 ` [PATCH v1 03/13] KVM: arm64: Extract PFN resolution in user_mem_abort() Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 04/13] KVM: arm64: Isolate mmap_read_lock inside new kvm_s2_fault_get_vma_info() helper Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 05/13] KVM: arm64: Extract stage-2 permission logic in user_mem_abort() Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 06/13] KVM: arm64: Extract page table mapping " Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 07/13] KVM: arm64: Simplify nested VMA shift calculation Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 08/13] KVM: arm64: Remove redundant state variables from struct kvm_s2_fault Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 09/13] KVM: arm64: Simplify return logic in user_mem_abort() Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 10/13] KVM: arm64: Initialize struct kvm_s2_fault completely at declaration Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 11/13] KVM: arm64: Optimize early exit checks in kvm_s2_fault_pin_pfn() Fuad Tabba
2026-03-17 17:10 ` Joey Gouly
2026-03-06 14:02 ` [PATCH v1 12/13] KVM: arm64: Hoist MTE validation check out of MMU lock path Fuad Tabba
2026-03-06 14:02 ` [PATCH v1 13/13] KVM: arm64: Clean up control flow in kvm_s2_fault_map() Fuad Tabba
2026-03-06 15:34 ` [PATCH v1 00/13] KVM: arm64: Refactor user_mem_abort() into a state-object model Marc Zyngier
2026-03-06 15:44 ` Fuad Tabba
2026-03-16 18:13 ` Marc Zyngier
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=20260306140232.2193802-1-tabba@google.com \
--to=tabba@google.com \
--cc=catalin.marinas@arm.com \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=qperret@google.com \
--cc=suzuki.poulose@arm.com \
--cc=vdonnefort@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