From: Paul Durrant Date: Fri, 10 Nov 2023 10:32:21 +0000 (+0000) Subject: consistently use khva for offset in existing cache X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=594e70842281af7a289d883cb702e1c7317d450b;p=people%2Fpauldu%2Flinux.git consistently use khva for offset in existing cache keep offset in uhva and use that when remapping Signed-off-by: Paul Durrant --- diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 0eeb034d0674..610ff72fb631 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -48,15 +48,15 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, unsigned long len) if (!gpc->active) return false; - if (offset_in_page(gpc->gpa) + len > PAGE_SIZE) - return false; - if (gpc->generation != slots->generation || kvm_is_error_hva(gpc->uhva)) return false; if (!gpc->valid) return false; + if (offset_in_page(gpc->khva) + len > PAGE_SIZE) + return false; + return true; } @@ -118,8 +118,9 @@ static inline bool mmu_notifier_retry_cache(struct kvm *kvm, unsigned long mmu_s static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) { - /* Note, the new page offset may be different than the old! */ - void *old_khva = gpc->khva - offset_in_page(gpc->khva); + unsigned long old_page_offset = offset_in_page(gpc->khva); + unsigned long page_offset = offset_in_page(gpc->uhva); + void *old_khva = gpc->khva - old_page_offset; kvm_pfn_t new_pfn = KVM_PFN_ERR_FAULT; void *new_khva = NULL; unsigned long mmu_seq; @@ -192,7 +193,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) gpc->valid = true; gpc->pfn = new_pfn; - gpc->khva = new_khva + offset_in_page(gpc->gpa); + gpc->khva = new_khva + page_offset; /* * Put the reference to the _new_ pfn. The pfn is now tracked by the @@ -215,8 +216,9 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, struct kvm_memslots *slots = kvm_memslots(gpc->kvm); unsigned long page_offset = offset_in_page(gpa); bool unmap_old = false; - unsigned long old_uhva; + unsigned long old_page_offset; kvm_pfn_t old_pfn; + bool hva_change = false; void *old_khva; int ret; @@ -242,8 +244,8 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, } old_pfn = gpc->pfn; - old_khva = gpc->khva - offset_in_page(gpc->khva); - old_uhva = gpc->uhva; + old_page_offset = offset_in_page(gpc->khva); + old_khva = gpc->khva - old_page_offset; /* If the userspace HVA is invalid, refresh that first */ if (gpc->gpa != gpa || gpc->generation != slots->generation || @@ -259,13 +261,24 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, ret = -EFAULT; goto out; } + + hva_change = true; + } else { + /* + * No need to do any re-mapping if the only thing that has + * changed is the page offset. Just subtract the old offset + * before the new one is added in. + */ + gpc->uhva -= old_page_offset; } + gpc->uhva += page_offset; + /* * If the userspace HVA changed or the PFN was already invalid, * drop the lock and do the HVA to PFN lookup again. */ - if (!gpc->valid || old_uhva != gpc->uhva) { + if (!gpc->valid || hva_change) { ret = hva_to_pfn_retry(gpc); } else { /*