Linux KVM/arm64 development list
 help / color / mirror / Atom feed
* [PATCH 0/3] KVM: arm64: pKVM is_created cleanup
@ 2026-06-18  9:01 Fuad Tabba
  2026-06-18  9:01 ` [PATCH 1/3] KVM: arm64: Drop the unused EL2-side is_created write Fuad Tabba
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Fuad Tabba @ 2026-06-18  9:01 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon
  Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
	Vincent Donnefort, Keir Fraser, Hyunwoo Kim, Fuad Tabba,
	linux-arm-kernel, kvmarm, linux-kernel

This small series tidies up the host-side kvm->arch.pkvm.is_created flag,
which tracks whether the hypervisor-side (EL2) VM has been instantiated.

It comes out of the ongoing pKVM (protected KVM) upstreaming work and runs
in parallel with it. The changes only remove dead or redundant code around
the flag, not any of the functional paths that work touches, so there is no
dependency in either direction and the two can be applied in any order.

is_created stays: the pKVM handle is reserved early (so host MMU-notifier
TLB invalidations have a valid handle before the first vCPU run), so a
non-zero handle no longer implies the EL2 VM exists. is_created is what
distinguishes "reserved" from "created", and the teardown path relies on it.
Only the cruft around it goes.

Cheers,
/fuad

Fuad Tabba (3):
  KVM: arm64: Drop the unused EL2-side is_created write
  KVM: arm64: Remove unreachable early checks in pkvm_init_host_vm()
  KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()

 arch/arm64/kvm/hyp/nvhe/pkvm.c |  1 -
 arch/arm64/kvm/pkvm.c          | 13 +++++--------
 2 files changed, 5 insertions(+), 9 deletions(-)

-- 
2.54.0.1189.g8c84645362-goog


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] KVM: arm64: Drop the unused EL2-side is_created write
  2026-06-18  9:01 [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Fuad Tabba
@ 2026-06-18  9:01 ` Fuad Tabba
  2026-06-18  9:01 ` [PATCH 2/3] KVM: arm64: Remove unreachable early checks in pkvm_init_host_vm() Fuad Tabba
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Fuad Tabba @ 2026-06-18  9:01 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon
  Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
	Vincent Donnefort, Keir Fraser, Hyunwoo Kim, Fuad Tabba,
	linux-arm-kernel, kvmarm, linux-kernel

init_pkvm_hyp_vm() sets is_created on the EL2-private VM struct, but the
hypervisor never reads it: pkvm_hyp_vm_is_created() and every other
consumer operate on the host's struct kvm, a distinct allocation from
the EL2-private copy. The field is write-only at EL2.

Remove the store; host-side is_created tracking is unaffected.

Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index eb1c10120f9f..30dd4b2afc26 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -433,7 +433,6 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
 	hyp_vm->host_kvm = host_kvm;
 	hyp_vm->kvm.created_vcpus = nr_vcpus;
 	hyp_vm->kvm.arch.pkvm.is_protected = READ_ONCE(host_kvm->arch.pkvm.is_protected);
-	hyp_vm->kvm.arch.pkvm.is_created = true;
 	hyp_vm->kvm.arch.flags = 0;
 	pkvm_init_features_from_host(hyp_vm, host_kvm);
 
-- 
2.54.0.1189.g8c84645362-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] KVM: arm64: Remove unreachable early checks in pkvm_init_host_vm()
  2026-06-18  9:01 [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Fuad Tabba
  2026-06-18  9:01 ` [PATCH 1/3] KVM: arm64: Drop the unused EL2-side is_created write Fuad Tabba
