]> xenbits.xensource.com Git - people/pauldu/linux.git/commitdiff
KVM: pfncache: check the need for invalidation under read lock first
authorPaul Durrant <pdurrant@amazon.com>
Mon, 4 Dec 2023 10:41:39 +0000 (10:41 +0000)
committerPaul Durrant <pdurrant@amazon.com>
Thu, 11 Jan 2024 09:43:36 +0000 (09:43 +0000)
Taking a write lock on a pfncache will be disruptive if the cache is
heavily used (which only requires a read lock). Hence, in the MMU notifier
callback, take read locks on caches to check for a match; only taking a
write lock to actually perform an invalidation (after a another check).

Signed-off-by: Paul Durrant <pdurrant@amazon.com>
Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
---
Cc: Sean Christopherson <seanjc@google.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
v10:
 - New in this version.

virt/kvm/pfncache.c

index ae822bff812fed7aee71ae881a4545df4c725ecf..70394d7c9a380545c8c86e42b8b499f9671cd6cb 100644 (file)
@@ -29,14 +29,30 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, unsigned long start,
 
        spin_lock(&kvm->gpc_lock);
        list_for_each_entry(gpc, &kvm->gpc_list, list) {
-               write_lock_irq(&gpc->lock);
+               read_lock_irq(&gpc->lock);
 
                /* Only a single page so no need to care about length */
                if (gpc->valid && !is_error_noslot_pfn(gpc->pfn) &&
                    gpc->uhva >= start && gpc->uhva < end) {
-                       gpc->valid = false;
+                       read_unlock_irq(&gpc->lock);
+
+                       /*
+                        * There is a small window here where the cache could
+                        * be modified, and invalidation would no longer be
+                        * necessary. Hence check again whether invalidation
+                        * is still necessary once the write lock has been
+                        * acquired.
+                        */
+
+                       write_lock_irq(&gpc->lock);
+                       if (gpc->valid && !is_error_noslot_pfn(gpc->pfn) &&
+                           gpc->uhva >= start && gpc->uhva < end)
+                               gpc->valid = false;
+                       write_unlock_irq(&gpc->lock);
+                       continue;
                }
-               write_unlock_irq(&gpc->lock);
+
+               read_unlock_irq(&gpc->lock);
        }
        spin_unlock(&kvm->gpc_lock);
 }