Skip to content

Commit 0e89ca1

Browse files
rananta468oupton
authored andcommitted
KVM: arm64: Split kvm_pgtable_stage2_destroy()
Split kvm_pgtable_stage2_destroy() into two: - kvm_pgtable_stage2_destroy_range(), that performs the page-table walk and free the entries over a range of addresses. - kvm_pgtable_stage2_destroy_pgd(), that frees the PGD. This refactoring enables subsequent patches to free large page-tables in chunks, calling cond_resched() between each chunk, to yield the CPU as necessary. Existing callers of kvm_pgtable_stage2_destroy(), that probably cannot take advantage of this (such as nVMHE), will continue to function as is. Signed-off-by: Raghavendra Rao Ananta <[email protected]> Suggested-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent d19c541 commit 0e89ca1

File tree

5 files changed

+73
-9
lines changed

5 files changed

+73
-9
lines changed

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke
355355
return pteref;
356356
}
357357

358+
static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref)
359+
{
360+
return pteref;
361+
}
362+
358363
static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker)
359364
{
360365
/*
@@ -384,6 +389,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke
384389
return rcu_dereference_check(pteref, !(walker->flags & KVM_PGTABLE_WALK_SHARED));
385390
}
386391

392+
static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref)
393+
{
394+
return rcu_dereference_raw(pteref);
395+
}
396+
387397
static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker)
388398
{
389399
if (walker->flags & KVM_PGTABLE_WALK_SHARED)
@@ -551,6 +561,26 @@ static inline int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2
551561
*/
552562
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
553563

564+
/**
565+
* kvm_pgtable_stage2_destroy_range() - Destroy the unlinked range of addresses.
566+
* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*().
567+
* @addr: Intermediate physical address at which to place the mapping.
568+
* @size: Size of the mapping.
569+
*
570+
* The page-table is assumed to be unreachable by any hardware walkers prior
571+
* to freeing and therefore no TLB invalidation is performed.
572+
*/
573+
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
574+
u64 addr, u64 size);
575+
576+
/**
577+
* kvm_pgtable_stage2_destroy_pgd() - Destroy the PGD of guest stage-2 page-table.
578+
* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*().
579+
*
580+
* It is assumed that the rest of the page-table is freed before this operation.
581+
*/
582+
void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt);
583+
554584
/**
555585
* kvm_pgtable_stage2_free_unlinked() - Free an unlinked stage-2 paging structure.
556586
* @mm_ops: Memory management callbacks.

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ struct pkvm_mapping {
179179

180180
int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
181181
struct kvm_pgtable_mm_ops *mm_ops);
182-
void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
182+
void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
183+
u64 addr, u64 size);
184+
void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt);
183185
int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys,
184186
enum kvm_pgtable_prot prot, void *mc,
185187
enum kvm_pgtable_walk_flags flags);

arch/arm64/kvm/hyp/pgtable.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,21 +1551,38 @@ static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx,
15511551
return 0;
15521552
}
15531553

1554-
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
1554+
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
1555+
u64 addr, u64 size)
15551556
{
1556-
size_t pgd_sz;
15571557
struct kvm_pgtable_walker walker = {
15581558
.cb = stage2_free_walker,
15591559
.flags = KVM_PGTABLE_WALK_LEAF |
15601560
KVM_PGTABLE_WALK_TABLE_POST,
15611561
};
15621562

1563-
WARN_ON(kvm_pgtable_walk(pgt, 0, BIT(pgt->ia_bits), &walker));
1563+
WARN_ON(kvm_pgtable_walk(pgt, addr, size, &walker));
1564+
}
1565+
1566+
void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
1567+
{
1568+
size_t pgd_sz;
1569+
15641570
pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level) * PAGE_SIZE;
1565-
pgt->mm_ops->free_pages_exact(kvm_dereference_pteref(&walker, pgt->pgd), pgd_sz);
1571+
1572+
/*
1573+
* Since the pgtable is unlinked at this point, and not shared with
1574+
* other walkers, safely deference pgd with kvm_dereference_pteref_raw()
1575+
*/
1576+
pgt->mm_ops->free_pages_exact(kvm_dereference_pteref_raw(pgt->pgd), pgd_sz);
15661577
pgt->pgd = NULL;
15671578
}
15681579

1580+
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
1581+
{
1582+
kvm_pgtable_stage2_destroy_range(pgt, 0, BIT(pgt->ia_bits));
1583+
kvm_pgtable_stage2_destroy_pgd(pgt);
1584+
}
1585+
15691586
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level)
15701587
{
15711588
kvm_pteref_t ptep = (kvm_pteref_t)pgtable;

arch/arm64/kvm/mmu.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,14 @@ static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type)
904904
return 0;
905905
}
906906

907+
static void kvm_stage2_destroy(struct kvm_pgtable *pgt)
908+
{
909+
unsigned int ia_bits = VTCR_EL2_IPA(pgt->mmu->vtcr);
910+
911+
KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, 0, BIT(ia_bits));
912+
KVM_PGT_FN(kvm_pgtable_stage2_destroy_pgd)(pgt);
913+
}
914+
907915
/**
908916
* kvm_init_stage2_mmu - Initialise a S2 MMU structure
909917
* @kvm: The pointer to the KVM structure
@@ -980,7 +988,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
980988
return 0;
981989

982990
out_destroy_pgtable:
983-
KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt);
991+
kvm_stage2_destroy(pgt);
984992
out_free_pgtable:
985993
kfree(pgt);
986994
return err;
@@ -1077,7 +1085,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
10771085
write_unlock(&kvm->mmu_lock);
10781086

10791087
if (pgt) {
1080-
KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt);
1088+
kvm_stage2_destroy(pgt);
10811089
kfree(pgt);
10821090
}
10831091
}

arch/arm64/kvm/pkvm.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,16 @@ static int __pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 start, u64 e
316316
return 0;
317317
}
318318

319-
void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
319+
void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
320+
u64 addr, u64 size)
320321
{
321-
__pkvm_pgtable_stage2_unmap(pgt, 0, ~(0ULL));
322+
__pkvm_pgtable_stage2_unmap(pgt, addr, addr + size);
323+
}
324+
325+
void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
326+
{
327+
/* Expected to be called after all pKVM mappings have been released. */
328+
WARN_ON_ONCE(!RB_EMPTY_ROOT(&pgt->pkvm_mappings.rb_root));
322329
}
323330

324331
int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size,

0 commit comments

Comments
 (0)