]> git.proxmox.com Git - mirror_qemu.git/blob - block/monitor/bitmap-qmp-cmds.c
282363606f945d6938dbd0543a8800fe405c0369
[mirror_qemu.git] / block / monitor / bitmap-qmp-cmds.c
1 /*
2 * QEMU block dirty bitmap QMP commands
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or
7 * later. See the COPYING file in the top-level directory.
8 *
9 * This file incorporates work covered by the following copyright and
10 * permission notice:
11 *
12 * Copyright (c) 2003-2008 Fabrice Bellard
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 * THE SOFTWARE.
31 */
32
33 #include "qemu/osdep.h"
34
35 #include "block/block_int.h"
36 #include "qapi/qapi-commands-block.h"
37 #include "qapi/error.h"
38
39 /**
40 * block_dirty_bitmap_lookup:
41 * Return a dirty bitmap (if present), after validating
42 * the node reference and bitmap names.
43 *
44 * @node: The name of the BDS node to search for bitmaps
45 * @name: The name of the bitmap to search for
46 * @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
47 * @errp: Output pointer for error information. Can be NULL.
48 *
49 * @return: A bitmap object on success, or NULL on failure.
50 */
51 BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
52 const char *name,
53 BlockDriverState **pbs,
54 Error **errp)
55 {
56 BlockDriverState *bs;
57 BdrvDirtyBitmap *bitmap;
58
59 GLOBAL_STATE_CODE();
60
61 if (!node) {
62 error_setg(errp, "Node cannot be NULL");
63 return NULL;
64 }
65 if (!name) {
66 error_setg(errp, "Bitmap name cannot be NULL");
67 return NULL;
68 }
69 bs = bdrv_lookup_bs(node, node, NULL);
70 if (!bs) {
71 error_setg(errp, "Node '%s' not found", node);
72 return NULL;
73 }
74
75 bitmap = bdrv_find_dirty_bitmap(bs, name);
76 if (!bitmap) {
77 error_setg(errp, "Dirty bitmap '%s' not found", name);
78 return NULL;
79 }
80
81 if (pbs) {
82 *pbs = bs;
83 }
84
85 return bitmap;
86 }
87
88 void qmp_block_dirty_bitmap_add(const char *node, const char *name,
89 bool has_granularity, uint32_t granularity,
90 bool has_persistent, bool persistent,
91 bool has_disabled, bool disabled,
92 Error **errp)
93 {
94 BlockDriverState *bs;
95 BdrvDirtyBitmap *bitmap;
96 AioContext *aio_context;
97
98 if (!name || name[0] == '\0') {
99 error_setg(errp, "Bitmap name cannot be empty");
100 return;
101 }
102
103 bs = bdrv_lookup_bs(node, node, errp);
104 if (!bs) {
105 return;
106 }
107
108 aio_context = bdrv_get_aio_context(bs);
109 aio_context_acquire(aio_context);
110
111 if (has_granularity) {
112 if (granularity < 512 || !is_power_of_2(granularity)) {
113 error_setg(errp, "Granularity must be power of 2 "
114 "and at least 512");
115 goto out;
116 }
117 } else {
118 /* Default to cluster size, if available: */
119 granularity = bdrv_get_default_bitmap_granularity(bs);
120 }
121
122 if (!has_persistent) {
123 persistent = false;
124 }
125
126 if (!has_disabled) {
127 disabled = false;
128 }
129
130 if (persistent &&
131 !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
132 {
133 goto out;
134 }
135
136 bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
137 if (bitmap == NULL) {
138 goto out;
139 }
140
141 if (disabled) {
142 bdrv_disable_dirty_bitmap(bitmap);
143 }
144
145 bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
146
147 out:
148 aio_context_release(aio_context);
149 }
150
151 BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
152 bool release,
153 BlockDriverState **bitmap_bs,
154 Error **errp)
155 {
156 BlockDriverState *bs;
157 BdrvDirtyBitmap *bitmap;
158 AioContext *aio_context;
159
160 GLOBAL_STATE_CODE();
161
162 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
163 if (!bitmap || !bs) {
164 return NULL;
165 }
166
167 aio_context = bdrv_get_aio_context(bs);
168 aio_context_acquire(aio_context);
169
170 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
171 errp)) {
172 aio_context_release(aio_context);
173 return NULL;
174 }
175
176 if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
177 bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
178 {
179 aio_context_release(aio_context);
180 return NULL;
181 }
182
183 if (release) {
184 bdrv_release_dirty_bitmap(bitmap);
185 }
186
187 if (bitmap_bs) {
188 *bitmap_bs = bs;
189 }
190
191 aio_context_release(aio_context);
192 return release ? NULL : bitmap;
193 }
194
195 void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
196 Error **errp)
197 {
198 block_dirty_bitmap_remove(node, name, true, NULL, errp);
199 }
200
201 /**
202 * Completely clear a bitmap, for the purposes of synchronizing a bitmap
203 * immediately after a full backup operation.
204 */
205 void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
206 Error **errp)
207 {
208 BdrvDirtyBitmap *bitmap;
209 BlockDriverState *bs;
210
211 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
212 if (!bitmap || !bs) {
213 return;
214 }
215
216 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
217 return;
218 }
219
220 bdrv_clear_dirty_bitmap(bitmap, NULL);
221 }
222
223 void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
224 Error **errp)
225 {
226 BlockDriverState *bs;
227 BdrvDirtyBitmap *bitmap;
228
229 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
230 if (!bitmap) {
231 return;
232 }
233
234 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
235 return;
236 }
237
238 bdrv_enable_dirty_bitmap(bitmap);
239 }
240
241 void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
242 Error **errp)
243 {
244 BlockDriverState *bs;
245 BdrvDirtyBitmap *bitmap;
246
247 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
248 if (!bitmap) {
249 return;
250 }
251
252 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
253 return;
254 }
255
256 bdrv_disable_dirty_bitmap(bitmap);
257 }
258
259 BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
260 BlockDirtyBitmapOrStrList *bms,
261 HBitmap **backup, Error **errp)
262 {
263 BlockDriverState *bs;
264 BdrvDirtyBitmap *dst, *src;
265 BlockDirtyBitmapOrStrList *lst;
266 HBitmap *local_backup = NULL;
267
268 GLOBAL_STATE_CODE();
269
270 dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
271 if (!dst) {
272 return NULL;
273 }
274
275 for (lst = bms; lst; lst = lst->next) {
276 switch (lst->value->type) {
277 const char *name, *node;
278 case QTYPE_QSTRING:
279 name = lst->value->u.local;
280 src = bdrv_find_dirty_bitmap(bs, name);
281 if (!src) {
282 error_setg(errp, "Dirty bitmap '%s' not found", name);
283 goto fail;
284 }
285 break;
286 case QTYPE_QDICT:
287 node = lst->value->u.external.node;
288 name = lst->value->u.external.name;
289 src = block_dirty_bitmap_lookup(node, name, NULL, errp);
290 if (!src) {
291 goto fail;
292 }
293 break;
294 default:
295 abort();
296 }
297
298 /* We do backup only for first merge operation */
299 if (!bdrv_merge_dirty_bitmap(dst, src,
300 local_backup ? NULL : &local_backup,
301 errp))
302 {
303 goto fail;
304 }
305 }
306
307 if (backup) {
308 *backup = local_backup;
309 } else {
310 hbitmap_free(local_backup);
311 }
312
313 return dst;
314
315 fail:
316 if (local_backup) {
317 bdrv_restore_dirty_bitmap(dst, local_backup);
318 }
319
320 return NULL;
321 }
322
323 void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
324 BlockDirtyBitmapOrStrList *bitmaps,
325 Error **errp)
326 {
327 block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
328 }