1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * KVM dirty ring implementation
5 * Copyright 2019 Red Hat, Inc.
7 #include <linux/kvm_host.h>
9 #include <linux/vmalloc.h>
10 #include <linux/kvm_dirty_ring.h>
11 #include <trace/events/kvm.h>
13 int __weak
kvm_cpu_dirty_log_size(void)
18 u32
kvm_dirty_ring_get_rsvd_entries(void)
20 return KVM_DIRTY_RING_RSVD_ENTRIES
+ kvm_cpu_dirty_log_size();
23 static u32
kvm_dirty_ring_used(struct kvm_dirty_ring
*ring
)
25 return READ_ONCE(ring
->dirty_index
) - READ_ONCE(ring
->reset_index
);
28 bool kvm_dirty_ring_soft_full(struct kvm_dirty_ring
*ring
)
30 return kvm_dirty_ring_used(ring
) >= ring
->soft_limit
;
33 static bool kvm_dirty_ring_full(struct kvm_dirty_ring
*ring
)
35 return kvm_dirty_ring_used(ring
) >= ring
->size
;
38 struct kvm_dirty_ring
*kvm_dirty_ring_get(struct kvm
*kvm
)
40 struct kvm_vcpu
*vcpu
= kvm_get_running_vcpu();
42 WARN_ON_ONCE(vcpu
->kvm
!= kvm
);
44 return &vcpu
->dirty_ring
;
47 static void kvm_reset_dirty_gfn(struct kvm
*kvm
, u32 slot
, u64 offset
, u64 mask
)
49 struct kvm_memory_slot
*memslot
;
55 if (as_id
>= KVM_ADDRESS_SPACE_NUM
|| id
>= KVM_USER_MEM_SLOTS
)
58 memslot
= id_to_memslot(__kvm_memslots(kvm
, as_id
), id
);
60 if (!memslot
|| (offset
+ __fls(mask
)) >= memslot
->npages
)
63 spin_lock(&kvm
->mmu_lock
);
64 kvm_arch_mmu_enable_log_dirty_pt_masked(kvm
, memslot
, offset
, mask
);
65 spin_unlock(&kvm
->mmu_lock
);
68 int kvm_dirty_ring_alloc(struct kvm_dirty_ring
*ring
, int index
, u32 size
)
70 ring
->dirty_gfns
= vmalloc(size
);
71 if (!ring
->dirty_gfns
)
73 memset(ring
->dirty_gfns
, 0, size
);
75 ring
->size
= size
/ sizeof(struct kvm_dirty_gfn
);
76 ring
->soft_limit
= ring
->size
- kvm_dirty_ring_get_rsvd_entries();
77 ring
->dirty_index
= 0;
78 ring
->reset_index
= 0;
84 static inline void kvm_dirty_gfn_set_invalid(struct kvm_dirty_gfn
*gfn
)
89 static inline void kvm_dirty_gfn_set_dirtied(struct kvm_dirty_gfn
*gfn
)
91 gfn
->flags
= KVM_DIRTY_GFN_F_DIRTY
;
94 static inline bool kvm_dirty_gfn_invalid(struct kvm_dirty_gfn
*gfn
)
96 return gfn
->flags
== 0;
99 static inline bool kvm_dirty_gfn_harvested(struct kvm_dirty_gfn
*gfn
)
101 return gfn
->flags
& KVM_DIRTY_GFN_F_RESET
;
104 int kvm_dirty_ring_reset(struct kvm
*kvm
, struct kvm_dirty_ring
*ring
)
106 u32 cur_slot
, next_slot
;
107 u64 cur_offset
, next_offset
;
110 struct kvm_dirty_gfn
*entry
;
111 bool first_round
= true;
113 /* This is only needed to make compilers happy */
114 cur_slot
= cur_offset
= mask
= 0;
117 entry
= &ring
->dirty_gfns
[ring
->reset_index
& (ring
->size
- 1)];
119 if (!kvm_dirty_gfn_harvested(entry
))
122 next_slot
= READ_ONCE(entry
->slot
);
123 next_offset
= READ_ONCE(entry
->offset
);
125 /* Update the flags to reflect that this GFN is reset */
126 kvm_dirty_gfn_set_invalid(entry
);
131 * Try to coalesce the reset operations when the guest is
132 * scanning pages in the same slot.
134 if (!first_round
&& next_slot
== cur_slot
) {
135 s64 delta
= next_offset
- cur_offset
;
137 if (delta
>= 0 && delta
< BITS_PER_LONG
) {
138 mask
|= 1ull << delta
;
142 /* Backwards visit, careful about overflows! */
143 if (delta
> -BITS_PER_LONG
&& delta
< 0 &&
144 (mask
<< -delta
>> -delta
) == mask
) {
145 cur_offset
= next_offset
;
146 mask
= (mask
<< -delta
) | 1;
150 kvm_reset_dirty_gfn(kvm
, cur_slot
, cur_offset
, mask
);
151 cur_slot
= next_slot
;
152 cur_offset
= next_offset
;
157 kvm_reset_dirty_gfn(kvm
, cur_slot
, cur_offset
, mask
);
159 trace_kvm_dirty_ring_reset(ring
);
164 void kvm_dirty_ring_push(struct kvm_dirty_ring
*ring
, u32 slot
, u64 offset
)
166 struct kvm_dirty_gfn
*entry
;
168 /* It should never get full */
169 WARN_ON_ONCE(kvm_dirty_ring_full(ring
));
171 entry
= &ring
->dirty_gfns
[ring
->dirty_index
& (ring
->size
- 1)];
174 entry
->offset
= offset
;
176 * Make sure the data is filled in before we publish this to
177 * the userspace program. There's no paired kernel-side reader.
180 kvm_dirty_gfn_set_dirtied(entry
);
182 trace_kvm_dirty_ring_push(ring
, slot
, offset
);
185 struct page
*kvm_dirty_ring_get_page(struct kvm_dirty_ring
*ring
, u32 offset
)
187 return vmalloc_to_page((void *)ring
->dirty_gfns
+ offset
* PAGE_SIZE
);
190 void kvm_dirty_ring_free(struct kvm_dirty_ring
*ring
)
192 vfree(ring
->dirty_gfns
);
193 ring
->dirty_gfns
= NULL
;