]> git.proxmox.com Git - pve-qemu.git/blob - debian/patches/extra/0007-memory-add-support-getting-and-using-a-dirty-bitmap-.patch
8b202fb208bb29ea056772c2032e5b0093027ff1
[pve-qemu.git] / debian / patches / extra / 0007-memory-add-support-getting-and-using-a-dirty-bitmap-.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Gerd Hoffmann <kraxel@redhat.com>
3 Date: Fri, 21 Apr 2017 11:16:25 +0200
4 Subject: [PATCH] memory: add support getting and using a dirty bitmap copy.
5
6 This patch adds support for getting and using a local copy of the dirty
7 bitmap.
8
9 memory_region_snapshot_and_clear_dirty() will create a snapshot of the
10 dirty bitmap for the specified range, clear the dirty bitmap and return
11 the copy. The returned bitmap can be a bit larger than requested, the
12 range is expanded so the code can copy unsigned longs from the bitmap
13 and avoid atomic bit update operations.
14
15 memory_region_snapshot_get_dirty() will return the dirty status of
16 pages, pretty much like memory_region_get_dirty(), but using the copy
17 returned by memory_region_copy_and_clear_dirty().
18
19 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
20 Message-id: 20170421091632.30900-3-kraxel@redhat.com
21 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
22 ---
23 exec.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
24 include/exec/memory.h | 47 +++++++++++++++++++++++++++++++
25 include/exec/ram_addr.h | 7 +++++
26 include/qemu/typedefs.h | 1 +
27 memory.c | 17 +++++++++++
28 5 files changed, 147 insertions(+)
29
30 diff --git a/exec.c b/exec.c
31 index fcb5b16131..07c2c8ea88 100644
32 --- a/exec.c
33 +++ b/exec.c
34 @@ -223,6 +223,12 @@ struct CPUAddressSpace {
35 MemoryListener tcg_as_listener;
36 };
37
38 +struct DirtyBitmapSnapshot {
39 + ram_addr_t start;
40 + ram_addr_t end;
41 + unsigned long dirty[];
42 +};
43 +
44 #endif
45
46 #if !defined(CONFIG_USER_ONLY)
47 @@ -1061,6 +1067,75 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
48 return dirty;
49 }
50
51 +DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
52 + (ram_addr_t start, ram_addr_t length, unsigned client)
53 +{
54 + DirtyMemoryBlocks *blocks;
55 + unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
56 + ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
57 + ram_addr_t last = QEMU_ALIGN_UP(start + length, align);
58 + DirtyBitmapSnapshot *snap;
59 + unsigned long page, end, dest;
60 +
61 + snap = g_malloc0(sizeof(*snap) +
62 + ((last - first) >> (TARGET_PAGE_BITS + 3)));
63 + snap->start = first;
64 + snap->end = last;
65 +
66 + page = first >> TARGET_PAGE_BITS;
67 + end = last >> TARGET_PAGE_BITS;
68 + dest = 0;
69 +
70 + rcu_read_lock();
71 +
72 + blocks = atomic_rcu_read(&ram_list.dirty_memory[client]);
73 +
74 + while (page < end) {
75 + unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
76 + unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
77 + unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset);
78 +
79 + assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL)));
80 + assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL)));
81 + offset >>= BITS_PER_LEVEL;
82 +
83 + bitmap_copy_and_clear_atomic(snap->dirty + dest,
84 + blocks->blocks[idx] + offset,
85 + num);
86 + page += num;
87 + dest += num >> BITS_PER_LEVEL;
88 + }
89 +
90 + rcu_read_unlock();
91 +
92 + if (tcg_enabled()) {
93 + tlb_reset_dirty_range_all(start, length);
94 + }
95 +
96 + return snap;
97 +}
98 +
99 +bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
100 + ram_addr_t start,
101 + ram_addr_t length)
102 +{
103 + unsigned long page, end;
104 +
105 + assert(start >= snap->start);
106 + assert(start + length <= snap->end);
107 +
108 + end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
109 + page = (start - snap->start) >> TARGET_PAGE_BITS;
110 +
111 + while (page < end) {
112 + if (test_bit(page, snap->dirty)) {
113 + return true;
114 + }
115 + page++;
116 + }
117 + return false;
118 +}
119 +
120 /* Called from RCU critical section */
121 hwaddr memory_region_section_get_iotlb(CPUState *cpu,
122 MemoryRegionSection *section,
123 diff --git a/include/exec/memory.h b/include/exec/memory.h
124 index f20b191793..1e15e79d00 100644
125 --- a/include/exec/memory.h
126 +++ b/include/exec/memory.h
127 @@ -871,6 +871,53 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
128 */
129 bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
130 hwaddr size, unsigned client);
131 +
132 +/**
133 + * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty
134 + * bitmap and clear it.
135 + *
136 + * Creates a snapshot of the dirty bitmap, clears the dirty bitmap and
137 + * returns the snapshot. The snapshot can then be used to query dirty
138 + * status, using memory_region_snapshot_get_dirty. Unlike
139 + * memory_region_test_and_clear_dirty this allows to query the same
140 + * page multiple times, which is especially useful for display updates
141 + * where the scanlines often are not page aligned.
142 + *
143 + * The dirty bitmap region which gets copyed into the snapshot (and
144 + * cleared afterwards) can be larger than requested. The boundaries
145 + * are rounded up/down so complete bitmap longs (covering 64 pages on
146 + * 64bit hosts) can be copied over into the bitmap snapshot. Which
147 + * isn't a problem for display updates as the extra pages are outside
148 + * the visible area, and in case the visible area changes a full
149 + * display redraw is due anyway. Should other use cases for this
150 + * function emerge we might have to revisit this implementation
151 + * detail.
152 + *
153 + * Use g_free to release DirtyBitmapSnapshot.
154 + *
155 + * @mr: the memory region being queried.
156 + * @addr: the address (relative to the start of the region) being queried.
157 + * @size: the size of the range being queried.
158 + * @client: the user of the logging information; typically %DIRTY_MEMORY_VGA.
159 + */
160 +DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
161 + hwaddr addr,
162 + hwaddr size,
163 + unsigned client);
164 +
165 +/**
166 + * memory_region_snapshot_get_dirty: Check whether a range of bytes is dirty
167 + * in the specified dirty bitmap snapshot.
168 + *
169 + * @mr: the memory region being queried.
170 + * @snap: the dirty bitmap snapshot
171 + * @addr: the address (relative to the start of the region) being queried.
172 + * @size: the size of the range being queried.
173 + */
174 +bool memory_region_snapshot_get_dirty(MemoryRegion *mr,
175 + DirtyBitmapSnapshot *snap,
176 + hwaddr addr, hwaddr size);
177 +
178 /**
179 * memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
180 * any external TLBs (e.g. kvm)
181 diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
182 index b05dc84ab9..2b63d7f59e 100644
183 --- a/include/exec/ram_addr.h
184 +++ b/include/exec/ram_addr.h
185 @@ -343,6 +343,13 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
186 ram_addr_t length,
187 unsigned client);
188
189 +DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
190 + (ram_addr_t start, ram_addr_t length, unsigned client);
191 +
192 +bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
193 + ram_addr_t start,
194 + ram_addr_t length);
195 +
196 static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
197 ram_addr_t length)
198 {
199 diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
200 index e95f28cfec..f08d327aec 100644
201 --- a/include/qemu/typedefs.h
202 +++ b/include/qemu/typedefs.h
203 @@ -23,6 +23,7 @@ typedef struct CPUAddressSpace CPUAddressSpace;
204 typedef struct CPUState CPUState;
205 typedef struct DeviceListener DeviceListener;
206 typedef struct DeviceState DeviceState;
207 +typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
208 typedef struct DisplayChangeListener DisplayChangeListener;
209 typedef struct DisplayState DisplayState;
210 typedef struct DisplaySurface DisplaySurface;
211 diff --git a/memory.c b/memory.c
212 index 4c95aaf39c..8a0648551f 100644
213 --- a/memory.c
214 +++ b/memory.c
215 @@ -1716,6 +1716,23 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
216 memory_region_get_ram_addr(mr) + addr, size, client);
217 }
218
219 +DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
220 + hwaddr addr,
221 + hwaddr size,
222 + unsigned client)
223 +{
224 + assert(mr->ram_block);
225 + return cpu_physical_memory_snapshot_and_clear_dirty(
226 + memory_region_get_ram_addr(mr) + addr, size, client);
227 +}
228 +
229 +bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap,
230 + hwaddr addr, hwaddr size)
231 +{
232 + assert(mr->ram_block);
233 + return cpu_physical_memory_snapshot_get_dirty(snap,
234 + memory_region_get_ram_addr(mr) + addr, size);
235 +}
236
237 void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
238 {
239 --
240 2.11.0
241