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:
committed by
Keir Fraser
parent
ef53e1835d
commit
dfe53de3e1
@@ -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
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user