@ 2026-06-18  9:01 ` Fuad Tabba
  2026-06-18  9:01 ` [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created() Fuad Tabba
  2026-06-18 10:06 ` [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Keir Fraser
  3 siblings, 0 replies; 7+ messages in thread
From: Fuad Tabba @ 2026-06-18  9:01 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon
  Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
	Vincent Donnefort, Keir Fraser, Hyunwoo Kim, Fuad Tabba,
	linux-arm-kernel, kvmarm, linux-kernel

pkvm_init_host_vm() runs once from kvm_arch_init_vm(), while the VM is
still being allocated and is not yet reachable by another thread. Both
early checks therefore test impossible state: is_created is still false
(it is only set on first vCPU run) and the handle is still zero (this
function is what reserves it). Neither branch can be taken.

Remove them.

Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/pkvm.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index 053e4f733e4b..67b90a58fbea 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -230,13 +230,6 @@ int pkvm_init_host_vm(struct kvm *kvm, unsigned long type)
 	int ret;
 	bool protected = type & KVM_VM_TYPE_ARM_PROTECTED;
 
-	if (pkvm_hyp_vm_is_created(kvm))
-		return -EINVAL;
-
-	/* VM is already reserved, no need to proceed. */
-	if (kvm->arch.pkvm.handle)
-		return 0;
-
 	/* Reserve the VM in hyp and obtain a hyp handle for the VM. */
 	ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm);
 	if (ret < 0)
-- 
2.54.0.1189.g8c84645362-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()
  2026-06-18  9:01 [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Fuad Tabba
  2026-06-18  9:01 ` [PATCH 1/3] KVM: arm64: Drop the unused EL2-side is_created write Fuad Tabba
  2026-06-18  9:01 ` [PATCH 2/3] KVM: arm64: Remove unreachable early checks in pkvm_init_host_vm() Fuad Tabba
@ 2026-06-18  9:01 ` Fuad Tabba
  2026-06-18  9:22   ` sashiko-bot
  2026-06-18 10:06 ` [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Keir Fraser
  3 siblings, 1 reply; 7+ messages in thread
From: Fuad Tabba @ 2026-06-18  9:01 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon
  Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
	Vincent Donnefort, Keir Fraser, Hyunwoo Kim, Fuad Tabba,
	linux-arm-kernel, kvmarm, linux-kernel

is_created is written under config_lock. Every concurrent reader is
serialised against that write: pkvm_create_hyp_vm() under config_lock,
and the memslot path (kvm_arch_prepare_memory_region) via slots_lock,
which the creation writer also holds. The teardown-path accesses have no
concurrent writer. The read is therefore serialised, and the READ_ONCE()
is unnecessary.

Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/pkvm.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index 67b90a58fbea..008766273912 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -185,7 +185,11 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm)
 
 bool pkvm_hyp_vm_is_created(struct kvm *kvm)
 {
-	return READ_ONCE(kvm->arch.pkvm.is_created);
+	/*
+	 * Serialised by config_lock/slots_lock, or by VM lifecycle at
+	 * teardown, so a plain read suffices.
+	 */
+	return kvm->arch.pkvm.is_created;
 }
 
 int pkvm_create_hyp_vm(struct kvm *kvm)
-- 
2.54.0.1189.g8c84645362-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()
  2026-06-18  9:01 ` [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created() Fuad Tabba
@ 2026-06-18  9:22   ` sashiko-bot
  2026-06-18  9:40     ` Fuad Tabba
  0 siblings, 1 reply; 7+ messages in thread
From: sashiko-bot @ 2026-06-18  9:22 UTC (permalink / raw)
  To: Fuad Tabba; +Cc: Marc Zyngier, kvmarm, Oliver Upton

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Teardown sequence inversion in `kvm_arch_destroy_vm()` causes memory leak of protected guest pages.
--

commit 3c4352fb45fd315836f7f7aa2ad63af580a902d7
Author: Fuad Tabba <tabba@google.com>

KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()

This patch removes an unnecessary READ_ONCE() around the read of
kvm->arch.pkvm.is_created. The read is already serialised against concurrent
writers by either config_lock, slots_lock, or the teardown VM lifecycle.

> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> index 67b90a58fbea2..008766273912e 100644
> --- a/arch/arm64/kvm/pkvm.c
> +++ b/arch/arm64/kvm/pkvm.c
> @@ -185,7 +185,11 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm)
>  
>  bool pkvm_hyp_vm_is_created(struct kvm *kvm)
>  {
> -	return READ_ONCE(kvm->arch.pkvm.is_created);
> +	/*
> +	 * Serialised by config_lock/slots_lock, or by VM lifecycle at
> +	 * teardown, so a plain read suffices.
> +	 */

[Severity: High]
This isn't a bug introduced by this patch, but since the comment mentions the
teardown lifecycle, is there a teardown sequence inversion in
kvm_arch_destroy_vm() that leaks protected guest pages?

Looking at kvm_arch_destroy_vm() in arch/arm64/kvm/arm.c, it calls
pkvm_destroy_hyp_vm() before kvm_uninit_stage2_mmu().

Because kvm_uninit_stage2_mmu() hasn't run yet, __pkvm_start_teardown_vm()
is not invoked. This causes the __pkvm_finalize_teardown_vm hypercall inside
pkvm_destroy_hyp_vm() to be rejected by the hypervisor, and the host clears
the handle via __pkvm_destroy_hyp_vm():

arch/arm64/kvm/pkvm.c:__pkvm_destroy_hyp_vm() {
    ...
    kvm->arch.pkvm.handle = 0;
}

Subsequently, when kvm_uninit_stage2_mmu() does run, it eventually calls
pkvm_pgtable_stage2_destroy_range(), which returns early due to the cleared
handle:

arch/arm64/kvm/pkvm.c:pkvm_pgtable_stage2_destroy_range() {
    if (!handle)
        return;
    ...
}

Does this sequence skip page reclamation and unsharing, permanently leaking
all memory donated to the protected guest?

> +	return kvm->arch.pkvm.is_created;
>  }
>  
>  int pkvm_create_hyp_vm(struct kvm *kvm)

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260618090128.3913688-1-tabba@google.com?part=3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()
  2026-06-18  9:22   ` sashiko-bot
@ 2026-06-18  9:40     ` Fuad Tabba
  0 siblings, 0 replies; 7+ messages in thread
From: Fuad Tabba @ 2026-06-18  9:40 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Marc Zyngier, kvmarm, Oliver Upton

On Thu, 18 Jun 2026 at 10:22, <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Teardown sequence inversion in `kvm_arch_destroy_vm()` causes memory leak of protected guest pages.
> --
>
> commit 3c4352fb45fd315836f7f7aa2ad63af580a902d7
> Author: Fuad Tabba <tabba@google.com>
>
> KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()
>
> This patch removes an unnecessary READ_ONCE() around the read of
> kvm->arch.pkvm.is_created. The read is already serialised against concurrent
> writers by either config_lock, slots_lock, or the teardown VM lifecycle.
>
> > diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> > index 67b90a58fbea2..008766273912e 100644
> > --- a/arch/arm64/kvm/pkvm.c
> > +++ b/arch/arm64/kvm/pkvm.c
> > @@ -185,7 +185,11 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm)
> >
> >  bool pkvm_hyp_vm_is_created(struct kvm *kvm)
> >  {
> > -     return READ_ONCE(kvm->arch.pkvm.is_created);
> > +     /*
> > +      * Serialised by config_lock/slots_lock, or by VM lifecycle at
> > +      * teardown, so a plain read suffices.
> > +      */
>
> [Severity: High]
> This isn't a bug introduced by this patch, but since the comment mentions the
> teardown lifecycle, is there a teardown sequence inversion in
> kvm_arch_destroy_vm() that leaks protected guest pages?
>
> Looking at kvm_arch_destroy_vm() in arch/arm64/kvm/arm.c, it calls
> pkvm_destroy_hyp_vm() before kvm_uninit_stage2_mmu().
>
> Because kvm_uninit_stage2_mmu() hasn't run yet, __pkvm_start_teardown_vm()
> is not invoked. This causes the __pkvm_finalize_teardown_vm hypercall inside
> pkvm_destroy_hyp_vm() to be rejected by the hypervisor, and the host clears
> the handle via __pkvm_destroy_hyp_vm():
>
> arch/arm64/kvm/pkvm.c:__pkvm_destroy_hyp_vm() {
>     ...
>     kvm->arch.pkvm.handle = 0;
> }
>
> Subsequently, when kvm_uninit_stage2_mmu() does run, it eventually calls
> pkvm_pgtable_stage2_destroy_range(), which returns early due to the cleared
> handle:
>
> arch/arm64/kvm/pkvm.c:pkvm_pgtable_stage2_destroy_range() {
>     if (!handle)
>         return;
>     ...
> }
>
> Does this sequence skip page reclamation and unsharing, permanently leaking
> all memory donated to the protected guest?

Not a leak. The reclaim runs before kvm_arch_destroy_vm(), not after it.

kvm_destroy_vm() unregisters the mmu-notifier before calling
kvm_arch_destroy_vm(). That release path (kvm_flush_shadow_all ->
kvm_arch_flush_shadow_all(), nested.c) calls kvm_uninit_stage2_mmu()
-> pkvm_pgtable_stage2_destroy_range() while the handle is still
valid, so __pkvm_start_teardown_vm() sets is_dying and the guest pages
are reclaimed there.

By the time kvm_arch_destroy_vm() runs pkvm_destroy_hyp_vm(),
__pkvm_finalize_teardown_vm() therefore succeeds (is_dying already
set, no WARN), and the kvm_uninit_stage2_mmu() that follows is a
second pass that returns early on the now-cleared handle. A pVM
teardown is WARN-free in practice, which wouldn't hold if finalize
were being rejected as described.

Cheers,
/fuad

>
> > +     return kvm->arch.pkvm.is_created;
> >  }
> >
> >  int pkvm_create_hyp_vm(struct kvm *kvm)
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260618090128.3913688-1-tabba@google.com?part=3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: pKVM is_created cleanup
  2026-06-18  9:01 [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Fuad Tabba
                   ` (2 preceding siblings ...)
  2026-06-18  9:01 ` [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created() Fuad Tabba
@ 2026-06-18 10:06 ` Keir Fraser
  3 siblings, 0 replies; 7+ messages in thread
From: Keir Fraser @ 2026-06-18 10:06 UTC (permalink / raw)
  To: Fuad Tabba
  Cc: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon,
	Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
	Vincent Donnefort, Hyunwoo Kim, linux-arm-kernel, kvmarm,
	linux-kernel

On Thu, Jun 18, 2026 at 10:01:25AM +0100, Fuad Tabba wrote:
> This small series tidies up the host-side kvm->arch.pkvm.is_created flag,
> which tracks whether the hypervisor-side (EL2) VM has been instantiated.
> 
> It comes out of the ongoing pKVM (protected KVM) upstreaming work and runs
> in parallel with it. The changes only remove dead or redundant code around
> the flag, not any of the functional paths that work touches, so there is no
> dependency in either direction and the two can be applied in any order.
> 
> is_created stays: the pKVM handle is reserved early (so host MMU-notifier
> TLB invalidations have a valid handle before the first vCPU run), so a
> non-zero handle no longer implies the EL2 VM exists. is_created is what
> distinguishes "reserved" from "created", and the teardown path relies on it.
> Only the cruft around it goes.

For the whole series: Reviewed-by: Keir Fraser <keirf@google.com>

> Cheers,
> /fuad
> 
> Fuad Tabba (3):
>   KVM: arm64: Drop the unused EL2-side is_created write
>   KVM: arm64: Remove unreachable early checks in pkvm_init_host_vm()
>   KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created()
> 
>  arch/arm64/kvm/hyp/nvhe/pkvm.c |  1 -
>  arch/arm64/kvm/pkvm.c          | 13 +++++--------
>  2 files changed, 5 insertions(+), 9 deletions(-)
> 
> -- 
> 2.54.0.1189.g8c84645362-goog
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-06-18 10:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18  9:01 [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Fuad Tabba
2026-06-18  9:01 ` [PATCH 1/3] KVM: arm64: Drop the unused EL2-side is_created write Fuad Tabba
2026-06-18  9:01 ` [PATCH 2/3] KVM: arm64: Remove unreachable early checks in pkvm_init_host_vm() Fuad Tabba
2026-06-18  9:01 ` [PATCH 3/3] KVM: arm64: Drop redundant READ_ONCE() in pkvm_hyp_vm_is_created() Fuad Tabba
2026-06-18  9:22   ` sashiko-bot
2026-06-18  9:40     ` Fuad Tabba
2026-06-18 10:06 ` [PATCH 0/3] KVM: arm64: pKVM is_created cleanup Keir Fraser

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox