]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: Propagate vcpu explicitly to mark_page_dirty_in_slot()
authorDavid Woodhouse <dwmw@amazon.co.uk>
Tue, 16 Nov 2021 21:56:51 +0000 (21:56 +0000)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Wed, 17 Nov 2021 17:15:44 +0000 (17:15 +0000)
The kvm_dirty_ring_get() function uses kvm_get_running_vcpu() to work out
which dirty ring to use, but there are some use cases where that doesn't
work.

There's one in setting the Xen shared info page, introduced in commit
629b5348841a ("KVM: x86/xen: update wallclock region") and reported by
"butt3rflyh4ck" <butterflyhuangxx@gmail.com> in
https://lore.kernel.org/kvm/CAFcO6XOmoS7EacN_n6v4Txk7xL7iqRa2gABg3F7E3Naf5uG94g@mail.gmail.com/

There's also about to be another one when the newly-reintroduced
gfn_to_pfn_cache needs to mark a page as dirty from the MMU notifier
which invalidates the mapping. In that case, we will *know* the vcpu
that can be 'blamed' for dirtying the page, and we just need to be
able to pass it in as an explicit argument when doing so.

This patch preemptively resolves the second issue, and paves the way
for resolving the first. A complete fix for the first issue will need
us to switch the Xen shinfo to be owned by a particular vCPU, which
will happen in a separate patch.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/arm64/kvm/mmu.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/spte.c
arch/x86/kvm/mmu/tdp_mmu.c
arch/x86/kvm/x86.c
include/linux/kvm_dirty_ring.h
include/linux/kvm_host.h
virt/kvm/dirty_ring.c
virt/kvm/kvm_main.c

index 326cdfec74a15df906d437773b40ea7a1ae7342d..d8411ce4db4b14487f3d46043470a36eb57cca26 100644 (file)
@@ -1143,7 +1143,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        /* Mark the page dirty only if the fault is handled successfully */
        if (writable && !ret) {
                kvm_set_pfn_dirty(pfn);
-               mark_page_dirty_in_slot(kvm, memslot, gfn);
+               mark_page_dirty_in_slot(kvm, vcpu, memslot, gfn);
        }
 
 out_unlock:
index 3be9beea838d134a077a67e05f12a1c9aaa7c2ef..cedeab55b0d8518c09b08c5c917e20afacb3cb9a 100644 (file)
@@ -3090,7 +3090,7 @@ fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
                return false;
 
        if (is_writable_pte(new_spte) && !is_writable_pte(old_spte))
-               mark_page_dirty_in_slot(vcpu->kvm, fault->slot, fault->gfn);
+               mark_page_dirty_in_slot(vcpu->kvm, vcpu, fault->slot, fault->gfn);
 
        return true;
 }
index 0c76c45fdb6867f039c74c9fbc29d661a5af2b00..0598515f3ae2e8b3095fba5d4e4cf0d4eea7e33f 100644 (file)
@@ -184,7 +184,7 @@ out:
        if ((spte & PT_WRITABLE_MASK) && kvm_slot_dirty_track_enabled(slot)) {
                /* Enforced by kvm_mmu_hugepage_adjust. */
                WARN_ON(level > PG_LEVEL_4K);
-               mark_page_dirty_in_slot(vcpu->kvm, slot, gfn);
+               mark_page_dirty_in_slot(vcpu->kvm, vcpu, slot, gfn);
        }
 
        *new_spte = spte;
index a54c3491af42c9fba8a894619ee7bd5c7f3f4628..c5669c9918a4256dd2b1eb7f5387323cdd5e96bc 100644 (file)
@@ -247,7 +247,7 @@ static void handle_changed_spte_dirty_log(struct kvm *kvm, int as_id, gfn_t gfn,
        if ((!is_writable_pte(old_spte) || pfn_changed) &&
            is_writable_pte(new_spte)) {
                slot = __gfn_to_memslot(__kvm_memslots(kvm, as_id), gfn);
-               mark_page_dirty_in_slot(kvm, slot, gfn);
+               mark_page_dirty_in_slot(kvm, NULL, slot, gfn);
        }
 }
 
index 5a403d92833f51e4f77d6fd67b38fd85efddb698..5af88f9e7fd14b943fbf88755a1405fdec15b802 100644 (file)
@@ -3353,7 +3353,7 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
  out:
        user_access_end();
  dirty:
-       mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa));
+       mark_page_dirty_in_slot(vcpu->kvm, vcpu, ghc->memslot, gpa_to_gfn(ghc->gpa));
 }
 
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
@@ -4420,7 +4420,7 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
        if (!copy_to_user_nofault(&st->preempted, &preempted, sizeof(preempted)))
                vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
 
-       mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa));
+       mark_page_dirty_in_slot(vcpu->kvm, vcpu, ghc->memslot, gpa_to_gfn(ghc->gpa));
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
index 4da8d4a4140bd0d3a13198a682a53e16a4f6a179..f3be974f9c5aaedd984c0499cce13dd5555eee93 100644 (file)
@@ -43,7 +43,8 @@ static inline int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring,
        return 0;
 }
 
-static inline struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm)
+static inline struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm,
+                                                       struct kvm_vcpu *vcpu)
 {
        return NULL;
 }
@@ -78,7 +79,8 @@ static inline bool kvm_dirty_ring_soft_full(struct kvm_dirty_ring *ring)
 
 u32 kvm_dirty_ring_get_rsvd_entries(void);
 int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring, int index, u32 size);
-struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm);
+struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm,
+                                         struct kvm_vcpu *vcpu);
 
 /*
  * called with kvm->slots_lock held, returns the number of
index c310648cc8f1abd8581f245871920b4e08a960f9..1628c32e4464d05ee1431bbb057d52ca5e81689b 100644 (file)
@@ -942,7 +942,8 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
 bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
 bool kvm_vcpu_is_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 unsigned long kvm_host_page_size(struct kvm_vcpu *vcpu, gfn_t gfn);
-void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot, gfn_t gfn);
+void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_vcpu *vcpu,
+                            struct kvm_memory_slot *memslot, gfn_t gfn);
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
 
 struct kvm_memslots *kvm_vcpu_memslots(struct kvm_vcpu *vcpu);
index 88f4683198ea757c1ce43781a08b5b59fac345cf..61c94fc4d7f0f7ba4026f94711ee70aa788177d2 100644 (file)
@@ -36,12 +36,16 @@ static bool kvm_dirty_ring_full(struct kvm_dirty_ring *ring)
        return kvm_dirty_ring_used(ring) >= ring->size;
 }
 
-struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm)
+struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm, struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
+       struct kvm_vcpu *running_vcpu = kvm_get_running_vcpu();
 
+       WARN_ON_ONCE(vcpu && vcpu != running_vcpu);
        WARN_ON_ONCE(vcpu->kvm != kvm);
 
+       if (!vcpu)
+               vcpu = running_vcpu;
+
        return &vcpu->dirty_ring;
 }
 
index 356d636e037dec1342f2aae7bcd8672f115e6524..7137995cab41a7d90d1b1f642366a15849e0347e 100644 (file)
@@ -2781,7 +2781,7 @@ int kvm_vcpu_read_guest_atomic(struct kvm_vcpu *vcpu, gpa_t gpa,
 }
 EXPORT_SYMBOL_GPL(kvm_vcpu_read_guest_atomic);
 
-static int __kvm_write_guest_page(struct kvm *kvm,
+static int __kvm_write_guest_page(struct kvm *kvm, struct kvm_vcpu *vcpu,
                                  struct kvm_memory_slot *memslot, gfn_t gfn,
                                  const void *data, int offset, int len)
 {
@@ -2794,7 +2794,7 @@ static int __kvm_write_guest_page(struct kvm *kvm,
        r = __copy_to_user((void __user *)addr + offset, data, len);
        if (r)
                return -EFAULT;
-       mark_page_dirty_in_slot(kvm, memslot, gfn);
+       mark_page_dirty_in_slot(kvm, vcpu, memslot, gfn);
        return 0;
 }
 
@@ -2803,7 +2803,7 @@ int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn,
 {
        struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
 
-       return __kvm_write_guest_page(kvm, slot, gfn, data, offset, len);
+       return __kvm_write_guest_page(kvm, NULL, slot, gfn, data, offset, len);
 }
 EXPORT_SYMBOL_GPL(kvm_write_guest_page);
 
@@ -2812,7 +2812,7 @@ int kvm_vcpu_write_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn,
 {
        struct kvm_memory_slot *slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
 
-       return __kvm_write_guest_page(vcpu->kvm, slot, gfn, data, offset, len);
+       return __kvm_write_guest_page(vcpu->kvm, vcpu, slot, gfn, data, offset, len);
 }
 EXPORT_SYMBOL_GPL(kvm_vcpu_write_guest_page);
 
@@ -2931,7 +2931,7 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
        r = __copy_to_user((void __user *)ghc->hva + offset, data, len);
        if (r)
                return -EFAULT;
-       mark_page_dirty_in_slot(kvm, ghc->memslot, gpa >> PAGE_SHIFT);
+       mark_page_dirty_in_slot(kvm, NULL, ghc->memslot, gpa >> PAGE_SHIFT);
 
        return 0;
 }
@@ -3000,7 +3000,7 @@ int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len)
 }
 EXPORT_SYMBOL_GPL(kvm_clear_guest);
 
-void mark_page_dirty_in_slot(struct kvm *kvm,
+void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_vcpu *vcpu,
                             struct kvm_memory_slot *memslot,
                             gfn_t gfn)
 {
@@ -3009,7 +3009,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm,
                u32 slot = (memslot->as_id << 16) | memslot->id;
 
                if (kvm->dirty_ring_size)
-                       kvm_dirty_ring_push(kvm_dirty_ring_get(kvm),
+                       kvm_dirty_ring_push(kvm_dirty_ring_get(kvm, vcpu),
                                            slot, rel_gfn);
                else
                        set_bit_le(rel_gfn, memslot->dirty_bitmap);
@@ -3022,7 +3022,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
        struct kvm_memory_slot *memslot;
 
        memslot = gfn_to_memslot(kvm, gfn);
-       mark_page_dirty_in_slot(kvm, memslot, gfn);
+       mark_page_dirty_in_slot(kvm, NULL, memslot, gfn);
 }
 EXPORT_SYMBOL_GPL(mark_page_dirty);
 
@@ -3031,7 +3031,7 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn)
        struct kvm_memory_slot *memslot;
 
        memslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
-       mark_page_dirty_in_slot(vcpu->kvm, memslot, gfn);
+       mark_page_dirty_in_slot(vcpu->kvm, vcpu, memslot, gfn);
 }
 EXPORT_SYMBOL_GPL(kvm_vcpu_mark_page_dirty);