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-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 * block_dirty_bitmap_lookup:
43 * Return a dirty bitmap (if present), after validating
44 * the node reference and bitmap names.
45 *
46 * @node: The name of the BDS node to search for bitmaps
47 * @name: The name of the bitmap to search for
48 * @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
49 * @errp: Output pointer for error information. Can be NULL.
50 *
51 * @return: A bitmap object on success, or NULL on failure.
52 */
block_dirty_bitmap_lookup(const char * node,const char * name,BlockDriverState ** pbs,Error ** errp)53 BdrvDirtyBitmap *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
qmp_block_dirty_bitmap_add(const char * node,const char * name,bool has_granularity,uint32_t granularity,bool has_persistent,bool persistent,bool has_disabled,bool disabled,Error ** errp)90 void 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
99 if (!name || name[0] == '\0') {
100 error_setg(errp, "Bitmap name cannot be empty");
101 return;
102 }
103
104 bs = bdrv_lookup_bs(node, node, errp);
105 if (!bs) {
106 return;
107 }
108
109 if (has_granularity) {
110 if (granularity < 512 || !is_power_of_2(granularity)) {
111 error_setg(errp, "Granularity must be power of 2 "
112 "and at least 512");
113 return;
114 }
115 } else {
116 /* Default to cluster size, if available: */
117 granularity = bdrv_get_default_bitmap_granularity(bs);
118 }
119
120 if (!has_persistent) {
121 persistent = false;
122 }
123
124 if (!has_disabled) {
125 disabled = false;
126 }
127
128 if (persistent &&
129 !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
130 {
131 return;
132 }
133
134 bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
135 if (bitmap == NULL) {
136 return;
137 }
138
139 if (disabled) {
140 bdrv_disable_dirty_bitmap(bitmap);
141 }
142
143 bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
144 }
145
block_dirty_bitmap_remove(const char * node,const char * name,bool release,BlockDriverState ** bitmap_bs,Error ** errp)146 BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
147 bool release,
148 BlockDriverState **bitmap_bs,
149 Error **errp)
150 {
151 BlockDriverState *bs;
152 BdrvDirtyBitmap *bitmap;
153
154 GLOBAL_STATE_CODE();
155
156 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
157 if (!bitmap || !bs) {
158 return NULL;
159 }
160
161 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
162 errp)) {
163 return NULL;
164 }
165
166 if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
167 bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
168 {
169 return NULL;
170 }
171
172 if (release) {
173 bdrv_release_dirty_bitmap(bitmap);
174 }
175
176 if (bitmap_bs) {
177 *bitmap_bs = bs;
178 }
179
180 return release ? NULL : bitmap;
181 }
182
qmp_block_dirty_bitmap_remove(const char * node,const char * name,Error ** errp)183 void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
184 Error **errp)
185 {
186 block_dirty_bitmap_remove(node, name, true, NULL, errp);
187 }
188
189 /**
190 * Completely clear a bitmap, for the purposes of synchronizing a bitmap
191 * immediately after a full backup operation.
192 */
qmp_block_dirty_bitmap_clear(const char * node,const char * name,Error ** errp)193 void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
194 Error **errp)
195 {
196 BdrvDirtyBitmap *bitmap;
197 BlockDriverState *bs;
198
199 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
200 if (!bitmap || !bs) {
201 return;
202 }
203
204 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
205 return;
206 }
207
208 bdrv_clear_dirty_bitmap(bitmap, NULL);
209 }
210
qmp_block_dirty_bitmap_enable(const char * node,const char * name,Error ** errp)211 void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
212 Error **errp)
213 {
214 BlockDriverState *bs;
215 BdrvDirtyBitmap *bitmap;
216
217 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
218 if (!bitmap) {
219 return;
220 }
221
222 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
223 return;
224 }
225
226 bdrv_enable_dirty_bitmap(bitmap);
227 }
228
qmp_block_dirty_bitmap_disable(const char * node,const char * name,Error ** errp)229 void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
230 Error **errp)
231 {
232 BlockDriverState *bs;
233 BdrvDirtyBitmap *bitmap;
234
235 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
236 if (!bitmap) {
237 return;
238 }
239
240 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
241 return;
242 }
243
244 bdrv_disable_dirty_bitmap(bitmap);
245 }
246
block_dirty_bitmap_merge(const char * dst_node,const char * dst_bitmap,BlockDirtyBitmapOrStrList * bms,HBitmap ** backup,Error ** errp)247 BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *dst_node,
248 const char *dst_bitmap,
249 BlockDirtyBitmapOrStrList *bms,
250 HBitmap **backup, Error **errp)
251 {
252 BlockDriverState *bs;
253 BdrvDirtyBitmap *dst, *src;
254 BlockDirtyBitmapOrStrList *lst;
255 const char *src_node, *src_bitmap;
256 HBitmap *local_backup = NULL;
257
258 GLOBAL_STATE_CODE();
259
260 dst = block_dirty_bitmap_lookup(dst_node, dst_bitmap, &bs, errp);
261 if (!dst) {
262 return NULL;
263 }
264
265 for (lst = bms; lst; lst = lst->next) {
266 switch (lst->value->type) {
267 case QTYPE_QSTRING:
268 src_bitmap = lst->value->u.local;
269 src = bdrv_find_dirty_bitmap(bs, src_bitmap);
270 if (!src) {
271 error_setg(errp, "Dirty bitmap '%s' not found", src_bitmap);
272 goto fail;
273 }
274 break;
275 case QTYPE_QDICT:
276 src_node = lst->value->u.external.node;
277 src_bitmap = lst->value->u.external.name;
278 src = block_dirty_bitmap_lookup(src_node, src_bitmap, NULL, errp);
279 if (!src) {
280 goto fail;
281 }
282 break;
283 default:
284 abort();
285 }
286
287 /* We do backup only for first merge operation */
288 if (!bdrv_merge_dirty_bitmap(dst, src,
289 local_backup ? NULL : &local_backup,
290 errp))
291 {
292 goto fail;
293 }
294 }
295
296 if (backup) {
297 *backup = local_backup;
298 } else {
299 hbitmap_free(local_backup);
300 }
301
302 return dst;
303
304 fail:
305 if (local_backup) {
306 bdrv_restore_dirty_bitmap(dst, local_backup);
307 }
308
309 return NULL;
310 }
311
qmp_block_dirty_bitmap_merge(const char * node,const char * target,BlockDirtyBitmapOrStrList * bitmaps,Error ** errp)312 void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
313 BlockDirtyBitmapOrStrList *bitmaps,
314 Error **errp)
315 {
316 block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
317 }
318