]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: Replace "async" pointer in gfn=>pfn with "no_wait" and error code
authorDavid Stevens <stevensd@chromium.org>
Thu, 10 Oct 2024 18:23:18 +0000 (11:23 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 25 Oct 2024 16:57:58 +0000 (12:57 -0400)
Add a pfn error code to communicate that hva_to_pfn() failed because I/O
was needed and disallowed, and convert @async to a constant @no_wait
boolean.  This will allow eliminating the @no_wait param by having callers
pass in FOLL_NOWAIT along with other FOLL_* flags.

Tested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: David Stevens <stevensd@chromium.org>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Tested-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-ID: <20241010182427.1434605-17-seanjc@google.com>

arch/x86/kvm/mmu/mmu.c
include/linux/kvm_host.h
virt/kvm/kvm_main.c
virt/kvm/kvm_mm.h
virt/kvm/pfncache.c

index e5e0bf7593e726bdb369d5e7875354cf47c39ef4..cae81209f9ed160d99dddb18a9d216e54287a73a 100644 (file)
@@ -4381,17 +4381,21 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu,
 
 static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 {
-       bool async;
-
        if (fault->is_private)
                return kvm_faultin_pfn_private(vcpu, fault);
 
-       async = false;
-       fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, false, &async,
+       fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, false, true,
                                          fault->write, &fault->map_writable,
                                          &fault->hva);
-       if (!async)
-               return RET_PF_CONTINUE; /* *pfn has correct page already */
+
+       /*
+        * If resolving the page failed because I/O is needed to fault-in the
+        * page, then either set up an asynchronous #PF to do the I/O, or if
+        * doing an async #PF isn't possible, retry with I/O allowed.  All
+        * other failures are terminal, i.e. retrying won't help.
+        */
+       if (fault->pfn != KVM_PFN_ERR_NEEDS_IO)
+               return RET_PF_CONTINUE;
 
        if (!fault->prefetch && kvm_can_do_async_pf(vcpu)) {
                trace_kvm_try_async_get_page(fault->addr, fault->gfn);
@@ -4409,7 +4413,7 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
         * to wait for IO.  Note, gup always bails if it is unable to quickly
         * get a page and a fatal signal, i.e. SIGKILL, is pending.
         */
-       fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, true, NULL,
+       fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, true, true,
                                          fault->write, &fault->map_writable,
                                          &fault->hva);
        return RET_PF_CONTINUE;
index 32e23e05a8c330c6caa7a64bf5b097a904b26ed8..dc15a9a64408491e8c7584e885760ca3f07ea61a 100644 (file)
@@ -97,6 +97,7 @@
 #define KVM_PFN_ERR_HWPOISON   (KVM_PFN_ERR_MASK + 1)
 #define KVM_PFN_ERR_RO_FAULT   (KVM_PFN_ERR_MASK + 2)
 #define KVM_PFN_ERR_SIGPENDING (KVM_PFN_ERR_MASK + 3)
+#define KVM_PFN_ERR_NEEDS_IO   (KVM_PFN_ERR_MASK + 4)
 
 /*
  * error pfns indicate that the gfn is in slot but faild to
@@ -1233,7 +1234,7 @@ kvm_pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
                      bool *writable);
 kvm_pfn_t gfn_to_pfn_memslot(const struct kvm_memory_slot *slot, gfn_t gfn);
 kvm_pfn_t __gfn_to_pfn_memslot(const struct kvm_memory_slot *slot, gfn_t gfn,
-                              bool interruptible, bool *async,
+                              bool interruptible, bool no_wait,
                               bool write_fault, bool *writable, hva_t *hva);
 
 void kvm_release_pfn_clean(kvm_pfn_t pfn);
index f5b7fd6533410714862cd108250da33b65ebb3fa..d7a72278c0338f7bb0a186066d86f474df862347 100644 (file)
@@ -2778,7 +2778,7 @@ static bool hva_to_pfn_fast(unsigned long addr, bool write_fault,
  * The slow path to get the pfn of the specified host virtual address,
  * 1 indicates success, -errno is returned if error is detected.
  */
-static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
+static int hva_to_pfn_slow(unsigned long addr, bool no_wait, bool write_fault,
                           bool interruptible, bool *writable, kvm_pfn_t *pfn)
 {
        /*
@@ -2801,7 +2801,7 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
 
        if (write_fault)
                flags |= FOLL_WRITE;
-       if (async)
+       if (no_wait)
                flags |= FOLL_NOWAIT;
        if (interruptible)
                flags |= FOLL_INTERRUPTIBLE;
@@ -2912,8 +2912,8 @@ out:
  * Pin guest page in memory and return its pfn.
  * @addr: host virtual address which maps memory to the guest
  * @interruptible: whether the process can be interrupted by non-fatal signals
- * @async: whether this function need to wait IO complete if the
- *         host page is not in the memory
+ * @no_wait: whether or not this function need to wait IO complete if the
+ *          host page is not in the memory
  * @write_fault: whether we should get a writable host page
  * @writable: whether it allows to map a writable host page for !@write_fault
  *
@@ -2922,7 +2922,7 @@ out:
  * 2): @write_fault = false && @writable, @writable will tell the caller
  *     whether the mapping is writable.
  */
-kvm_pfn_t hva_to_pfn(unsigned long addr, bool interruptible, bool *async,
+kvm_pfn_t hva_to_pfn(unsigned long addr, bool interruptible, bool no_wait,
                     bool write_fault, bool *writable)
 {
        struct vm_area_struct *vma;
@@ -2934,7 +2934,7 @@ kvm_pfn_t hva_to_pfn(unsigned long addr, bool interruptible, bool *async,
        if (hva_to_pfn_fast(addr, write_fault, writable, &pfn))
                return pfn;
 
-       npages = hva_to_pfn_slow(addr, async, write_fault, interruptible,
+       npages = hva_to_pfn_slow(addr, no_wait, write_fault, interruptible,
                                 writable, &pfn);
        if (npages == 1)
                return pfn;
@@ -2956,16 +2956,17 @@ retry:
                if (r < 0)
                        pfn = KVM_PFN_ERR_FAULT;
        } else {
-               if (async && vma_is_valid(vma, write_fault))
-                       *async = true;
-               pfn = KVM_PFN_ERR_FAULT;
+               if (no_wait && vma_is_valid(vma, write_fault))
+                       pfn = KVM_PFN_ERR_NEEDS_IO;
+               else
+                       pfn = KVM_PFN_ERR_FAULT;
        }
        mmap_read_unlock(current->mm);
        return pfn;
 }
 
 kvm_pfn_t __gfn_to_pfn_memslot(const struct kvm_memory_slot *slot, gfn_t gfn,
-                              bool interruptible, bool *async,
+                              bool interruptible, bool no_wait,
                               bool write_fault, bool *writable, hva_t *hva)
 {
        unsigned long addr = __gfn_to_hva_many(slot, gfn, NULL, write_fault);
@@ -2987,21 +2988,21 @@ kvm_pfn_t __gfn_to_pfn_memslot(const struct kvm_memory_slot *slot, gfn_t gfn,
                writable = NULL;
        }
 
-       return hva_to_pfn(addr, interruptible, async, write_fault, writable);
+       return hva_to_pfn(addr, interruptible, no_wait, write_fault, writable);
 }
 EXPORT_SYMBOL_GPL(__gfn_to_pfn_memslot);
 
 kvm_pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
                      bool *writable)
 {
-       return __gfn_to_pfn_memslot(gfn_to_memslot(kvm, gfn), gfn, false, NULL,
+       return __gfn_to_pfn_memslot(gfn_to_memslot(kvm, gfn), gfn, false, false,
                                    write_fault, writable, NULL);
 }
 EXPORT_SYMBOL_GPL(gfn_to_pfn_prot);
 
 kvm_pfn_t gfn_to_pfn_memslot(const struct kvm_memory_slot *slot, gfn_t gfn)
 {
-       return __gfn_to_pfn_memslot(slot, gfn, false, NULL, true, NULL, NULL);
+       return __gfn_to_pfn_memslot(slot, gfn, false, false, true, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(gfn_to_pfn_memslot);
 
index a3fa86f60d6c396eb09bb0b57dd4295e71e82541..51f3fee4ca3fe6cc9997e2c4ae48c64aac2048e1 100644 (file)
@@ -20,7 +20,7 @@
 #define KVM_MMU_UNLOCK(kvm)            spin_unlock(&(kvm)->mmu_lock)
 #endif /* KVM_HAVE_MMU_RWLOCK */
 
-kvm_pfn_t hva_to_pfn(unsigned long addr, bool interruptible, bool *async,
+kvm_pfn_t hva_to_pfn(unsigned long addr, bool interruptible, bool no_wait,
                     bool write_fault, bool *writable);
 
 #ifdef CONFIG_HAVE_KVM_PFNCACHE
index 58c706a610e5b405bb0db5b06d947f6c111f655a..32dc61f48c811004487b095bf04cd86c33b1391c 100644 (file)
@@ -197,8 +197,8 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc)
                        cond_resched();
                }
 
-               /* We always request a writeable mapping */
-               new_pfn = hva_to_pfn(gpc->uhva, false, NULL, true, NULL);
+               /* We always request a writable mapping */
+               new_pfn = hva_to_pfn(gpc->uhva, false, false, true, NULL);
                if (is_error_noslot_pfn(new_pfn))
                        goto out_error;