]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/extra/0007-memory-add-support-getting-and-using-a-dirty-bitmap-.patch
bump version to 2.9.1-9
[pve-qemu.git] / debian / patches / extra / 0007-memory-add-support-getting-and-using-a-dirty-bitmap-.patch
CommitLineData
3dcc8d3b 1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
ddbcf45e
WB
2From: Gerd Hoffmann <kraxel@redhat.com>
3Date: Fri, 21 Apr 2017 11:16:25 +0200
3dcc8d3b 4Subject: [PATCH] memory: add support getting and using a dirty bitmap copy.
ddbcf45e
WB
5
6This patch adds support for getting and using a local copy of the dirty
7bitmap.
8
9memory_region_snapshot_and_clear_dirty() will create a snapshot of the
10dirty bitmap for the specified range, clear the dirty bitmap and return
11the copy. The returned bitmap can be a bit larger than requested, the
12range is expanded so the code can copy unsigned longs from the bitmap
13and avoid atomic bit update operations.
14
15memory_region_snapshot_get_dirty() will return the dirty status of
16pages, pretty much like memory_region_get_dirty(), but using the copy
17returned by memory_region_copy_and_clear_dirty().
18
19Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
20Message-id: 20170421091632.30900-3-kraxel@redhat.com
21Signed-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
30diff --git a/exec.c b/exec.c
31index 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,
123diff --git a/include/exec/memory.h b/include/exec/memory.h
124index 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)
181diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
182index 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 {
199diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
200index 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;
211diff --git a/memory.c b/memory.c
212index 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--
2402.11.0
241