Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[sfrench/cifs-2.6.git] / include / linux / kvm_host.h
index 178fe4b69af2776527032acde6a47d92bf98250e..48f31dcd318a08cd75bddeed9de265501c837c7b 100644 (file)
@@ -2063,6 +2063,32 @@ static inline int mmu_invalidate_retry_gfn(struct kvm *kvm,
                return 1;
        return 0;
 }
+
+/*
+ * This lockless version of the range-based retry check *must* be paired with a
+ * call to the locked version after acquiring mmu_lock, i.e. this is safe to
+ * use only as a pre-check to avoid contending mmu_lock.  This version *will*
+ * get false negatives and false positives.
+ */
+static inline bool mmu_invalidate_retry_gfn_unsafe(struct kvm *kvm,
+                                                  unsigned long mmu_seq,
+                                                  gfn_t gfn)
+{
+       /*
+        * Use READ_ONCE() to ensure the in-progress flag and sequence counter
+        * are always read from memory, e.g. so that checking for retry in a
+        * loop won't result in an infinite retry loop.  Don't force loads for
+        * start+end, as the key to avoiding infinite retry loops is observing
+        * the 1=>0 transition of in-progress, i.e. getting false negatives
+        * due to stale start+end values is acceptable.
+        */
+       if (unlikely(READ_ONCE(kvm->mmu_invalidate_in_progress)) &&
+           gfn >= kvm->mmu_invalidate_range_start &&
+           gfn < kvm->mmu_invalidate_range_end)
+               return true;
+
+       return READ_ONCE(kvm->mmu_invalidate_seq) != mmu_seq;
+}
 #endif
 
 #ifdef CONFIG_HAVE_KVM_IRQ_ROUTING