1 /* 2 * Block Dirty Bitmap 3 * 4 * Copyright (c) 2016 Red Hat. Inc 5 * 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: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 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. 23 */ 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" 30 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(). 38 */ 39 struct BdrvDirtyBitmap { 40 QemuMutex *mutex; 41 HBitmap *bitmap; /* Dirty sector 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 (Number of sectors) */ 46 bool disabled; /* Bitmap is read-only */ 47 int active_iterators; /* How many iterators are active */ 48 QLIST_ENTRY(BdrvDirtyBitmap) list; 49 }; 50 51 struct BdrvDirtyBitmapIter { 52 HBitmapIter hbi; 53 BdrvDirtyBitmap *bitmap; 54 }; 55 56 static inline void bdrv_dirty_bitmaps_lock(BlockDriverState *bs) 57 { 58 qemu_mutex_lock(&bs->dirty_bitmap_mutex); 59 } 60 61 static inline void bdrv_dirty_bitmaps_unlock(BlockDriverState *bs) 62 { 63 qemu_mutex_unlock(&bs->dirty_bitmap_mutex); 64 } 65 66 void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap) 67 { 68 qemu_mutex_lock(bitmap->mutex); 69 } 70 71 void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap) 72 { 73 qemu_mutex_unlock(bitmap->mutex); 74 } 75 76 /* Called with BQL or dirty_bitmap lock taken. */ 77 BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name) 78 { 79 BdrvDirtyBitmap *bm; 80 81 assert(name); 82 QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { 83 if (bm->name && !strcmp(name, bm->name)) { 84 return bm; 85 } 86 } 87 return NULL; 88 } 89 90 /* Called with BQL taken. */ 91 void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) 92 { 93 assert(!bdrv_dirty_bitmap_frozen(bitmap)); 94 g_free(bitmap->name); 95 bitmap->name = NULL; 96 } 97 98 /* Called with BQL taken. */ 99 BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, 100 uint32_t granularity, 101 const char *name, 102 Error **errp) 103 { 104 int64_t bitmap_size; 105 BdrvDirtyBitmap *bitmap; 106 uint32_t sector_granularity; 107 108 assert((granularity & (granularity - 1)) == 0); 109 110 if (name && bdrv_find_dirty_bitmap(bs, name)) { 111 error_setg(errp, "Bitmap already exists: %s", name); 112 return NULL; 113 } 114 sector_granularity = granularity >> BDRV_SECTOR_BITS; 115 assert(sector_granularity); 116 bitmap_size = bdrv_nb_sectors(bs); 117 if (bitmap_size < 0) { 118 error_setg_errno(errp, -bitmap_size, "could not get length of device"); 119 errno = -bitmap_size; 120 return NULL; 121 } 122 bitmap = g_new0(BdrvDirtyBitmap, 1); 123 bitmap->mutex = &bs->dirty_bitmap_mutex; 124 bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity)); 125 bitmap->size = bitmap_size; 126 bitmap->name = g_strdup(name); 127 bitmap->disabled = false; 128 bdrv_dirty_bitmaps_lock(bs); 129 QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list); 130 bdrv_dirty_bitmaps_unlock(bs); 131 return bitmap; 132 } 133 134 /* bdrv_create_meta_dirty_bitmap 135 * 136 * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e. 137 * when a dirty status bit in @bitmap is changed (either from reset to set or 138 * the other way around), its respective meta dirty bitmap bit will be marked 139 * dirty as well. 140 * 141 * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap. 142 * @chunk_size: how many bytes of bitmap data does each bit in the meta bitmap 143 * track. 144 */ 145 void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap, 146 int chunk_size) 147 { 148 assert(!bitmap->meta); 149 qemu_mutex_lock(bitmap->mutex); 150 bitmap->meta = hbitmap_create_meta(bitmap->bitmap, 151 chunk_size * BITS_PER_BYTE); 152 qemu_mutex_unlock(bitmap->mutex); 153 } 154 155 void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap) 156 { 157 assert(bitmap->meta); 158 qemu_mutex_lock(bitmap->mutex); 159 hbitmap_free_meta(bitmap->bitmap); 160 bitmap->meta = NULL; 161 qemu_mutex_unlock(bitmap->mutex); 162 } 163 164 int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs, 165 BdrvDirtyBitmap *bitmap, int64_t sector, 166 int nb_sectors) 167 { 168 uint64_t i; 169 int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta); 170 171 /* To optimize: we can make hbitmap to internally check the range in a 172 * coarse level, or at least do it word by word. */ 173 for (i = sector; i < sector + nb_sectors; i += sectors_per_bit) { 174 if (hbitmap_get(bitmap->meta, i)) { 175 return true; 176 } 177 } 178 return false; 179 } 180 181 int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs, 182 BdrvDirtyBitmap *bitmap, int64_t sector, 183 int nb_sectors) 184 { 185 bool dirty; 186 187 qemu_mutex_lock(bitmap->mutex); 188 dirty = bdrv_dirty_bitmap_get_meta_locked(bs, bitmap, sector, nb_sectors); 189 qemu_mutex_unlock(bitmap->mutex); 190 191 return dirty; 192 } 193 194 void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs, 195 BdrvDirtyBitmap *bitmap, int64_t sector, 196 int nb_sectors) 197 { 198 qemu_mutex_lock(bitmap->mutex); 199 hbitmap_reset(bitmap->meta, sector, nb_sectors); 200 qemu_mutex_unlock(bitmap->mutex); 201 } 202 203 int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap) 204 { 205 return bitmap->size; 206 } 207 208 const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap) 209 { 210 return bitmap->name; 211 } 212 213 /* Called with BQL taken. */ 214 bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap) 215 { 216 return bitmap->successor; 217 } 218 219 /* Called with BQL taken. */ 220 bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) 221 { 222 return !(bitmap->disabled || bitmap->successor); 223 } 224 225 /* Called with BQL taken. */ 226 DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) 227 { 228 if (bdrv_dirty_bitmap_frozen(bitmap)) { 229 return DIRTY_BITMAP_STATUS_FROZEN; 230 } else if (!bdrv_dirty_bitmap_enabled(bitmap)) { 231 return DIRTY_BITMAP_STATUS_DISABLED; 232 } else { 233 return DIRTY_BITMAP_STATUS_ACTIVE; 234 } 235 } 236 237 /** 238 * Create a successor bitmap destined to replace this bitmap after an operation. 239 * Requires that the bitmap is not frozen and has no successor. 240 * Called with BQL taken. 241 */ 242 int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, 243 BdrvDirtyBitmap *bitmap, Error **errp) 244 { 245 uint64_t granularity; 246 BdrvDirtyBitmap *child; 247 248 if (bdrv_dirty_bitmap_frozen(bitmap)) { 249 error_setg(errp, "Cannot create a successor for a bitmap that is " 250 "currently frozen"); 251 return -1; 252 } 253 assert(!bitmap->successor); 254 255 /* Create an anonymous successor */ 256 granularity = bdrv_dirty_bitmap_granularity(bitmap); 257 child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp); 258 if (!child) { 259 return -1; 260 } 261 262 /* Successor will be on or off based on our current state. */ 263 child->disabled = bitmap->disabled; 264 265 /* Install the successor and freeze the parent */ 266 bitmap->successor = child; 267 return 0; 268 } 269 270 /** 271 * For a bitmap with a successor, yield our name to the successor, 272 * delete the old bitmap, and return a handle to the new bitmap. 273 * Called with BQL taken. 274 */ 275 BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, 276 BdrvDirtyBitmap *bitmap, 277 Error **errp) 278 { 279 char *name; 280 BdrvDirtyBitmap *successor = bitmap->successor; 281 282 if (successor == NULL) { 283 error_setg(errp, "Cannot relinquish control if " 284 "there's no successor present"); 285 return NULL; 286 } 287 288 name = bitmap->name; 289 bitmap->name = NULL; 290 successor->name = name; 291 bitmap->successor = NULL; 292 bdrv_release_dirty_bitmap(bs, bitmap); 293 294 return successor; 295 } 296 297 /** 298 * In cases of failure where we can no longer safely delete the parent, 299 * we may wish to re-join the parent and child/successor. 300 * The merged parent will be un-frozen, but not explicitly re-enabled. 301 * Called with BQL taken. 302 */ 303 BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs, 304 BdrvDirtyBitmap *parent, 305 Error **errp) 306 { 307 BdrvDirtyBitmap *successor = parent->successor; 308 309 if (!successor) { 310 error_setg(errp, "Cannot reclaim a successor when none is present"); 311 return NULL; 312 } 313 314 if (!hbitmap_merge(parent->bitmap, successor->bitmap)) { 315 error_setg(errp, "Merging of parent and successor bitmap failed"); 316 return NULL; 317 } 318 bdrv_release_dirty_bitmap(bs, successor); 319 parent->successor = NULL; 320 321 return parent; 322 } 323 324 /** 325 * Truncates _all_ bitmaps attached to a BDS. 326 * Called with BQL taken. 327 */ 328 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs) 329 { 330 BdrvDirtyBitmap *bitmap; 331 uint64_t size = bdrv_nb_sectors(bs); 332 333 bdrv_dirty_bitmaps_lock(bs); 334 QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { 335 assert(!bdrv_dirty_bitmap_frozen(bitmap)); 336 assert(!bitmap->active_iterators); 337 hbitmap_truncate(bitmap->bitmap, size); 338 bitmap->size = size; 339 } 340 bdrv_dirty_bitmaps_unlock(bs); 341 } 342 343 /* Called with BQL taken. */ 344 static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs, 345 BdrvDirtyBitmap *bitmap, 346 bool only_named) 347 { 348 BdrvDirtyBitmap *bm, *next; 349 bdrv_dirty_bitmaps_lock(bs); 350 QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { 351 if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) { 352 assert(!bm->active_iterators); 353 assert(!bdrv_dirty_bitmap_frozen(bm)); 354 assert(!bm->meta); 355 QLIST_REMOVE(bm, list); 356 hbitmap_free(bm->bitmap); 357 g_free(bm->name); 358 g_free(bm); 359 360 if (bitmap) { 361 goto out; 362 } 363 } 364 } 365 if (bitmap) { 366 abort(); 367 } 368 369 out: 370 bdrv_dirty_bitmaps_unlock(bs); 371 } 372 373 /* Called with BQL taken. */ 374 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) 375 { 376 bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false); 377 } 378 379 /** 380 * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()). 381 * There must not be any frozen bitmaps attached. 382 * Called with BQL taken. 383 */ 384 void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) 385 { 386 bdrv_do_release_matching_dirty_bitmap(bs, NULL, true); 387 } 388 389 /* Called with BQL taken. */ 390 void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) 391 { 392 assert(!bdrv_dirty_bitmap_frozen(bitmap)); 393 bitmap->disabled = true; 394 } 395 396 /* Called with BQL taken. */ 397 void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap) 398 { 399 assert(!bdrv_dirty_bitmap_frozen(bitmap)); 400 bitmap->disabled = false; 401 } 402 403 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) 404 { 405 BdrvDirtyBitmap *bm; 406 BlockDirtyInfoList *list = NULL; 407 BlockDirtyInfoList **plist = &list; 408 409 bdrv_dirty_bitmaps_lock(bs); 410 QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { 411 BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1); 412 BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1); 413 info->count = bdrv_get_dirty_count(bm); 414 info->granularity = bdrv_dirty_bitmap_granularity(bm); 415 info->has_name = !!bm->name; 416 info->name = g_strdup(bm->name); 417 info->status = bdrv_dirty_bitmap_status(bm); 418 entry->value = info; 419 *plist = entry; 420 plist = &entry->next; 421 } 422 bdrv_dirty_bitmaps_unlock(bs); 423 424 return list; 425 } 426 427 /* Called within bdrv_dirty_bitmap_lock..unlock */ 428 int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, 429 int64_t sector) 430 { 431 if (bitmap) { 432 return hbitmap_get(bitmap->bitmap, sector); 433 } else { 434 return 0; 435 } 436 } 437 438 /** 439 * Chooses a default granularity based on the existing cluster size, 440 * but clamped between [4K, 64K]. Defaults to 64K in the case that there 441 * is no cluster size information available. 442 */ 443 uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs) 444 { 445 BlockDriverInfo bdi; 446 uint32_t granularity; 447 448 if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size > 0) { 449 granularity = MAX(4096, bdi.cluster_size); 450 granularity = MIN(65536, granularity); 451 } else { 452 granularity = 65536; 453 } 454 455 return granularity; 456 } 457 458 uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap) 459 { 460 return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap); 461 } 462 463 uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap) 464 { 465 return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->meta); 466 } 467 468 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap, 469 uint64_t first_sector) 470 { 471 BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1); 472 hbitmap_iter_init(&iter->hbi, bitmap->bitmap, first_sector); 473 iter->bitmap = bitmap; 474 bitmap->active_iterators++; 475 return iter; 476 } 477 478 BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap) 479 { 480 BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1); 481 hbitmap_iter_init(&iter->hbi, bitmap->meta, 0); 482 iter->bitmap = bitmap; 483 bitmap->active_iterators++; 484 return iter; 485 } 486 487 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter) 488 { 489 if (!iter) { 490 return; 491 } 492 assert(iter->bitmap->active_iterators > 0); 493 iter->bitmap->active_iterators--; 494 g_free(iter); 495 } 496 497 int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter) 498 { 499 return hbitmap_iter_next(&iter->hbi); 500 } 501 502 /* Called within bdrv_dirty_bitmap_lock..unlock */ 503 void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, 504 int64_t cur_sector, int64_t nr_sectors) 505 { 506 assert(bdrv_dirty_bitmap_enabled(bitmap)); 507 hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); 508 } 509 510 void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap, 511 int64_t cur_sector, int64_t nr_sectors) 512 { 513 bdrv_dirty_bitmap_lock(bitmap); 514 bdrv_set_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors); 515 bdrv_dirty_bitmap_unlock(bitmap); 516 } 517 518 /* Called within bdrv_dirty_bitmap_lock..unlock */ 519 void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, 520 int64_t cur_sector, int64_t nr_sectors) 521 { 522 assert(bdrv_dirty_bitmap_enabled(bitmap)); 523 hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors); 524 } 525 526 void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, 527 int64_t cur_sector, int64_t nr_sectors) 528 { 529 bdrv_dirty_bitmap_lock(bitmap); 530 bdrv_reset_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors); 531 bdrv_dirty_bitmap_unlock(bitmap); 532 } 533 534 void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) 535 { 536 assert(bdrv_dirty_bitmap_enabled(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; 545 } 546 bdrv_dirty_bitmap_unlock(bitmap); 547 } 548 549 void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in) 550 { 551 HBitmap *tmp = bitmap->bitmap; 552 assert(bdrv_dirty_bitmap_enabled(bitmap)); 553 bitmap->bitmap = in; 554 hbitmap_free(tmp); 555 } 556 557 uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap, 558 uint64_t start, uint64_t count) 559 { 560 return hbitmap_serialization_size(bitmap->bitmap, start, count); 561 } 562 563 uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap) 564 { 565 return hbitmap_serialization_granularity(bitmap->bitmap); 566 } 567 568 void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap, 569 uint8_t *buf, uint64_t start, 570 uint64_t count) 571 { 572 hbitmap_serialize_part(bitmap->bitmap, buf, start, count); 573 } 574 575 void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap, 576 uint8_t *buf, uint64_t start, 577 uint64_t count, bool finish) 578 { 579 hbitmap_deserialize_part(bitmap->bitmap, buf, start, count, finish); 580 } 581 582 void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap, 583 uint64_t start, uint64_t count, 584 bool finish) 585 { 586 hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish); 587 } 588 589 void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap) 590 { 591 hbitmap_deserialize_finish(bitmap->bitmap); 592 } 593 594 void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, 595 int64_t nr_sectors) 596 { 597 BdrvDirtyBitmap *bitmap; 598 599 if (QLIST_EMPTY(&bs->dirty_bitmaps)) { 600 return; 601 } 602 603 bdrv_dirty_bitmaps_lock(bs); 604 QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { 605 if (!bdrv_dirty_bitmap_enabled(bitmap)) { 606 continue; 607 } 608 hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors); 609 } 610 bdrv_dirty_bitmaps_unlock(bs); 611 } 612 613 /** 614 * Advance a BdrvDirtyBitmapIter to an arbitrary offset. 615 */ 616 void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t sector_num) 617 { 618 hbitmap_iter_init(&iter->hbi, iter->hbi.hb, sector_num); 619 } 620 621 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap) 622 { 623 return hbitmap_count(bitmap->bitmap); 624 } 625 626 int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap) 627 { 628 return hbitmap_count(bitmap->meta); 629 } 630