1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include "qemu/osdep.h"
34
35#include "block/block-io.h"
36#include "block/block_int.h"
37#include "block/dirty-bitmap.h"
38#include "qapi/qapi-commands-block.h"
39#include "qapi/error.h"
40
41
42
43
44
45
46
47
48
49
50
51
52
53BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
54 const char *name,
55 BlockDriverState **pbs,
56 Error **errp)
57{
58 BlockDriverState *bs;
59 BdrvDirtyBitmap *bitmap;
60
61 GLOBAL_STATE_CODE();
62
63 if (!node) {
64 error_setg(errp, "Node cannot be NULL");
65 return NULL;
66 }
67 if (!name) {
68 error_setg(errp, "Bitmap name cannot be NULL");
69 return NULL;
70 }
71 bs = bdrv_lookup_bs(node, node, NULL);
72 if (!bs) {
73 error_setg(errp, "Node '%s' not found", node);
74 return NULL;
75 }
76
77 bitmap = bdrv_find_dirty_bitmap(bs, name);
78 if (!bitmap) {
79 error_setg(errp, "Dirty bitmap '%s' not found", name);
80 return NULL;
81 }
82
83 if (pbs) {
84 *pbs = bs;
85 }
86
87 return bitmap;
88}
89
90void qmp_block_dirty_bitmap_add(const char *node, const char *name,
91 bool has_granularity, uint32_t granularity,
92 bool has_persistent, bool persistent,
93 bool has_disabled, bool disabled,
94 Error **errp)
95{
96 BlockDriverState *bs;
97 BdrvDirtyBitmap *bitmap;
98 AioContext *aio_context;
99
100 if (!name || name[0] == '\0') {
101 error_setg(errp, "Bitmap name cannot be empty");
102 return;
103 }
104
105 bs = bdrv_lookup_bs(node, node, errp);
106 if (!bs) {
107 return;
108 }
109
110 aio_context = bdrv_get_aio_context(bs);
111 aio_context_acquire(aio_context);
112
113 if (has_granularity) {
114 if (granularity < 512 || !is_power_of_2(granularity)) {
115 error_setg(errp, "Granularity must be power of 2 "
116 "and at least 512");
117 goto out;
118 }
119 } else {
120
121 granularity = bdrv_get_default_bitmap_granularity(bs);
122 }
123
124 if (!has_persistent) {
125 persistent = false;
126 }
127
128 if (!has_disabled) {
129 disabled = false;
130 }
131
132 if (persistent &&
133 !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
134 {
135 goto out;
136 }
137
138 bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
139 if (bitmap == NULL) {
140 goto out;
141 }
142
143 if (disabled) {
144 bdrv_disable_dirty_bitmap(bitmap);
145 }
146
147 bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
148
149out:
150 aio_context_release(aio_context);
151}
152
153BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
154 bool release,
155 BlockDriverState **bitmap_bs,
156 Error **errp)
157{
158 BlockDriverState *bs;
159 BdrvDirtyBitmap *bitmap;
160 AioContext *aio_context;
161
162 GLOBAL_STATE_CODE();
163
164 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
165 if (!bitmap || !bs) {
166 return NULL;
167 }
168
169 aio_context = bdrv_get_aio_context(bs);
170 aio_context_acquire(aio_context);
171
172 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
173 errp)) {
174 aio_context_release(aio_context);
175 return NULL;
176 }
177
178 if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
179 bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
180 {
181 aio_context_release(aio_context);
182 return NULL;
183 }
184
185 if (release) {
186 bdrv_release_dirty_bitmap(bitmap);
187 }
188
189 if (bitmap_bs) {
190 *bitmap_bs = bs;
191 }
192
193 aio_context_release(aio_context);
194 return release ? NULL : bitmap;
195}
196
197void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
198 Error **errp)
199{
200 block_dirty_bitmap_remove(node, name, true, NULL, errp);
201}
202
203
204
205
206
207void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
208 Error **errp)
209{
210 BdrvDirtyBitmap *bitmap;
211 BlockDriverState *bs;
212
213 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
214 if (!bitmap || !bs) {
215 return;
216 }
217
218 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
219 return;
220 }
221
222 bdrv_clear_dirty_bitmap(bitmap, NULL);
223}
224
225void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
226 Error **errp)
227{
228 BlockDriverState *bs;
229 BdrvDirtyBitmap *bitmap;
230
231 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
232 if (!bitmap) {
233 return;
234 }
235
236 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
237 return;
238 }
239
240 bdrv_enable_dirty_bitmap(bitmap);
241}
242
243void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
244 Error **errp)
245{
246 BlockDriverState *bs;
247 BdrvDirtyBitmap *bitmap;
248
249 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
250 if (!bitmap) {
251 return;
252 }
253
254 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
255 return;
256 }
257
258 bdrv_disable_dirty_bitmap(bitmap);
259}
260
261BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
262 BlockDirtyBitmapOrStrList *bms,
263 HBitmap **backup, Error **errp)
264{
265 BlockDriverState *bs;
266 BdrvDirtyBitmap *dst, *src;
267 BlockDirtyBitmapOrStrList *lst;
268 HBitmap *local_backup = NULL;
269
270 GLOBAL_STATE_CODE();
271
272 dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
273 if (!dst) {
274 return NULL;
275 }
276
277 for (lst = bms; lst; lst = lst->next) {
278 switch (lst->value->type) {
279 const char *name, *node;
280 case QTYPE_QSTRING:
281 name = lst->value->u.local;
282 src = bdrv_find_dirty_bitmap(bs, name);
283 if (!src) {
284 error_setg(errp, "Dirty bitmap '%s' not found", name);
285 goto fail;
286 }
287 break;
288 case QTYPE_QDICT:
289 node = lst->value->u.external.node;
290 name = lst->value->u.external.name;
291 src = block_dirty_bitmap_lookup(node, name, NULL, errp);
292 if (!src) {
293 goto fail;
294 }
295 break;
296 default:
297 abort();
298 }
299
300
301 if (!bdrv_merge_dirty_bitmap(dst, src,
302 local_backup ? NULL : &local_backup,
303 errp))
304 {
305 goto fail;
306 }
307 }
308
309 if (backup) {
310 *backup = local_backup;
311 } else {
312 hbitmap_free(local_backup);
313 }
314
315 return dst;
316
317fail:
318 if (local_backup) {
319 bdrv_restore_dirty_bitmap(dst, local_backup);
320 }
321
322 return NULL;
323}
324
325void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
326 BlockDirtyBitmapOrStrList *bitmaps,
327 Error **errp)
328{
329 block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
330}
331