aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Guangrong <guangrong.xiao@linux.intel.com>2016-02-24 04:51:10 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2016-03-03 08:36:21 -0500
commitf29d4d7810d7fd61442371cd68957e1d37ed79bb (patch)
tree2db4d5b891ce6fcab4e9eb630cbf684b593d3105
parent21ebbedaddf25a35a70fedc001ba7e5f5b9129bc (diff)
KVM: page track: introduce kvm_slot_page_track_{add,remove}_page
These two functions are the user APIs: - kvm_slot_page_track_add_page(): add the page to the tracking pool after that later specified access on that page will be tracked - kvm_slot_page_track_remove_page(): remove the page from the tracking pool, the specified access on the page is not tracked after the last user is gone Both of these are called under the protection both of mmu-lock and kvm->srcu or kvm->slots_lock Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_page_track.h7
-rw-r--r--arch/x86/kvm/page_track.c85
2 files changed, 92 insertions, 0 deletions
diff --git a/arch/x86/include/asm/kvm_page_track.h b/arch/x86/include/asm/kvm_page_track.h
index 5520040682d1..e363e3040ba4 100644
--- a/arch/x86/include/asm/kvm_page_track.h
+++ b/arch/x86/include/asm/kvm_page_track.h
@@ -10,4 +10,11 @@ void kvm_page_track_free_memslot(struct kvm_memory_slot *free,
10 struct kvm_memory_slot *dont); 10 struct kvm_memory_slot *dont);
11int kvm_page_track_create_memslot(struct kvm_memory_slot *slot, 11int kvm_page_track_create_memslot(struct kvm_memory_slot *slot,
12 unsigned long npages); 12 unsigned long npages);
13
14void kvm_slot_page_track_add_page(struct kvm *kvm,
15 struct kvm_memory_slot *slot, gfn_t gfn,
16 enum kvm_page_track_mode mode);
17void kvm_slot_page_track_remove_page(struct kvm *kvm,
18 struct kvm_memory_slot *slot, gfn_t gfn,
19 enum kvm_page_track_mode mode);
13#endif 20#endif
diff --git a/arch/x86/kvm/page_track.c b/arch/x86/kvm/page_track.c
index 8c396d08c0a4..cd76bc318968 100644
--- a/arch/x86/kvm/page_track.c
+++ b/arch/x86/kvm/page_track.c
@@ -50,3 +50,88 @@ track_free:
50 kvm_page_track_free_memslot(slot, NULL); 50 kvm_page_track_free_memslot(slot, NULL);
51 return -ENOMEM; 51 return -ENOMEM;
52} 52}
53
54static inline bool page_track_mode_is_valid(enum kvm_page_track_mode mode)
55{
56 if (mode < 0 || mode >= KVM_PAGE_TRACK_MAX)
57 return false;
58
59 return true;
60}
61
62static void update_gfn_track(struct kvm_memory_slot *slot, gfn_t gfn,
63 enum kvm_page_track_mode mode, short count)
64{
65 int index, val;
66
67 index = gfn_to_index(gfn, slot->base_gfn, PT_PAGE_TABLE_LEVEL);
68
69 val = slot->arch.gfn_track[mode][index];
70
71 if (WARN_ON(val + count < 0 || val + count > USHRT_MAX))
72 return;
73
74 slot->arch.gfn_track[mode][index] += count;
75}
76
77/*
78 * add guest page to the tracking pool so that corresponding access on that
79 * page will be intercepted.
80 *
81 * It should be called under the protection both of mmu-lock and kvm->srcu
82 * or kvm->slots_lock.
83 *
84 * @kvm: the guest instance we are interested in.
85 * @slot: the @gfn belongs to.
86 * @gfn: the guest page.
87 * @mode: tracking mode, currently only write track is supported.
88 */
89void kvm_slot_page_track_add_page(struct kvm *kvm,
90 struct kvm_memory_slot *slot, gfn_t gfn,
91 enum kvm_page_track_mode mode)
92{
93
94 if (WARN_ON(!page_track_mode_is_valid(mode)))
95 return;
96
97 update_gfn_track(slot, gfn, mode, 1);
98
99 /*
100 * new track stops large page mapping for the
101 * tracked page.
102 */
103 kvm_mmu_gfn_disallow_lpage(slot, gfn);
104
105 if (mode == KVM_PAGE_TRACK_WRITE)
106 if (kvm_mmu_slot_gfn_write_protect(kvm, slot, gfn))
107 kvm_flush_remote_tlbs(kvm);
108}
109
110/*
111 * remove the guest page from the tracking pool which stops the interception
112 * of corresponding access on that page. It is the opposed operation of
113 * kvm_slot_page_track_add_page().
114 *
115 * It should be called under the protection both of mmu-lock and kvm->srcu
116 * or kvm->slots_lock.
117 *
118 * @kvm: the guest instance we are interested in.
119 * @slot: the @gfn belongs to.
120 * @gfn: the guest page.
121 * @mode: tracking mode, currently only write track is supported.
122 */
123void kvm_slot_page_track_remove_page(struct kvm *kvm,
124 struct kvm_memory_slot *slot, gfn_t gfn,
125 enum kvm_page_track_mode mode)
126{
127 if (WARN_ON(!page_track_mode_is_valid(mode)))
128 return;
129
130 update_gfn_track(slot, gfn, mode, -1);
131
132 /*
133 * allow large page mapping for the tracked page
134 * after the tracker is gone.
135 */
136 kvm_mmu_gfn_allow_lpage(slot, gfn);
137}