Re: [PATCH v2 1/2] KVM: arm64: Resume stage-2 teardown where the walk stopped
From: Oliver Upton
Date: Wed Nov 04 2026 - 14:19:34 EST
Hi Fuad,
On Wed, Nov 04, 2026 at 12:44:50PM +0000, Fuad Tabba wrote:
> +u64 kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
> + u64 addr, u64 size)
Returning a signed value here would be a good idea so you can percolate
walk failures back up to the caller. Since that WARN_ON() below may as
well be a BUG_ON() in hyp code.
Otherwise, rest looks good.
Thanks,
Oliver
> {
> struct kvm_pgtable_walker walker = {
> .cb = stage2_free_walker,
> .flags = KVM_PGTABLE_WALK_LEAF |
> KVM_PGTABLE_WALK_TABLE_POST,
> };
> + struct kvm_pgtable_walk_data data = {
> + .walker = &walker,
> + .start = addr,
> + .addr = addr,
> + .end = addr + size,
> + };
>
> - WARN_ON(kvm_pgtable_walk(pgt, addr, size, &walker));
> + if (WARN_ON(_kvm_pgtable_walk(pgt, &data)))
> + return addr + size;
> +
> + return data.addr;
> }
>
> void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 1db10d8d6db73..4f1adadeffb8b 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1011,8 +1011,8 @@ static void stage2_destroy_range(struct kvm_pgtable *pgt, phys_addr_t addr,
>
> do {
> next = stage2_range_addr_end(addr, end);
> - KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, addr,
> - next - addr);
> + next = KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, addr, next - addr);
> + next = min(next, end);
> if (next != end)
> cond_resched();
> } while (addr = next, addr != end);
> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> index 016997288fd23..f21c3326dda68 100644
> --- a/arch/arm64/kvm/pkvm.c
> +++ b/arch/arm64/kvm/pkvm.c
> @@ -499,14 +499,14 @@ static int __pkvm_pgtable_stage2_unshare(struct kvm_pgtable *pgt, u64 start, u64
> return 0;
> }
>
> -void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
> - u64 addr, u64 size)
> +u64 pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
> + u64 addr, u64 size)
> {
> struct kvm *kvm = kvm_s2_mmu_to_kvm(pgt->mmu);
> pkvm_handle_t handle = kvm->arch.pkvm.handle;
>
> if (!handle)
> - return;
> + return addr + size;
>
> if (pkvm_hyp_vm_is_created(kvm) && !kvm->arch.pkvm.is_dying) {
> WARN_ON(kvm_call_hyp_nvhe(__pkvm_start_teardown_vm, handle));
> @@ -517,6 +517,8 @@ void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
> __pkvm_pgtable_stage2_reclaim(pgt, addr, addr + size);
> else
> __pkvm_pgtable_stage2_unshare(pgt, addr, addr + size);
> +
> + return addr + size;
> }
>
> void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
> --
> 2.47.3
>