|
@@ -50,3 +50,88 @@ track_free:
|
|
kvm_page_track_free_memslot(slot, NULL);
|
|
kvm_page_track_free_memslot(slot, NULL);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+static inline bool page_track_mode_is_valid(enum kvm_page_track_mode mode)
|
|
|
|
+{
|
|
|
|
+ if (mode < 0 || mode >= KVM_PAGE_TRACK_MAX)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void update_gfn_track(struct kvm_memory_slot *slot, gfn_t gfn,
|
|
|
|
+ enum kvm_page_track_mode mode, short count)
|
|
|
|
+{
|
|
|
|
+ int index, val;
|
|
|
|
+
|
|
|
|
+ index = gfn_to_index(gfn, slot->base_gfn, PT_PAGE_TABLE_LEVEL);
|
|
|
|
+
|
|
|
|
+ val = slot->arch.gfn_track[mode][index];
|
|
|
|
+
|
|
|
|
+ if (WARN_ON(val + count < 0 || val + count > USHRT_MAX))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ slot->arch.gfn_track[mode][index] += count;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * add guest page to the tracking pool so that corresponding access on that
|
|
|
|
+ * page will be intercepted.
|
|
|
|
+ *
|
|
|
|
+ * It should be called under the protection both of mmu-lock and kvm->srcu
|
|
|
|
+ * or kvm->slots_lock.
|
|
|
|
+ *
|
|
|
|
+ * @kvm: the guest instance we are interested in.
|
|
|
|
+ * @slot: the @gfn belongs to.
|
|
|
|
+ * @gfn: the guest page.
|
|
|
|
+ * @mode: tracking mode, currently only write track is supported.
|
|
|
|
+ */
|
|
|
|
+void kvm_slot_page_track_add_page(struct kvm *kvm,
|
|
|
|
+ struct kvm_memory_slot *slot, gfn_t gfn,
|
|
|
|
+ enum kvm_page_track_mode mode)
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+ if (WARN_ON(!page_track_mode_is_valid(mode)))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ update_gfn_track(slot, gfn, mode, 1);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * new track stops large page mapping for the
|
|
|
|
+ * tracked page.
|
|
|
|
+ */
|
|
|
|
+ kvm_mmu_gfn_disallow_lpage(slot, gfn);
|
|
|
|
+
|
|
|
|
+ if (mode == KVM_PAGE_TRACK_WRITE)
|
|
|
|
+ if (kvm_mmu_slot_gfn_write_protect(kvm, slot, gfn))
|
|
|
|
+ kvm_flush_remote_tlbs(kvm);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * remove the guest page from the tracking pool which stops the interception
|
|
|
|
+ * of corresponding access on that page. It is the opposed operation of
|
|
|
|
+ * kvm_slot_page_track_add_page().
|
|
|
|
+ *
|
|
|
|
+ * It should be called under the protection both of mmu-lock and kvm->srcu
|
|
|
|
+ * or kvm->slots_lock.
|
|
|
|
+ *
|
|
|
|
+ * @kvm: the guest instance we are interested in.
|
|
|
|
+ * @slot: the @gfn belongs to.
|
|
|
|
+ * @gfn: the guest page.
|
|
|
|
+ * @mode: tracking mode, currently only write track is supported.
|
|
|
|
+ */
|
|
|
|
+void kvm_slot_page_track_remove_page(struct kvm *kvm,
|
|
|
|
+ struct kvm_memory_slot *slot, gfn_t gfn,
|
|
|
|
+ enum kvm_page_track_mode mode)
|
|
|
|
+{
|
|
|
|
+ if (WARN_ON(!page_track_mode_is_valid(mode)))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ update_gfn_track(slot, gfn, mode, -1);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * allow large page mapping for the tracked page
|
|
|
|
+ * after the tracker is gone.
|
|
|
|
+ */
|
|
|
|
+ kvm_mmu_gfn_allow_lpage(slot, gfn);
|
|
|
|
+}
|