ANDROID: KVM: arm64: Turn llist of pinned pages into an rb-tree

Indexed by IPA, so we can efficiently lookup.

Bug: 357781595
Change-Id: I10ad6ad5a7a6aa34a0814ed334b20f4ae42ca830
Signed-off-by: Quentin Perret <qperret@google.com>
Signed-off-by: Keir Fraser <keirf@google.com>
This commit is contained in:
Quentin Perret
2022-07-06 10:56:24 +00:00
committed by Keir Fraser
parent ef53e1835d
commit dfe53de3e1
3 changed files with 36 additions and 11 deletions
+3 -2
View File
@@ -242,8 +242,9 @@ struct kvm_smccc_features {
};
struct kvm_pinned_page {
struct list_head link;
struct rb_node node;
struct page *page;
u64 ipa;
};
typedef unsigned int pkvm_handle_t;
@@ -251,7 +252,7 @@ typedef unsigned int pkvm_handle_t;
struct kvm_protected_vm {
pkvm_handle_t handle;
struct kvm_hyp_memcache teardown_mc;
struct list_head pinned_pages;
struct rb_root pinned_pages;
gpa_t pvmfw_load_addr;
bool enabled;
};
+26 -4
View File
@@ -343,6 +343,7 @@ void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_
static void pkvm_stage2_flush(struct kvm *kvm)
{
struct kvm_pinned_page *ppage;
struct rb_node *node;
/*
* Contrary to stage2_apply_range(), we don't need to check
@@ -350,7 +351,8 @@ static void pkvm_stage2_flush(struct kvm *kvm)
* from a vcpu thread, and the list is only ever freed on VM
* destroy (which only occurs when all vcpu are gone).
*/
list_for_each_entry(ppage, &kvm->arch.pkvm.pinned_pages, link) {
for (node = rb_first(&kvm->arch.pkvm.pinned_pages); node; node = rb_next(node)) {
ppage = rb_entry(node, struct kvm_pinned_page, node);
__clean_dcache_guest_page(page_address(ppage->page), PAGE_SIZE);
cond_resched_rwlock_write(&kvm->mmu_lock);
}
@@ -932,7 +934,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
int cpu, err;
struct kvm_pgtable *pgt;
INIT_LIST_HEAD(&kvm->arch.pkvm.pinned_pages);
kvm->arch.pkvm.pinned_pages = RB_ROOT;
mmu->arch = &kvm->arch;
/*
@@ -1459,6 +1461,26 @@ static int pkvm_host_map_guest(u64 pfn, u64 gfn)
return (ret == -EPERM) ? -EAGAIN : ret;
}
static int cmp_ppages(struct rb_node *node, const struct rb_node *parent)
{
struct kvm_pinned_page *a = container_of(node, struct kvm_pinned_page, node);
struct kvm_pinned_page *b = container_of(parent, struct kvm_pinned_page, node);
if (a->ipa < b->ipa)
return -1;
if (a->ipa > b->ipa)
return 1;
return 0;
}
static int insert_ppage(struct kvm *kvm, struct kvm_pinned_page *ppage)
{
if (rb_find_add(&ppage->node, &kvm->arch.pkvm.pinned_pages, cmp_ppages))
return -EEXIST;
return 0;
}
static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
struct kvm_memory_slot *memslot)
{
@@ -1524,8 +1546,8 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
}
ppage->page = page;
INIT_LIST_HEAD(&ppage->link);
list_add(&ppage->link, &kvm->arch.pkvm.pinned_pages);
ppage->ipa = fault_ipa;
WARN_ON(insert_ppage(kvm, ppage));
write_unlock(&kvm->mmu_lock);
return 0;
+7 -5
View File
@@ -148,9 +148,9 @@ static bool pkvm_teardown_vm(struct kvm *host_kvm)
static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm)
{
struct kvm_pinned_page *ppage, *tmp;
struct kvm_pinned_page *ppage;
struct mm_struct *mm = current->mm;
struct list_head *ppages;
struct rb_node *node;
unsigned long pages = 0;
if (!pkvm_teardown_vm(host_kvm))
@@ -158,14 +158,16 @@ static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm)
free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc);
ppages = &host_kvm->arch.pkvm.pinned_pages;
list_for_each_entry_safe(ppage, tmp, ppages, link) {
node = rb_first(&host_kvm->arch.pkvm.pinned_pages);
while (node) {
ppage = rb_entry(node, struct kvm_pinned_page, node);
WARN_ON(kvm_call_hyp_nvhe(__pkvm_host_reclaim_page,
page_to_pfn(ppage->page)));
cond_resched();
unpin_user_pages_dirty_lock(&ppage->page, 1, true);
list_del(&ppage->link);
node = rb_next(node);
rb_erase(&ppage->node, &host_kvm->arch.pkvm.pinned_pages);
kfree(ppage);
pages++;
}