]> git.proxmox.com Git - mirror_qemu.git/blob - block/monitor/bitmap-qmp-cmds.c
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20201104' into staging
[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 if (!node) {
60 error_setg(errp, "Node cannot be NULL");
61 return NULL;
62 }
63 if (!name) {
64 error_setg(errp, "Bitmap name cannot be NULL");
65 return NULL;
66 }
67 bs = bdrv_lookup_bs(node, node, NULL);
68 if (!bs) {
69 error_setg(errp, "Node '%s' not found", node);
70 return NULL;
71 }
72
73 bitmap = bdrv_find_dirty_bitmap(bs, name);
74 if (!bitmap) {
75 error_setg(errp, "Dirty bitmap '%s' not found", name);
76 return NULL;
77 }
78
79 if (pbs) {
80 *pbs = bs;
81 }
82
83 return bitmap;
84 }
85
86 void qmp_block_dirty_bitmap_add(const char *node, const char *name,
87 bool has_granularity, uint32_t granularity,
88 bool has_persistent, bool persistent,
89 bool has_disabled, bool disabled,
90 Error **errp)
91 {
92 BlockDriverState *bs;
93 BdrvDirtyBitmap *bitmap;
94 AioContext *aio_context;
95
96 if (!name || name[0] == '\0') {
97 error_setg(errp, "Bitmap name cannot be empty");
98 return;
99 }
100
101 bs = bdrv_lookup_bs(node, node, errp);
102 if (!bs) {
103 return;
104 }
105
106 aio_context = bdrv_get_aio_context(bs);
107 aio_context_acquire(aio_context);
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 goto out;
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 goto out;
132 }
133
134 bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
135 if (bitmap == NULL) {
136 goto out;
137 }
138
139 if (disabled) {
140 bdrv_disable_dirty_bitmap(bitmap);
141 }
142
143 bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
144
145 out:
146 aio_context_release(aio_context);
147 }
148
149 BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
150 bool release,
151 BlockDriverState **bitmap_bs,
152 Error **errp)
153 {
154 BlockDriverState *bs;
155 BdrvDirtyBitmap *bitmap;
156 AioContext *aio_context;
157
158 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
159 if (!bitmap || !bs) {
160 return NULL;
161 }
162
163 aio_context = bdrv_get_aio_context(bs);
164 aio_context_acquire(aio_context);
165
166 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
167 errp)) {
168 aio_context_release(aio_context);
169 return NULL;
170 }
171
172 if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
173 bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
174 {
175 aio_context_release(aio_context);
176 return NULL;
177 }
178
179 if (release) {
180 bdrv_release_dirty_bitmap(bitmap);
181 }
182
183 if (bitmap_bs) {
184 *bitmap_bs = bs;
185 }
186
187 aio_context_release(aio_context);
188 return release ? NULL : bitmap;
189 }
190
191 void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
192 Error **errp)
193 {
194 block_dirty_bitmap_remove(node, name, true, NULL, errp);
195 }
196
197 /**
198 * Completely clear a bitmap, for the purposes of synchronizing a bitmap
199 * immediately after a full backup operation.
200 */
201 void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
202 Error **errp)
203 {
204 BdrvDirtyBitmap *bitmap;
205 BlockDriverState *bs;
206
207 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
208 if (!bitmap || !bs) {
209 return;
210 }
211
212 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
213 return;
214 }
215
216 bdrv_clear_dirty_bitmap(bitmap, NULL);
217 }
218
219 void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
220 Error **errp)
221 {
222 BlockDriverState *bs;
223 BdrvDirtyBitmap *bitmap;
224
225 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
226 if (!bitmap) {
227 return;
228 }
229
230 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
231 return;
232 }
233
234 bdrv_enable_dirty_bitmap(bitmap);
235 }
236
237 void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
238 Error **errp)
239 {
240 BlockDriverState *bs;
241 BdrvDirtyBitmap *bitmap;
242
243 bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
244 if (!bitmap) {
245 return;
246 }
247
248 if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
249 return;
250 }
251
252 bdrv_disable_dirty_bitmap(bitmap);
253 }
254
255 BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
256 BlockDirtyBitmapMergeSourceList *bms,
257 HBitmap **backup, Error **errp)
258 {
259 BlockDriverState *bs;
260 BdrvDirtyBitmap *dst, *src, *anon;
261 BlockDirtyBitmapMergeSourceList *lst;
262 Error *local_err = NULL;
263
264 dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
265 if (!dst) {
266 return NULL;
267 }
268
269 anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
270 NULL, errp);
271 if (!anon) {
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 dst = NULL;
284 goto out;
285 }
286 break;
287 case QTYPE_QDICT:
288 node = lst->value->u.external.node;
289 name = lst->value->u.external.name;
290 src = block_dirty_bitmap_lookup(node, name, NULL, errp);
291 if (!src) {
292 dst = NULL;
293 goto out;
294 }
295 break;
296 default:
297 abort();
298 }
299
300 bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
301 if (local_err) {
302 error_propagate(errp, local_err);
303 dst = NULL;
304 goto out;
305 }
306 }
307
308 /* Merge into dst; dst is unchanged on failure. */
309 bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
310
311 out:
312 bdrv_release_dirty_bitmap(anon);
313 return dst;
314 }
315
316 void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
317 BlockDirtyBitmapMergeSourceList *bitmaps,
318 Error **errp)
319 {
320 block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
321 }