FAILED: patch "[PATCH] KVM: arm64: Correctly handle page aging notifiers for" failed to apply to 4.19-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.19-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-4.19.y
git checkout FETCH_HEAD
git cherry-pick -x df6556adf27b7372cfcd97e1c0afb0d516c8279f
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023072357-trilogy-average-5fd9@gregkh' --subject-prefix 'PATCH 4.19.y' HEAD^..
Possible dependencies:
df6556adf27b ("KVM: arm64: Correctly handle page aging notifiers for unaligned memslot") ca5de2448c3b ("KVM: arm64: Atomically update stage 2 leaf attributes in parallel walks") 6b91b8f95cad ("KVM: arm64: Use an opaque type for pteps")fa002e8e79b3 ("KVM: arm64: Don't pass kvm_pgtable through kvm_pgtable_walk_data") 2a611c7f87f2 ("KVM: arm64: Pass mm_ops through the visitor context") 83844a2317ec ("KVM: arm64: Stash observed pte value in visitor context") dfc7a7769ab7 ("KVM: arm64: Combine visitor arguments into a context structure") 094d00f8ca58 ("KVM: arm64: pkvm: Use the mm_ops indirection for cache maintenance") e82edcc75c4e ("KVM: arm64: Implement do_share() helper for sharing memory") 82bb02445de5 ("KVM: arm64: Implement kvm_pgtable_hyp_unmap() at EL2") d6b4bd3f4897 ("KVM: arm64: Fixup hyp stage-1 refcount")2ea2ff91e822 ("KVM: arm64: Refcount hyp stage-1 pgtable pages") cf0c7125d578 ("Merge branch kvm-arm64/mmu/el2-tracking into kvmarm-master/next")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From df6556adf27b7372cfcd97e1c0afb0d516c8279f Mon Sep 17 00:00:00 2001
From: Oliver Upton <[email protected]>
Date: Tue, 27 Jun 2023 23:54:05 +0000
Subject: [PATCH] KVM: arm64: Correctly handle page aging notifiers for
unaligned memslot
Userspace is allowed to select any PAGE_SIZE aligned hva to back guest memory. This is even the case with hugepages, although it is a rather suboptimal configuration as PTE level mappings are used at stage-2.
The arm64 page aging handlers have an assumption that the specified range is exactly one page/block of memory, which in the aforementioned case is not necessarily true. All together this leads to the WARN() in kvm_age_gfn() firing.
However, the WARN is only part of the issue as the table walkers visit at most a single leaf PTE. For hugepage-backed memory in a memslot that isn't hugepage-aligned, page aging entirely misses accesses to the hugepage beyond the first page in the memslot.
Add a new walker dedicated to handling page aging MMU notifiers capable of walking a range of PTEs. Convert kvm(_test)_age_gfn() over to the new walker and drop the WARN that caught the issue in the first place. The implementation of this walker was inspired by the test_clear_young() implementation by Yu Zhao [*], but repurposed to address a bug in the existing aging implementation.
arch/arm64/include/asm/kvm_pgtable.h +9 -17
@@ -608,22 +608,26 @@ int kvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size);kvm_pte_t kvm_pgtable_stage2_mkyoung (struct kvm_pgtable *pgt,u64 addr);/** -* kvm_pgtable_stage2_mkold() - Clear the access flag in a page-table entry. +* kvm_pgtable_stage2_test_clear_young() - Test and optionally clear the access +* flag in a page-table entry. * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*(). * @addr: Intermediate physical address to identify the page-table entry. +* @size: Size of the address range to visit. +* @mkold: True if the access flag should be cleared. * * The offset of @addr within a page is ignored. * -* If there is a valid, leaf page-table entry used to translate @addr, then -* clear the access flag in that entry. +* Tests and conditionally clears the access flag for every valid, leaf +* page-table entry used to translate the range [@addr, @addr + @size). * * Note that it is the caller's responsibility to invalidate the TLB after * calling this function to ensure that the updated permissions are visible * to the CPUs. * -* Return: The old page-table entry prior to clearing the flag, 0 on failure. +* Return: True if any of the visited PTEs had the access flag set. */ -kvm_pte_t kvm_pgtable_stage2_mkold (struct kvm_pgtable *pgt,u64 addr); +bool kvm_pgtable_stage2_test_clear_young (struct kvm_pgtable *pgt,u64 addr, +u64 size,bool mkold);/** * kvm_pgtable_stage2_relax_perms() - Relax the permissions enforced by a
@@ -645,18 +649,6 @@ kvm_pte_t kvm_pgtable_stage2_mkold(struct kvm_pgtable *pgt, u64 addr);int kvm_pgtable_stage2_relax_perms (struct kvm_pgtable *pgt,u64 addr,enum kvm_pgtable_prot prot); -/** -* kvm_pgtable_stage2_is_young() - Test whether a page-table entry has the -* access flag set. -* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*(). -* @addr: Intermediate physical address to identify the page-table entry. -* -* The offset of @addr within a page is ignored. -* -* Return: True if the page-table entry has the access flag set, false otherwise. -*/ -bool kvm_pgtable_stage2_is_young (struct kvm_pgtable *pgt,u64 addr); -/** * kvm_pgtable_stage2_flush_range() - Clean and invalidate data cache to Point * of Coherency for guest stage-2 address
arch/arm64/kvm/hyp/pgtable.c +38 -9
63 lines not on this page · raw message
arch/arm64/kvm/mmu.c +8 -10
@@ -1756,27 +1756,25 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)bool kvm_age_gfn (struct kvm *kvm,struct kvm_gfn_range *range) {u64 size = (range->end - range->start) <<PAGE_SHIFT ; -kvm_pte_t kpte; -pte_t pte;if (!kvm->arch.mmu.pgt)return false; -WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE && size !=PUD_SIZE ); - - kpte =kvm_pgtable_stage2_mkold (kvm->arch.mmu.pgt, - range->start <<PAGE_SHIFT ); - pte =__pte (kpte); -return pte_valid (pte) &&pte_young (pte); +return kvm_pgtable_stage2_test_clear_young (kvm->arch.mmu.pgt, + range->start <<PAGE_SHIFT , + size, true); }bool kvm_test_age_gfn (struct kvm *kvm,struct kvm_gfn_range *range) { +u64 size = (range->end - range->start) <<PAGE_SHIFT ; +if (!kvm->arch.mmu.pgt)return false; -return kvm_pgtable_stage2_is_young (kvm->arch.mmu.pgt, - range->start <<PAGE_SHIFT ); +return kvm_pgtable_stage2_test_clear_young (kvm->arch.mmu.pgt, + range->start <<PAGE_SHIFT , + size, false); }phys_addr_t kvm_mmu_get_httbr (void )