replay: added replay log format description
[qemu/ar7.git] / block / dirty-bitmap.c
blob909f0517f8c229f612dbb1996554875d2777617d
1 /*
2 * Block Dirty Bitmap
4 * Copyright (c) 2016-2017 Red Hat. Inc
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "qemu/osdep.h"
25 #include "qapi/error.h"
26 #include "qemu-common.h"
27 #include "trace.h"
28 #include "block/block_int.h"
29 #include "block/blockjob.h"
31 /**
32 * A BdrvDirtyBitmap can be in three possible states:
33 * (1) successor is NULL and disabled is false: full r/w mode
34 * (2) successor is NULL and disabled is true: read only mode ("disabled")
35 * (3) successor is set: frozen mode.
36 * A frozen bitmap cannot be renamed, deleted, anonymized, cleared, set,
37 * or enabled. A frozen bitmap can only abdicate() or reclaim().
39 struct BdrvDirtyBitmap {
40 QemuMutex *mutex;
41 HBitmap *bitmap; /* Dirty bitmap implementation */
42 HBitmap *meta; /* Meta dirty bitmap */
43 BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
44 char *name; /* Optional non-empty unique ID */
45 int64_t size; /* Size of the bitmap, in bytes */
46 bool disabled; /* Bitmap is disabled. It ignores all writes to
47 the device */
48 int active_iterators; /* How many iterators are active */
49 bool readonly; /* Bitmap is read-only. This field also
50 prevents the respective image from being
51 modified (i.e. blocks writes and discards).
52 Such operations must fail and both the image
53 and this bitmap must remain unchanged while
54 this flag is set. */
55 bool persistent; /* bitmap must be saved to owner disk image */
56 QLIST_ENTRY(BdrvDirtyBitmap) list;
59 struct BdrvDirtyBitmapIter {
60 HBitmapIter hbi;
61 BdrvDirtyBitmap *bitmap;
64 static inline void bdrv_dirty_bitmaps_lock(BlockDriverState *bs)
66 qemu_mutex_lock(&bs->dirty_bitmap_mutex);
69 static inline void bdrv_dirty_bitmaps_unlock(BlockDriverState *bs)
71 qemu_mutex_unlock(&bs->dirty_bitmap_mutex);
74 void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap)
76 qemu_mutex_lock(bitmap->mutex);
79 void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap)
81 qemu_mutex_unlock(bitmap->mutex);
84 /* Called with BQL or dirty_bitmap lock taken. */
85 BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
87 BdrvDirtyBitmap *bm;
89 assert(name);
90 QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
91 if (bm->name && !strcmp(name, bm->name)) {
92 return bm;
95 return NULL;
98 /* Called with BQL taken. */
99 void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
101 assert(!bdrv_dirty_bitmap_frozen(bitmap));
102 g_free(bitmap->name);
103 bitmap->name = NULL;
104 bitmap->persistent = false;
107 /* Called with BQL taken. */
108 BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
109 uint32_t granularity,
110 const char *name,
111 Error **errp)
113 int64_t bitmap_size;
114 BdrvDirtyBitmap *bitmap;
116 assert(is_power_of_2(granularity) && granularity >= BDRV_SECTOR_SIZE);
118 if (name && bdrv_find_dirty_bitmap(bs, name)) {
119 error_setg(errp, "Bitmap already exists: %s", name);
120 return NULL;
122 bitmap_size = bdrv_getlength(bs);
123 if (bitmap_size < 0) {
124 error_setg_errno(errp, -bitmap_size, "could not get length of device");
125 errno = -bitmap_size;
126 return NULL;
128 bitmap = g_new0(BdrvDirtyBitmap, 1);
129 bitmap->mutex = &bs->dirty_bitmap_mutex;
130 bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(granularity));
131 bitmap->size = bitmap_size;
132 bitmap->name = g_strdup(name);
133 bitmap->disabled = false;
134 bdrv_dirty_bitmaps_lock(bs);
135 QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
136 bdrv_dirty_bitmaps_unlock(bs);
137 return bitmap;
140 /* bdrv_create_meta_dirty_bitmap
142 * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e.
143 * when a dirty status bit in @bitmap is changed (either from reset to set or
144 * the other way around), its respective meta dirty bitmap bit will be marked
145 * dirty as well.
147 * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
148 * @chunk_size: how many bytes of bitmap data does each bit in the meta bitmap
149 * track.
151 void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
152 int chunk_size)
154 assert(!bitmap->meta);
155 qemu_mutex_lock(bitmap->mutex);
156 bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
157 chunk_size * BITS_PER_BYTE);
158 qemu_mutex_unlock(bitmap->mutex);
161 void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
163 assert(bitmap->meta);
164 qemu_mutex_lock(bitmap->mutex);
165 hbitmap_free_meta(bitmap->bitmap);
166 bitmap->meta = NULL;
167 qemu_mutex_unlock(bitmap->mutex);
170 int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
172 return bitmap->size;
175 const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
177 return bitmap->name;
180 /* Called with BQL taken. */
181 bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
183 return bitmap->successor;
186 /* Called with BQL taken. */
187 bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
189 return !(bitmap->disabled || bitmap->successor);
192 /* Called with BQL taken. */
193 DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
195 if (bdrv_dirty_bitmap_frozen(bitmap)) {
196 return DIRTY_BITMAP_STATUS_FROZEN;
197 } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
198 return DIRTY_BITMAP_STATUS_DISABLED;
199 } else {
200 return DIRTY_BITMAP_STATUS_ACTIVE;
205 * Create a successor bitmap destined to replace this bitmap after an operation.
206 * Requires that the bitmap is not frozen and has no successor.
207 * Called with BQL taken.
209 int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
210 BdrvDirtyBitmap *bitmap, Error **errp)
212 uint64_t granularity;
213 BdrvDirtyBitmap *child;
215 if (bdrv_dirty_bitmap_frozen(bitmap)) {
216 error_setg(errp, "Cannot create a successor for a bitmap that is "
217 "currently frozen");
218 return -1;
220 assert(!bitmap->successor);
222 /* Create an anonymous successor */
223 granularity = bdrv_dirty_bitmap_granularity(bitmap);
224 child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
225 if (!child) {
226 return -1;
229 /* Successor will be on or off based on our current state. */
230 child->disabled = bitmap->disabled;
232 /* Install the successor and freeze the parent */
233 bitmap->successor = child;
234 return 0;
238 * For a bitmap with a successor, yield our name to the successor,
239 * delete the old bitmap, and return a handle to the new bitmap.
240 * Called with BQL taken.
242 BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
243 BdrvDirtyBitmap *bitmap,
244 Error **errp)
246 char *name;
247 BdrvDirtyBitmap *successor = bitmap->successor;
249 if (successor == NULL) {
250 error_setg(errp, "Cannot relinquish control if "
251 "there's no successor present");
252 return NULL;
255 name = bitmap->name;
256 bitmap->name = NULL;
257 successor->name = name;
258 bitmap->successor = NULL;
259 successor->persistent = bitmap->persistent;
260 bitmap->persistent = false;
261 bdrv_release_dirty_bitmap(bs, bitmap);
263 return successor;
267 * In cases of failure where we can no longer safely delete the parent,
268 * we may wish to re-join the parent and child/successor.
269 * The merged parent will be un-frozen, but not explicitly re-enabled.
270 * Called with BQL taken.
272 BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
273 BdrvDirtyBitmap *parent,
274 Error **errp)
276 BdrvDirtyBitmap *successor = parent->successor;
278 if (!successor) {
279 error_setg(errp, "Cannot reclaim a successor when none is present");
280 return NULL;
283 if (!hbitmap_merge(parent->bitmap, successor->bitmap)) {
284 error_setg(errp, "Merging of parent and successor bitmap failed");
285 return NULL;
287 bdrv_release_dirty_bitmap(bs, successor);
288 parent->successor = NULL;
290 return parent;
294 * Truncates _all_ bitmaps attached to a BDS.
295 * Called with BQL taken.
297 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
299 BdrvDirtyBitmap *bitmap;
301 bdrv_dirty_bitmaps_lock(bs);
302 QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
303 assert(!bdrv_dirty_bitmap_frozen(bitmap));
304 assert(!bitmap->active_iterators);
305 hbitmap_truncate(bitmap->bitmap, bytes);
306 bitmap->size = bytes;
308 bdrv_dirty_bitmaps_unlock(bs);
311 static bool bdrv_dirty_bitmap_has_name(BdrvDirtyBitmap *bitmap)
313 return !!bdrv_dirty_bitmap_name(bitmap);
316 /* Called with BQL taken. */
317 static void bdrv_do_release_matching_dirty_bitmap(
318 BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
319 bool (*cond)(BdrvDirtyBitmap *bitmap))
321 BdrvDirtyBitmap *bm, *next;
322 bdrv_dirty_bitmaps_lock(bs);
323 QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
324 if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) {
325 assert(!bm->active_iterators);
326 assert(!bdrv_dirty_bitmap_frozen(bm));
327 assert(!bm->meta);
328 QLIST_REMOVE(bm, list);
329 hbitmap_free(bm->bitmap);
330 g_free(bm->name);
331 g_free(bm);
333 if (bitmap) {
334 goto out;
338 if (bitmap) {
339 abort();
342 out:
343 bdrv_dirty_bitmaps_unlock(bs);
346 /* Called with BQL taken. */
347 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
349 bdrv_do_release_matching_dirty_bitmap(bs, bitmap, NULL);
353 * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
354 * There must not be any frozen bitmaps attached.
355 * This function does not remove persistent bitmaps from the storage.
356 * Called with BQL taken.
358 void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
360 bdrv_do_release_matching_dirty_bitmap(bs, NULL, bdrv_dirty_bitmap_has_name);
364 * Release all persistent dirty bitmaps attached to a BDS (for use in
365 * bdrv_inactivate_recurse()).
366 * There must not be any frozen bitmaps attached.
367 * This function does not remove persistent bitmaps from the storage.
369 void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs)
371 bdrv_do_release_matching_dirty_bitmap(bs, NULL,
372 bdrv_dirty_bitmap_get_persistance);
376 * Remove persistent dirty bitmap from the storage if it exists.
377 * Absence of bitmap is not an error, because we have the following scenario:
378 * BdrvDirtyBitmap can have .persistent = true but not yet saved and have no
379 * stored version. For such bitmap bdrv_remove_persistent_dirty_bitmap() should
380 * not fail.
381 * This function doesn't release corresponding BdrvDirtyBitmap.
383 void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
384 const char *name,
385 Error **errp)
387 if (bs->drv && bs->drv->bdrv_remove_persistent_dirty_bitmap) {
388 bs->drv->bdrv_remove_persistent_dirty_bitmap(bs, name, errp);
392 /* Called with BQL taken. */
393 void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
395 assert(!bdrv_dirty_bitmap_frozen(bitmap));
396 bitmap->disabled = true;
399 /* Called with BQL taken. */
400 void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
402 assert(!bdrv_dirty_bitmap_frozen(bitmap));
403 bitmap->disabled = false;
406 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
408 BdrvDirtyBitmap *bm;
409 BlockDirtyInfoList *list = NULL;
410 BlockDirtyInfoList **plist = &list;
412 bdrv_dirty_bitmaps_lock(bs);
413 QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
414 BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
415 BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
416 info->count = bdrv_get_dirty_count(bm);
417 info->granularity = bdrv_dirty_bitmap_granularity(bm);
418 info->has_name = !!bm->name;
419 info->name = g_strdup(bm->name);
420 info->status = bdrv_dirty_bitmap_status(bm);
421 entry->value = info;
422 *plist = entry;
423 plist = &entry->next;
425 bdrv_dirty_bitmaps_unlock(bs);
427 return list;
430 /* Called within bdrv_dirty_bitmap_lock..unlock */
431 bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
432 int64_t offset)
434 if (bitmap) {
435 return hbitmap_get(bitmap->bitmap, offset);
436 } else {
437 return false;
442 * Chooses a default granularity based on the existing cluster size,
443 * but clamped between [4K, 64K]. Defaults to 64K in the case that there
444 * is no cluster size information available.
446 uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
448 BlockDriverInfo bdi;
449 uint32_t granularity;
451 if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size > 0) {
452 granularity = MAX(4096, bdi.cluster_size);
453 granularity = MIN(65536, granularity);
454 } else {
455 granularity = 65536;
458 return granularity;
461 uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
463 return 1U << hbitmap_granularity(bitmap->bitmap);
466 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
468 BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
469 hbitmap_iter_init(&iter->hbi, bitmap->bitmap, 0);
470 iter->bitmap = bitmap;
471 bitmap->active_iterators++;
472 return iter;
475 BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
477 BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
478 hbitmap_iter_init(&iter->hbi, bitmap->meta, 0);
479 iter->bitmap = bitmap;
480 bitmap->active_iterators++;
481 return iter;
484 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
486 if (!iter) {
487 return;
489 assert(iter->bitmap->active_iterators > 0);
490 iter->bitmap->active_iterators--;
491 g_free(iter);
494 int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
496 return hbitmap_iter_next(&iter->hbi);
499 /* Called within bdrv_dirty_bitmap_lock..unlock */
500 void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
501 int64_t offset, int64_t bytes)
503 assert(bdrv_dirty_bitmap_enabled(bitmap));
504 assert(!bdrv_dirty_bitmap_readonly(bitmap));
505 hbitmap_set(bitmap->bitmap, offset, bytes);
508 void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
509 int64_t offset, int64_t bytes)
511 bdrv_dirty_bitmap_lock(bitmap);
512 bdrv_set_dirty_bitmap_locked(bitmap, offset, bytes);
513 bdrv_dirty_bitmap_unlock(bitmap);
516 /* Called within bdrv_dirty_bitmap_lock..unlock */
517 void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
518 int64_t offset, int64_t bytes)
520 assert(bdrv_dirty_bitmap_enabled(bitmap));
521 assert(!bdrv_dirty_bitmap_readonly(bitmap));
522 hbitmap_reset(bitmap->bitmap, offset, bytes);
525 void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
526 int64_t offset, int64_t bytes)
528 bdrv_dirty_bitmap_lock(bitmap);
529 bdrv_reset_dirty_bitmap_locked(bitmap, offset, bytes);
530 bdrv_dirty_bitmap_unlock(bitmap);
533 void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
535 assert(bdrv_dirty_bitmap_enabled(bitmap));
536 assert(!bdrv_dirty_bitmap_readonly(bitmap));
537 bdrv_dirty_bitmap_lock(bitmap);
538 if (!out) {
539 hbitmap_reset_all(bitmap->bitmap);
540 } else {
541 HBitmap *backup = bitmap->bitmap;
542 bitmap->bitmap = hbitmap_alloc(bitmap->size,
543 hbitmap_granularity(backup));
544 *out = backup;
546 bdrv_dirty_bitmap_unlock(bitmap);
549 void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
551 HBitmap *tmp = bitmap->bitmap;
552 assert(bdrv_dirty_bitmap_enabled(bitmap));
553 assert(!bdrv_dirty_bitmap_readonly(bitmap));
554 bitmap->bitmap = in;
555 hbitmap_free(tmp);
558 uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
559 uint64_t offset, uint64_t bytes)
561 return hbitmap_serialization_size(bitmap->bitmap, offset, bytes);
564 uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
566 return hbitmap_serialization_align(bitmap->bitmap);
569 void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
570 uint8_t *buf, uint64_t offset,
571 uint64_t bytes)
573 hbitmap_serialize_part(bitmap->bitmap, buf, offset, bytes);
576 void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
577 uint8_t *buf, uint64_t offset,
578 uint64_t bytes, bool finish)
580 hbitmap_deserialize_part(bitmap->bitmap, buf, offset, bytes, finish);
583 void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
584 uint64_t offset, uint64_t bytes,
585 bool finish)
587 hbitmap_deserialize_zeroes(bitmap->bitmap, offset, bytes, finish);
590 void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
591 uint64_t offset, uint64_t bytes,
592 bool finish)
594 hbitmap_deserialize_ones(bitmap->bitmap, offset, bytes, finish);
597 void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
599 hbitmap_deserialize_finish(bitmap->bitmap);
602 void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
604 BdrvDirtyBitmap *bitmap;
606 if (QLIST_EMPTY(&bs->dirty_bitmaps)) {
607 return;
610 bdrv_dirty_bitmaps_lock(bs);
611 QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
612 if (!bdrv_dirty_bitmap_enabled(bitmap)) {
613 continue;
615 assert(!bdrv_dirty_bitmap_readonly(bitmap));
616 hbitmap_set(bitmap->bitmap, offset, bytes);
618 bdrv_dirty_bitmaps_unlock(bs);
622 * Advance a BdrvDirtyBitmapIter to an arbitrary offset.
624 void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t offset)
626 hbitmap_iter_init(&iter->hbi, iter->hbi.hb, offset);
629 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
631 return hbitmap_count(bitmap->bitmap);
634 int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
636 return hbitmap_count(bitmap->meta);
639 bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap)
641 return bitmap->readonly;
644 /* Called with BQL taken. */
645 void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value)
647 qemu_mutex_lock(bitmap->mutex);
648 bitmap->readonly = value;
649 qemu_mutex_unlock(bitmap->mutex);
652 bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
654 BdrvDirtyBitmap *bm;
655 QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
656 if (bm->readonly) {
657 return true;
661 return false;
664 /* Called with BQL taken. */
665 void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
667 qemu_mutex_lock(bitmap->mutex);
668 bitmap->persistent = persistent;
669 qemu_mutex_unlock(bitmap->mutex);
672 bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
674 return bitmap->persistent;
677 bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
679 BdrvDirtyBitmap *bm;
680 QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
681 if (bm->persistent && !bm->readonly) {
682 return true;
686 return false;
689 BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
690 BdrvDirtyBitmap *bitmap)
692 return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) :
693 QLIST_NEXT(bitmap, list);
696 char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
698 return hbitmap_sha256(bitmap->bitmap, errp);
701 int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset)
703 return hbitmap_next_zero(bitmap->bitmap, offset);