]> xenbits.xensource.com Git - people/pauldu/linux.git/commitdiff
consistently use khva for offset in existing cache
authorPaul Durrant <pdurrant@amazon.com>
Fri, 10 Nov 2023 10:32:21 +0000 (10:32 +0000)
committerPaul Durrant <pdurrant@amazon.com>
Mon, 20 Nov 2023 18:06:23 +0000 (18:06 +0000)
keep offset in uhva and use that when remapping

Signed-off-by: Paul Durrant <pdurrant@amazon.com>
virt/kvm/pfncache.c

index 0eeb034d06749ce1aeecd9d7ea4642bbab29e897..610ff72fb631eef3a906c753223bd94e57711ab8 100644 (file)
@@ -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 {
                /*