FAILED: patch "[PATCH] KVM: arm64: nv: Delay freeing of shadow S2 structures until" failed to apply to 7.2-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 7.2-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-7.2.y
git checkout FETCH_HEAD
git cherry-pick -x e5843f4effaa2ffac3e789ecd4456403564961d4
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092944-padlock-brunette-089e@gregkh' --subject-prefix 'PATCH 7.2.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e5843f4effaa2ffac3e789ecd4456403564961d4 Mon Sep 17 00:00:00 2001
From: Marc Zyngier <[email protected]>
Date: Fri, 11 Sep 2026 17:22:03 +0100
Subject: [PATCH] KVM: arm64: nv: Delay freeing of shadow S2 structures until
VM destruction
We free the shadow S2 structures from kvm_arch_flush_shadow_all(), which is a Bad Idea(tm). Freeing the page tables is fair game (this is what this callback is for), but freeing the container that could still be referenced by another part of the system is not great.
Instead, grow separate destructors that gets called when we tear the VM down for good. From there, we can nuke both the individual MMUs as well as the global array that points to them, safe in the knowledge that the vcpus themselves have been destroyed already.
arch/arm64/include/asm/kvm_nested.h +1 -0
@@ -67,6 +67,7 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)extern bool forward_smc_trap (struct kvm_vcpu *vcpu);extern bool forward_debug_exception (struct kvm_vcpu *vcpu);extern int kvm_init_nested (struct kvm *kvm); +extern void kvm_destroy_nested (struct kvm *kvm);extern int kvm_vcpu_init_nested (struct kvm_vcpu *vcpu);extern void kvm_init_nested_s2_mmu (struct kvm_s2_mmu *mmu);extern struct kvm_s2_mmu *lookup_s2_mmu (struct kvm_vcpu *vcpu);
arch/arm64/kvm/arm.c +2 -2
@@ -282,7 +282,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) err_uninit_mmu:kvm_uninit_stage2_mmu (kvm); -kvfree (kvm->arch.nested_mmus); +kvm_destroy_nested (kvm); err_free_cpumask:free_cpumask_var (kvm->arch.supported_cpus); err_unshare_kvm:
@@ -340,7 +340,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)kvm_unshare_hyp (kvm, kvm +1 ); -kvfree (kvm->arch.nested_mmus); +kvm_destroy_nested (kvm);kvm_arm_teardown_hypercalls (kvm); }
arch/arm64/kvm/nested.c +10 -5
@@ -56,6 +56,15 @@ int kvm_init_nested(struct kvm *kvm)return kvm->arch.nested_mmus ?0 : -ENOMEM ; } +void kvm_destroy_nested (struct kvm *kvm) +{ +for (int i =0 ; i < kvm->arch.nested_mmus_size; i+=S2_MMU_PER_VCPU ) +kvfree (kvm->arch.nested_mmus[i]); + + kvm->arch.nested_mmus_size =0 ; +kvfree (kvm->arch.nested_mmus); +} +static int init_nested_s2_mmu (struct kvm *kvm,struct kvm_s2_mmu *mmu) {/*
@@ -1322,16 +1331,12 @@ void kvm_nested_s2_flush(struct kvm *kvm)void kvm_arch_flush_shadow_all (struct kvm *kvm) { -for (int i = kvm->arch.nested_mmus_size -1 ; i >=0 ; i--) { +for (int i =0 ; i < kvm->arch.nested_mmus_size; i++) {struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];if (!WARN_ON (atomic_read (&mmu->refcnt)))kvm_free_stage2_pgd (mmu); - -if ((i %S2_MMU_PER_VCPU ) ==0 ) -kvfree (mmu); } - kvm->arch.nested_mmus_size =0 ;kvm_uninit_stage2_mmu (kvm); }
Sasha Levin
maintainerPATCH 1/2 KVM: arm64: nv: Fix life cycle of the nested_mmus array
From: Marc Zyngier <[email protected]>
[ Upstream commit 33346f8960c7bb6a3b4e273b5cfe25c5a8be349f ]
The nested_mmus array holds the shadow page tables that are used when a guest is running a nested context. These structures are allocated on VCPU_INIT for whole guest, which implies that they may have to be relocated as the array grows.
Should a VCPU_INIT occur whilst a vcpu is actively running an L2 and that the allocation requires relocation, that vcpu will still be running with a pointer to the previous structure, which will have been freed.
Fix this by turning the array of structures to an array of pointers, which is now allocated at VM creation, sized to the absolute maximum that KVM can handle.
In turn, each VCPU_INIT contributes S2_MMU_PER_VCPU to the pool. No reallocation is ever performed, and the life cycle of each object is much clearer:
- the nested_mmus array is allocated in kvm_init_nested(), and freed in kvm_arch_destroy_vm()
- s2_mmu structures are allocated in kvm_vcpu_init_nested(), and freed on kvm_arch_flush_shadow_all()
Finally, the freeing of vcpu->arch.vncr_array is made consistent rather than being done on some failure paths, but not others.
[ Backport to 7.2: omit vncr_tlb_count initialization because this tree
removed the counter in 87c2bbf189829 and does not have the subsequent VNCR TLB tracking reintroduction. Retain kvcalloc() for the per-vCPU MMU block, with the new fixed S2_MMU_PER_VCPU allocation size, because this call site has not undergone the upstream allocator conversion. Preserve the pointer-array lifetime changes required by e5843f4effaa2 ("KVM: arm64: nv: Delay freeing of shadow S2 structures until VM destruction"). No functions are added. ]
Stable-dep-of: e5843f4effaa ("KVM: arm64: nv: Delay freeing of shadow S2 structures until VM destruction")
--- arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/include/asm/kvm_nested.h | 2 +- arch/arm64/kvm/arm.c | 8 ++- arch/arm64/kvm/nested.c | 89 +++++++++++++---------------- 4 files changed, 49 insertions(+), 52 deletions(-)
arch/arm64/include/asm/kvm_host.h +1 -1
@@ -322,7 +322,7 @@ struct kvm_arch {* Stage 2 paging state for VMs with nested S2 using a virtual * VMID. */ -struct kvm_s2_mmu *nested_mmus; +struct kvm_s2_mmu **nested_mmus;size_t nested_mmus_size;int nested_mmus_next;
arch/arm64/include/asm/kvm_nested.h +1 -1
@@ -66,7 +66,7 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)extern bool forward_smc_trap (struct kvm_vcpu *vcpu);extern bool forward_debug_exception (struct kvm_vcpu *vcpu); -extern void kvm_init_nested (struct kvm *kvm); +extern int kvm_init_nested (struct kvm *kvm);extern int kvm_vcpu_init_nested (struct kvm_vcpu *vcpu);extern void kvm_init_nested_s2_mmu (struct kvm_s2_mmu *mmu);extern struct kvm_s2_mmu *lookup_s2_mmu (struct kvm_vcpu *vcpu);
arch/arm64/kvm/arm.c +6 -2
@@ -236,8 +236,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)mutex_unlock (&kvm->lock);#endif -kvm_init_nested (kvm); - ret =kvm_share_hyp (kvm, kvm +1 );if (ret)return ret;
@@ -252,6 +250,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)if (ret) goto err_free_cpumask; + ret =kvm_init_nested (kvm); +if (ret) + goto err_uninit_mmu; +if (is_protected_kvm_enabled ()) {/* * If any failures occur after this is successful, make sure to
@@ -280,6 +282,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) err_uninit_mmu:kvm_uninit_stage2_mmu (kvm); +kvfree (kvm->arch.nested_mmus); err_free_cpumask:free_cpumask_var (kvm->arch.supported_cpus); err_unshare_kvm:
@@ -337,6 +340,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)kvm_unshare_hyp (kvm, kvm +1 ); +kvfree (kvm->arch.nested_mmus);kvm_arm_teardown_hypercalls (kvm); }
arch/arm64/kvm/nested.c +41 -48
168 lines not on this page · raw message
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 KVM: arm64: nv: Delay freeing of shadow S2 structures until VM destruction
From: Marc Zyngier <[email protected]>
[ Upstream commit e5843f4effaa2ffac3e789ecd4456403564961d4 ]
We free the shadow S2 structures from kvm_arch_flush_shadow_all(), which is a Bad Idea(tm). Freeing the page tables is fair game (this is what this callback is for), but freeing the container that could still be referenced by another part of the system is not great.
Instead, grow separate destructors that gets called when we tear the VM down for good. From there, we can nuke both the individual MMUs as well as the global array that points to them, safe in the knowledge that the vcpus themselves have been destroyed already.
--- arch/arm64/include/asm/kvm_nested.h | 1 + arch/arm64/kvm/arm.c | 4 ++-- arch/arm64/kvm/nested.c | 15 ++++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-)
arch/arm64/include/asm/kvm_nested.h +1 -0
@@ -67,6 +67,7 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)extern bool forward_smc_trap (struct kvm_vcpu *vcpu);extern bool forward_debug_exception (struct kvm_vcpu *vcpu);extern int kvm_init_nested (struct kvm *kvm); +extern void kvm_destroy_nested (struct kvm *kvm);extern int kvm_vcpu_init_nested (struct kvm_vcpu *vcpu);extern void kvm_init_nested_s2_mmu (struct kvm_s2_mmu *mmu);extern struct kvm_s2_mmu *lookup_s2_mmu (struct kvm_vcpu *vcpu);
arch/arm64/kvm/arm.c +2 -2
@@ -282,7 +282,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) err_uninit_mmu:kvm_uninit_stage2_mmu (kvm); -kvfree (kvm->arch.nested_mmus); +kvm_destroy_nested (kvm); err_free_cpumask:free_cpumask_var (kvm->arch.supported_cpus); err_unshare_kvm:
@@ -340,7 +340,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)kvm_unshare_hyp (kvm, kvm +1 ); -kvfree (kvm->arch.nested_mmus); +kvm_destroy_nested (kvm);kvm_arm_teardown_hypercalls (kvm); }
arch/arm64/kvm/nested.c +10 -5
@@ -54,6 +54,15 @@ int kvm_init_nested(struct kvm *kvm)return kvm->arch.nested_mmus ?0 : -ENOMEM ; } +void kvm_destroy_nested (struct kvm *kvm) +{ +for (int i =0 ; i < kvm->arch.nested_mmus_size; i+=S2_MMU_PER_VCPU ) +kvfree (kvm->arch.nested_mmus[i]); + + kvm->arch.nested_mmus_size =0 ; +kvfree (kvm->arch.nested_mmus); +} +static int init_nested_s2_mmu (struct kvm *kvm,struct kvm_s2_mmu *mmu) {/*
@@ -1307,16 +1316,12 @@ void kvm_nested_s2_flush(struct kvm *kvm)void kvm_arch_flush_shadow_all (struct kvm *kvm) { -for (int i = kvm->arch.nested_mmus_size -1 ; i >=0 ; i--) { +for (int i =0 ; i < kvm->arch.nested_mmus_size; i++) {struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];if (!WARN_ON (atomic_read (&mmu->refcnt)))kvm_free_stage2_pgd (mmu); - -if ((i %S2_MMU_PER_VCPU ) ==0 ) -kvfree (mmu); } - kvm->arch.nested_mmus_size =0 ;kvm_uninit_stage2_mmu (kvm); }
Signature · 1 line
2.53.0