qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-05-26-v3' into staging

bitmaps patches for 2020-05-26

- fix non-blockdev migration of bitmaps when mirror job is in use
- add bitmap sizing to 'qemu-img measure'
- add 'qemu-img convert --bitmaps'

# gpg: Signature made Thu 28 May 2020 19:16:47 BST
# gpg: using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full]
# gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full]
# gpg: aka "[jpeg image of size 6874]" [full]
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-bitmaps-2020-05-26-v3:
iotests: Add test 291 to for qemu-img bitmap coverage
qemu-img: Add convert --bitmaps option
qemu-img: Factor out code for merging bitmaps
qcow2: Expose bitmaps' size during measure
iotests: Fix test 178
migration: forbid bitmap migration by generated node-name
migration: add_bitmaps_to_list: check disk name once
iotests: 194: test also migration of dirty bitmap
migration: fix bitmaps pre-blockdev migration with mirror job
block/dirty-bitmap: add bdrv_has_named_bitmaps helper
migration: refactor init_dirty_bitmap_migration

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

+576 -71
+1 -1
block/crypto.c
··· 552 552 * Unallocated blocks are still encrypted so allocation status makes no 553 553 * difference to the file size. 554 554 */ 555 - info = g_new(BlockMeasureInfo, 1); 555 + info = g_new0(BlockMeasureInfo, 1); 556 556 info->fully_allocated = luks_payload_size + size; 557 557 info->required = luks_payload_size + size; 558 558 return info;
+13
block/dirty-bitmap.c
··· 818 818 return false; 819 819 } 820 820 821 + bool bdrv_has_named_bitmaps(BlockDriverState *bs) 822 + { 823 + BdrvDirtyBitmap *bm; 824 + 825 + QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { 826 + if (bdrv_dirty_bitmap_name(bm)) { 827 + return true; 828 + } 829 + } 830 + 831 + return false; 832 + } 833 + 821 834 /* Called with BQL taken. */ 822 835 void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent) 823 836 {
+36
block/qcow2-bitmap.c
··· 1755 1755 1756 1756 return s->qcow_version >= 3; 1757 1757 } 1758 + 1759 + /* 1760 + * Compute the space required for bitmaps in @bs. 1761 + * 1762 + * The computation is based as if copying to a new image with the 1763 + * given @cluster_size, which may differ from the cluster size in @bs. 1764 + */ 1765 + uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, 1766 + uint32_t cluster_size) 1767 + { 1768 + uint64_t bitmaps_size = 0; 1769 + BdrvDirtyBitmap *bm; 1770 + size_t bitmap_dir_size = 0; 1771 + 1772 + FOR_EACH_DIRTY_BITMAP(bs, bm) { 1773 + if (bdrv_dirty_bitmap_get_persistence(bm)) { 1774 + const char *name = bdrv_dirty_bitmap_name(bm); 1775 + uint32_t granularity = bdrv_dirty_bitmap_granularity(bm); 1776 + uint64_t bmbytes = 1777 + get_bitmap_bytes_needed(bdrv_dirty_bitmap_size(bm), 1778 + granularity); 1779 + uint64_t bmclusters = DIV_ROUND_UP(bmbytes, cluster_size); 1780 + 1781 + /* Assume the entire bitmap is allocated */ 1782 + bitmaps_size += bmclusters * cluster_size; 1783 + /* Also reserve space for the bitmap table entries */ 1784 + bitmaps_size += ROUND_UP(bmclusters * sizeof(uint64_t), 1785 + cluster_size); 1786 + /* And space for contribution to bitmap directory size */ 1787 + bitmap_dir_size += calc_dir_entry_size(strlen(name), 0); 1788 + } 1789 + } 1790 + bitmaps_size += ROUND_UP(bitmap_dir_size, cluster_size); 1791 + 1792 + return bitmaps_size; 1793 + }
+11 -3
block/qcow2.c
··· 4953 4953 required = virtual_size; 4954 4954 } 4955 4955 4956 - info = g_new(BlockMeasureInfo, 1); 4956 + info = g_new0(BlockMeasureInfo, 1); 4957 4957 info->fully_allocated = 4958 4958 qcow2_calc_prealloc_size(virtual_size, cluster_size, 4959 4959 ctz32(refcount_bits)) + luks_payload_size; 4960 4960 4961 - /* Remove data clusters that are not required. This overestimates the 4961 + /* 4962 + * Remove data clusters that are not required. This overestimates the 4962 4963 * required size because metadata needed for the fully allocated file is 4963 - * still counted. 4964 + * still counted. Show bitmaps only if both source and destination 4965 + * would support them. 4964 4966 */ 4965 4967 info->required = info->fully_allocated - virtual_size + required; 4968 + info->has_bitmaps = version >= 3 && in_bs && 4969 + bdrv_supports_persistent_dirty_bitmap(in_bs); 4970 + if (info->has_bitmaps) { 4971 + info->bitmaps = qcow2_get_persistent_dirty_bitmap_size(in_bs, 4972 + cluster_size); 4973 + } 4966 4974 return info; 4967 4975 4968 4976 err:
+2
block/qcow2.h
··· 783 783 const char *name, 784 784 Error **errp); 785 785 bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); 786 + uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, 787 + uint32_t cluster_size); 786 788 787 789 ssize_t coroutine_fn 788 790 qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
+1 -1
block/raw-format.c
··· 359 359 BDRV_SECTOR_SIZE); 360 360 } 361 361 362 - info = g_new(BlockMeasureInfo, 1); 362 + info = g_new0(BlockMeasureInfo, 1); 363 363 info->required = required; 364 364 365 365 /* Unallocated sectors count towards the file size in raw images */
+12 -1
docs/tools/qemu-img.rst
··· 162 162 163 163 .. program:: qemu-img-convert 164 164 165 + .. option:: --bitmaps 166 + 167 + Additionally copy all persistent bitmaps from the top layer of the source 168 + 165 169 .. option:: -n 166 170 167 171 Skip the creation of the target volume ··· 397 401 4 398 402 Error on reading data 399 403 400 - .. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME 404 + .. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME 401 405 402 406 Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* 403 407 to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can ··· 616 620 617 621 required size: 524288 618 622 fully allocated size: 1074069504 623 + bitmaps size: 0 619 624 620 625 The ``required size`` is the file size of the new image. It may be smaller 621 626 than the virtual disk size if the image format supports compact representation. ··· 624 629 been written to all sectors. This is the maximum size that the image file can 625 630 occupy with the exception of internal snapshots, dirty bitmaps, vmstate data, 626 631 and other advanced image format features. 632 + 633 + The ``bitmaps size`` is the additional size required in order to 634 + copy bitmaps from a source image in addition to the guest-visible 635 + data; the line is omitted if either source or destination lacks 636 + bitmap support, or 0 if bitmaps are supported but there is nothing 637 + to copy. 627 638 628 639 .. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME 629 640
+1
include/block/dirty-bitmap.h
··· 95 95 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes); 96 96 bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); 97 97 bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); 98 + bool bdrv_has_named_bitmaps(BlockDriverState *bs); 98 99 bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); 99 100 bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap); 100 101 bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap);
+97 -33
migration/block-dirty-bitmap.c
··· 268 268 } 269 269 270 270 /* Called with iothread lock taken. */ 271 + static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) 272 + { 273 + BdrvDirtyBitmap *bitmap; 274 + DirtyBitmapMigBitmapState *dbms; 275 + Error *local_err = NULL; 276 + 277 + bitmap = bdrv_dirty_bitmap_first(bs); 278 + if (!bitmap) { 279 + return 0; 280 + } 281 + 282 + if (!bs_name || strcmp(bs_name, "") == 0) { 283 + error_report("Bitmap '%s' in unnamed node can't be migrated", 284 + bdrv_dirty_bitmap_name(bitmap)); 285 + return -1; 286 + } 287 + 288 + if (bs_name[0] == '#') { 289 + error_report("Bitmap '%s' in a node with auto-generated " 290 + "name '%s' can't be migrated", 291 + bdrv_dirty_bitmap_name(bitmap), bs_name); 292 + return -1; 293 + } 294 + 295 + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { 296 + if (!bdrv_dirty_bitmap_name(bitmap)) { 297 + continue; 298 + } 299 + 300 + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, &local_err)) { 301 + error_report_err(local_err); 302 + return -1; 303 + } 304 + 305 + bdrv_ref(bs); 306 + bdrv_dirty_bitmap_set_busy(bitmap, true); 307 + 308 + dbms = g_new0(DirtyBitmapMigBitmapState, 1); 309 + dbms->bs = bs; 310 + dbms->node_name = bs_name; 311 + dbms->bitmap = bitmap; 312 + dbms->total_sectors = bdrv_nb_sectors(bs); 313 + dbms->sectors_per_chunk = CHUNK_SIZE * 8 * 314 + bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; 315 + if (bdrv_dirty_bitmap_enabled(bitmap)) { 316 + dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED; 317 + } 318 + if (bdrv_dirty_bitmap_get_persistence(bitmap)) { 319 + dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; 320 + } 321 + 322 + QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list, 323 + dbms, entry); 324 + } 325 + 326 + return 0; 327 + } 328 + 329 + /* Called with iothread lock taken. */ 271 330 static int init_dirty_bitmap_migration(void) 272 331 { 273 332 BlockDriverState *bs; 274 - BdrvDirtyBitmap *bitmap; 275 333 DirtyBitmapMigBitmapState *dbms; 276 - Error *local_err = NULL; 334 + GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL); 335 + BlockBackend *blk; 277 336 278 337 dirty_bitmap_mig_state.bulk_completed = false; 279 338 dirty_bitmap_mig_state.prev_bs = NULL; 280 339 dirty_bitmap_mig_state.prev_bitmap = NULL; 281 340 dirty_bitmap_mig_state.no_bitmaps = false; 282 341 283 - for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) { 284 - const char *name = bdrv_get_device_or_node_name(bs); 342 + /* 343 + * Use blockdevice name for direct (or filtered) children of named block 344 + * backends. 345 + */ 346 + for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { 347 + const char *name = blk_name(blk); 285 348 286 - FOR_EACH_DIRTY_BITMAP(bs, bitmap) { 287 - if (!bdrv_dirty_bitmap_name(bitmap)) { 288 - continue; 289 - } 349 + if (!name || strcmp(name, "") == 0) { 350 + continue; 351 + } 290 352 291 - if (!name || strcmp(name, "") == 0) { 292 - error_report("Found bitmap '%s' in unnamed node %p. It can't " 293 - "be migrated", bdrv_dirty_bitmap_name(bitmap), bs); 294 - goto fail; 353 + bs = blk_bs(blk); 354 + 355 + /* Skip filters without bitmaps */ 356 + while (bs && bs->drv && bs->drv->is_filter && 357 + !bdrv_has_named_bitmaps(bs)) 358 + { 359 + if (bs->backing) { 360 + bs = bs->backing->bs; 361 + } else if (bs->file) { 362 + bs = bs->file->bs; 363 + } else { 364 + bs = NULL; 295 365 } 366 + } 296 367 297 - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, 298 - &local_err)) { 299 - error_report_err(local_err); 368 + if (bs && bs->drv && !bs->drv->is_filter) { 369 + if (add_bitmaps_to_list(bs, name)) { 300 370 goto fail; 301 371 } 302 - 303 - bdrv_ref(bs); 304 - bdrv_dirty_bitmap_set_busy(bitmap, true); 372 + g_hash_table_add(handled_by_blk, bs); 373 + } 374 + } 305 375 306 - dbms = g_new0(DirtyBitmapMigBitmapState, 1); 307 - dbms->bs = bs; 308 - dbms->node_name = name; 309 - dbms->bitmap = bitmap; 310 - dbms->total_sectors = bdrv_nb_sectors(bs); 311 - dbms->sectors_per_chunk = CHUNK_SIZE * 8 * 312 - bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; 313 - if (bdrv_dirty_bitmap_enabled(bitmap)) { 314 - dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED; 315 - } 316 - if (bdrv_dirty_bitmap_get_persistence(bitmap)) { 317 - dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; 318 - } 376 + for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) { 377 + if (g_hash_table_contains(handled_by_blk, bs)) { 378 + continue; 379 + } 319 380 320 - QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list, 321 - dbms, entry); 381 + if (add_bitmaps_to_list(bs, bdrv_get_node_name(bs))) { 382 + goto fail; 322 383 } 323 384 } 324 385 ··· 331 392 dirty_bitmap_mig_state.no_bitmaps = true; 332 393 } 333 394 395 + g_hash_table_destroy(handled_by_blk); 396 + 334 397 return 0; 335 398 336 399 fail: 400 + g_hash_table_destroy(handled_by_blk); 337 401 dirty_bitmap_mig_cleanup(); 338 402 339 403 return -1;
+11 -5
qapi/block-core.json
··· 636 636 # efficiently so file size may be smaller than virtual disk size. 637 637 # 638 638 # The values are upper bounds that are guaranteed to fit the new image file. 639 - # Subsequent modification, such as internal snapshot or bitmap creation, may 640 - # require additional space and is not covered here. 639 + # Subsequent modification, such as internal snapshot or further bitmap 640 + # creation, may require additional space and is not covered here. 641 641 # 642 - # @required: Size required for a new image file, in bytes. 642 + # @required: Size required for a new image file, in bytes, when copying just 643 + # allocated guest-visible contents. 643 644 # 644 645 # @fully-allocated: Image file size, in bytes, once data has been written 645 - # to all sectors. 646 + # to all sectors, when copying just guest-visible contents. 647 + # 648 + # @bitmaps: Additional size required if all the top-level bitmap metadata 649 + # in the source image were to be copied to the destination, 650 + # present only when source and destination both support 651 + # persistent bitmaps. (since 5.1) 646 652 # 647 653 # Since: 2.10 648 654 ## 649 655 { 'struct': 'BlockMeasureInfo', 650 - 'data': {'required': 'int', 'fully-allocated': 'int'} } 656 + 'data': {'required': 'int', 'fully-allocated': 'int', '*bitmaps': 'int'} } 651 657 652 658 ## 653 659 # @query-block:
+2 -2
qemu-img-cmds.hx
··· 46 46 ERST 47 47 48 48 DEF("convert", img_convert, 49 - "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") 49 + "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") 50 50 SRST 51 - .. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME 51 + .. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME 52 52 ERST 53 53 54 54 DEF("create", img_create,
+91 -16
qemu-img.c
··· 78 78 OPTION_ENABLE = 272, 79 79 OPTION_DISABLE = 273, 80 80 OPTION_MERGE = 274, 81 + OPTION_BITMAPS = 275, 81 82 }; 82 83 83 84 typedef enum OutputFormat { ··· 191 192 " hiding corruption that has already occurred.\n" 192 193 "\n" 193 194 "Parameters to convert subcommand:\n" 195 + " '--bitmaps' copies all top-level persistent bitmaps to destination\n" 194 196 " '-m' specifies how many coroutines work in parallel during the convert\n" 195 197 " process (defaults to 8)\n" 196 198 " '-W' allow to write to the target out of order rather than sequential\n" ··· 1638 1640 return ret; 1639 1641 } 1640 1642 1643 + /* Convenience wrapper around qmp_block_dirty_bitmap_merge */ 1644 + static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name, 1645 + const char *src_node, const char *src_name, 1646 + Error **errp) 1647 + { 1648 + BlockDirtyBitmapMergeSource *merge_src; 1649 + BlockDirtyBitmapMergeSourceList *list; 1650 + 1651 + merge_src = g_new0(BlockDirtyBitmapMergeSource, 1); 1652 + merge_src->type = QTYPE_QDICT; 1653 + merge_src->u.external.node = g_strdup(src_node); 1654 + merge_src->u.external.name = g_strdup(src_name); 1655 + list = g_new0(BlockDirtyBitmapMergeSourceList, 1); 1656 + list->value = merge_src; 1657 + qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp); 1658 + qapi_free_BlockDirtyBitmapMergeSourceList(list); 1659 + } 1660 + 1641 1661 enum ImgConvertBlockStatus { 1642 1662 BLK_DATA, 1643 1663 BLK_ZERO, ··· 2121 2141 return s->ret; 2122 2142 } 2123 2143 2144 + static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) 2145 + { 2146 + BdrvDirtyBitmap *bm; 2147 + Error *err = NULL; 2148 + 2149 + FOR_EACH_DIRTY_BITMAP(src, bm) { 2150 + const char *name; 2151 + 2152 + if (!bdrv_dirty_bitmap_get_persistence(bm)) { 2153 + continue; 2154 + } 2155 + name = bdrv_dirty_bitmap_name(bm); 2156 + qmp_block_dirty_bitmap_add(dst->node_name, name, 2157 + true, bdrv_dirty_bitmap_granularity(bm), 2158 + true, true, 2159 + true, !bdrv_dirty_bitmap_enabled(bm), 2160 + &err); 2161 + if (err) { 2162 + error_reportf_err(err, "Failed to create bitmap %s: ", name); 2163 + return -1; 2164 + } 2165 + 2166 + do_dirty_bitmap_merge(dst->node_name, name, src->node_name, name, 2167 + &err); 2168 + if (err) { 2169 + error_reportf_err(err, "Failed to populate bitmap %s: ", name); 2170 + return -1; 2171 + } 2172 + } 2173 + 2174 + return 0; 2175 + } 2176 + 2124 2177 #define MAX_BUF_SECTORS 32768 2125 2178 2126 2179 static int img_convert(int argc, char **argv) ··· 2142 2195 int64_t ret = -EINVAL; 2143 2196 bool force_share = false; 2144 2197 bool explict_min_sparse = false; 2198 + bool bitmaps = false; 2145 2199 2146 2200 ImgConvertState s = (ImgConvertState) { 2147 2201 /* Need at least 4k of zeros for sparse detection */ ··· 2161 2215 {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, 2162 2216 {"salvage", no_argument, 0, OPTION_SALVAGE}, 2163 2217 {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO}, 2218 + {"bitmaps", no_argument, 0, OPTION_BITMAPS}, 2164 2219 {0, 0, 0, 0} 2165 2220 }; 2166 2221 c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU", ··· 2286 2341 */ 2287 2342 s.has_zero_init = true; 2288 2343 break; 2344 + case OPTION_BITMAPS: 2345 + bitmaps = true; 2346 + break; 2289 2347 } 2290 2348 } 2291 2349 ··· 2346 2404 error_report("Must specify image file name"); 2347 2405 goto fail_getopt; 2348 2406 } 2349 - 2350 2407 2351 2408 /* ret is still -EINVAL until here */ 2352 2409 ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough); ··· 2507 2564 } 2508 2565 } 2509 2566 2567 + /* Determine if bitmaps need copying */ 2568 + if (bitmaps) { 2569 + if (s.src_num > 1) { 2570 + error_report("Copying bitmaps only possible with single source"); 2571 + ret = -1; 2572 + goto out; 2573 + } 2574 + if (!bdrv_supports_persistent_dirty_bitmap(blk_bs(s.src[0]))) { 2575 + error_report("Source lacks bitmap support"); 2576 + ret = -1; 2577 + goto out; 2578 + } 2579 + } 2580 + 2510 2581 /* 2511 2582 * The later open call will need any decryption secrets, and 2512 2583 * bdrv_create() will purge "opts", so extract them now before ··· 2515 2586 if (!skip_create) { 2516 2587 open_opts = qdict_new(); 2517 2588 qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort); 2518 - } 2519 2589 2520 - if (!skip_create) { 2521 2590 /* Create the new image */ 2522 2591 ret = bdrv_create(drv, out_filename, opts, &local_err); 2523 2592 if (ret < 0) { ··· 2554 2623 goto out; 2555 2624 } 2556 2625 out_bs = blk_bs(s.target); 2626 + 2627 + if (bitmaps && !bdrv_supports_persistent_dirty_bitmap(out_bs)) { 2628 + error_report("Format driver '%s' does not support bitmaps", 2629 + out_bs->drv->format_name); 2630 + ret = -1; 2631 + goto out; 2632 + } 2557 2633 2558 2634 if (s.compressed && !block_driver_can_compress(out_bs->drv)) { 2559 2635 error_report("Compression not supported for this file format"); ··· 2614 2690 } 2615 2691 2616 2692 ret = convert_do_copy(&s); 2693 + 2694 + /* Now copy the bitmaps */ 2695 + if (bitmaps && ret == 0) { 2696 + ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs); 2697 + } 2698 + 2617 2699 out: 2618 2700 if (!ret) { 2619 2701 qemu_progress_print(100, 0); ··· 4714 4796 qmp_block_dirty_bitmap_disable(bs->node_name, bitmap, &err); 4715 4797 op = "disable"; 4716 4798 break; 4717 - case BITMAP_MERGE: { 4718 - BlockDirtyBitmapMergeSource *merge_src; 4719 - BlockDirtyBitmapMergeSourceList *list; 4720 - 4721 - merge_src = g_new0(BlockDirtyBitmapMergeSource, 1); 4722 - merge_src->type = QTYPE_QDICT; 4723 - merge_src->u.external.node = g_strdup(src_bs->node_name); 4724 - merge_src->u.external.name = g_strdup(act->src); 4725 - list = g_new0(BlockDirtyBitmapMergeSourceList, 1); 4726 - list->value = merge_src; 4727 - qmp_block_dirty_bitmap_merge(bs->node_name, bitmap, list, &err); 4728 - qapi_free_BlockDirtyBitmapMergeSourceList(list); 4799 + case BITMAP_MERGE: 4800 + do_dirty_bitmap_merge(bs->node_name, bitmap, src_bs->node_name, 4801 + act->src, &err); 4729 4802 op = "merge"; 4730 4803 break; 4731 - } 4732 4804 default: 4733 4805 g_assert_not_reached(); 4734 4806 } ··· 5302 5374 if (output_format == OFORMAT_HUMAN) { 5303 5375 printf("required size: %" PRIu64 "\n", info->required); 5304 5376 printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated); 5377 + if (info->has_bitmaps) { 5378 + printf("bitmaps size: %" PRIu64 "\n", info->bitmaps); 5379 + } 5305 5380 } else { 5306 5381 dump_json_block_measure_info(info); 5307 5382 }
+17 -1
tests/qemu-iotests/178.out.qcow2
··· 13 13 qemu-img: Invalid parameter 'snapshot.foo' 14 14 qemu-img: Failed in parsing snapshot param 'snapshot.foo' 15 15 qemu-img: --output must be used with human or json as argument. 16 - qemu-img: Image size must be less than 8 EiB! 16 + qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807. 17 17 qemu-img: Unknown file format 'foo' 18 18 19 19 == Size calculation for a new file (human) == ··· 37 37 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 38 38 required size: 196608 39 39 fully allocated size: 196608 40 + bitmaps size: 0 40 41 41 42 converted image file size in bytes: 196608 42 43 ··· 45 46 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 46 47 required size: 393216 47 48 fully allocated size: 1074135040 49 + bitmaps size: 0 48 50 wrote 512/512 bytes at offset 512 49 51 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 50 52 wrote 65536/65536 bytes at offset 65536 ··· 53 55 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 54 56 required size: 589824 55 57 fully allocated size: 1074135040 58 + bitmaps size: 0 56 59 57 60 converted image file size in bytes: 524288 58 61 ··· 60 63 61 64 required size: 524288 62 65 fully allocated size: 1074135040 66 + bitmaps size: 0 63 67 64 68 converted image file size in bytes: 458752 65 69 ··· 67 71 68 72 required size: 1074135040 69 73 fully allocated size: 1074135040 74 + bitmaps size: 0 70 75 71 76 == qcow2 input image and LUKS encryption == 72 77 73 78 required size: 2686976 74 79 fully allocated size: 1076232192 80 + bitmaps size: 0 75 81 76 82 == qcow2 input image and preallocation (human) == 77 83 78 84 required size: 1074135040 79 85 fully allocated size: 1074135040 86 + bitmaps size: 0 80 87 81 88 converted image file size in bytes: 1074135040 82 89 ··· 87 94 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 88 95 required size: 8716288 89 96 fully allocated size: 8716288 97 + bitmaps size: 0 90 98 91 99 converted image file size in bytes: 8716288 92 100 ··· 173 181 174 182 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 175 183 { 184 + "bitmaps": 0, 176 185 "required": 196608, 177 186 "fully-allocated": 196608 178 187 } ··· 183 192 184 193 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 185 194 { 195 + "bitmaps": 0, 186 196 "required": 393216, 187 197 "fully-allocated": 1074135040 188 198 } ··· 193 203 wrote 64512/64512 bytes at offset 134217728 194 204 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 195 205 { 206 + "bitmaps": 0, 196 207 "required": 589824, 197 208 "fully-allocated": 1074135040 198 209 } ··· 202 213 == qcow2 input image with internal snapshot (json) == 203 214 204 215 { 216 + "bitmaps": 0, 205 217 "required": 524288, 206 218 "fully-allocated": 1074135040 207 219 } ··· 211 223 == qcow2 input image and a backing file (json) == 212 224 213 225 { 226 + "bitmaps": 0, 214 227 "required": 1074135040, 215 228 "fully-allocated": 1074135040 216 229 } ··· 218 231 == qcow2 input image and LUKS encryption == 219 232 220 233 { 234 + "bitmaps": 0, 221 235 "required": 2686976, 222 236 "fully-allocated": 1076232192 223 237 } ··· 225 239 == qcow2 input image and preallocation (json) == 226 240 227 241 { 242 + "bitmaps": 0, 228 243 "required": 1074135040, 229 244 "fully-allocated": 1074135040 230 245 } ··· 237 252 wrote 8388608/8388608 bytes at offset 0 238 253 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 239 254 { 255 + "bitmaps": 0, 240 256 "required": 8716288, 241 257 "fully-allocated": 8716288 242 258 }
+1 -1
tests/qemu-iotests/178.out.raw
··· 13 13 qemu-img: Invalid parameter 'snapshot.foo' 14 14 qemu-img: Failed in parsing snapshot param 'snapshot.foo' 15 15 qemu-img: --output must be used with human or json as argument. 16 - qemu-img: Image size must be less than 8 EiB! 16 + qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807. 17 17 qemu-img: Unknown file format 'foo' 18 18 19 19 == Size calculation for a new file (human) ==
+45 -2
tests/qemu-iotests/190
··· 2 2 # 3 3 # qemu-img measure sub-command tests on huge qcow2 files 4 4 # 5 - # Copyright (C) 2017 Red Hat, Inc. 5 + # Copyright (C) 2017-2020 Red Hat, Inc. 6 6 # 7 7 # This program is free software; you can redistribute it and/or modify 8 8 # it under the terms of the GNU General Public License as published by ··· 42 42 _supported_fmt qcow2 43 43 _supported_proto file 44 44 45 - echo "== Huge file ==" 45 + echo "== Huge file without bitmaps ==" 46 46 echo 47 47 48 48 _make_test_img -o 'cluster_size=2M' 2T ··· 50 50 $QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG" 51 51 $QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG" 52 52 $QEMU_IMG measure -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG" 53 + 54 + echo 55 + echo "== Huge file with bitmaps ==" 56 + echo 57 + 58 + $QEMU_IMG bitmap --add --granularity 512 -f qcow2 "$TEST_IMG" b1 59 + $QEMU_IMG bitmap --add -g 2M -f qcow2 "$TEST_IMG" b2 60 + 61 + # No bitmap without a source 62 + $QEMU_IMG measure -O qcow2 --size 10M 63 + # No bitmap output, since raw does not support it 64 + $QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG" 65 + # No bitmap output, since no bitmaps on raw source. Munge required size, as 66 + # some filesystems store the qcow2 file with less sparseness than others 67 + $QEMU_IMG measure -O qcow2 -f raw "$TEST_IMG" | 68 + sed '/^required size:/ s/[0-9][0-9]*/SIZE/' 69 + # No bitmap output, since v2 does not support it 70 + $QEMU_IMG measure -O qcow2 -o compat=0.10 -f qcow2 "$TEST_IMG" 71 + 72 + # Compute expected output: bitmap clusters + bitmap tables + bitmaps directory 73 + echo 74 + val2T=$((2*1024*1024*1024*1024)) 75 + cluster=$((64*1024)) 76 + b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster )) 77 + b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster )) 78 + echo expected bitmap $((b1clusters * cluster + 79 + (b1clusters * 8 + cluster - 1) / cluster * cluster + 80 + b2clusters * cluster + 81 + (b2clusters * 8 + cluster - 1) / cluster * cluster + 82 + cluster)) 83 + $QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG" 84 + 85 + # Compute expected output: bitmap clusters + bitmap tables + bitmaps directory 86 + echo 87 + cluster=$((2*1024*1024)) 88 + b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster )) 89 + b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster )) 90 + echo expected bitmap $((b1clusters * cluster + 91 + (b1clusters * 8 + cluster - 1) / cluster * cluster + 92 + b2clusters * cluster + 93 + (b2clusters * 8 + cluster - 1) / cluster * cluster + 94 + cluster)) 95 + $QEMU_IMG measure --output=json -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG" 53 96 54 97 # success, all done 55 98 echo "*** done"
+26 -1
tests/qemu-iotests/190.out
··· 1 1 QA output created by 190 2 - == Huge file == 2 + == Huge file without bitmaps == 3 3 4 4 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2199023255552 5 5 required size: 2199023255552 6 6 fully allocated size: 2199023255552 7 7 required size: 335806464 8 8 fully allocated size: 2199359062016 9 + bitmaps size: 0 9 10 required size: 18874368 10 11 fully allocated size: 2199042129920 12 + bitmaps size: 0 13 + 14 + == Huge file with bitmaps == 15 + 16 + required size: 327680 17 + fully allocated size: 10813440 18 + required size: 2199023255552 19 + fully allocated size: 2199023255552 20 + required size: SIZE 21 + fully allocated size: 17170432 22 + required size: 335806464 23 + fully allocated size: 2199359062016 24 + 25 + expected bitmap 537198592 26 + required size: 335806464 27 + fully allocated size: 2199359062016 28 + bitmaps size: 537198592 29 + 30 + expected bitmap 545259520 31 + { 32 + "bitmaps": 545259520, 33 + "required": 18874368, 34 + "fully-allocated": 2199042129920 35 + } 11 36 *** done
+10 -4
tests/qemu-iotests/194
··· 42 42 .add_incoming('unix:{0}'.format(migration_sock_path)) 43 43 .launch()) 44 44 45 + source_vm.qmp_log('block-dirty-bitmap-add', node='drive0', name='bitmap0') 46 + 45 47 iotests.log('Launching NBD server on destination...') 46 48 iotests.log(dest_vm.qmp('nbd-server-start', addr={'type': 'unix', 'data': {'path': nbd_sock_path}})) 47 49 iotests.log(dest_vm.qmp('nbd-server-add', device='drive0', writable=True)) ··· 61 63 filters=[iotests.filter_qmp_event]) 62 64 63 65 iotests.log('Starting migration...') 64 - source_vm.qmp('migrate-set-capabilities', 65 - capabilities=[{'capability': 'events', 'state': True}]) 66 - dest_vm.qmp('migrate-set-capabilities', 67 - capabilities=[{'capability': 'events', 'state': True}]) 66 + capabilities = [{'capability': 'events', 'state': True}, 67 + {'capability': 'dirty-bitmaps', 'state': True}] 68 + source_vm.qmp('migrate-set-capabilities', capabilities=capabilities) 69 + dest_vm.qmp('migrate-set-capabilities', capabilities=capabilities) 68 70 iotests.log(source_vm.qmp('migrate', uri='unix:{0}'.format(migration_sock_path))) 71 + 72 + source_vm.qmp_log('migrate-start-postcopy') 69 73 70 74 while True: 71 75 event1 = source_vm.event_wait('MIGRATION') ··· 82 86 iotests.log('Stopping the NBD server on destination...') 83 87 iotests.log(dest_vm.qmp('nbd-server-stop')) 84 88 break 89 + 90 + iotests.log(source_vm.qmp('query-block')['return'][0]['dirty-bitmaps'])
+6
tests/qemu-iotests/194.out
··· 1 1 Launching VMs... 2 + {"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap0", "node": "drive0"}} 3 + {"return": {}} 2 4 Launching NBD server on destination... 3 5 {"return": {}} 4 6 {"return": {}} ··· 8 10 {"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 9 11 Starting migration... 10 12 {"return": {}} 13 + {"execute": "migrate-start-postcopy", "arguments": {}} 14 + {"return": {}} 11 15 {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 12 16 {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 17 + {"data": {"status": "postcopy-active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 13 18 {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 14 19 Gracefully ending the `drive-mirror` job on source... 15 20 {"return": {}} 16 21 {"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 17 22 Stopping the NBD server on destination... 18 23 {"return": {}} 24 + [{"busy": false, "count": 0, "granularity": 65536, "name": "bitmap0", "persistent": false, "recording": true, "status": "active"}]
+112
tests/qemu-iotests/291
··· 1 + #!/usr/bin/env bash 2 + # 3 + # Test qemu-img bitmap handling 4 + # 5 + # Copyright (C) 2018-2020 Red Hat, Inc. 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # This program is distributed in the hope that it will be useful, 13 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + # GNU General Public License for more details. 16 + # 17 + # You should have received a copy of the GNU General Public License 18 + # along with this program. If not, see <http://www.gnu.org/licenses/>. 19 + # 20 + 21 + seq="$(basename $0)" 22 + echo "QA output created by $seq" 23 + 24 + status=1 # failure is the default! 25 + 26 + _cleanup() 27 + { 28 + _cleanup_test_img 29 + nbd_server_stop 30 + } 31 + trap "_cleanup; exit \$status" 0 1 2 3 15 32 + 33 + # get standard environment, filters and checks 34 + . ./common.rc 35 + . ./common.filter 36 + . ./common.nbd 37 + 38 + _supported_fmt qcow2 39 + _supported_proto file 40 + _supported_os Linux 41 + _require_command QEMU_NBD 42 + 43 + echo 44 + echo "=== Initial image setup ===" 45 + echo 46 + 47 + # Create backing image with one bitmap 48 + TEST_IMG="$TEST_IMG.base" _make_test_img 10M 49 + $QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG.base" b0 50 + $QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io 51 + 52 + # Create initial image and populate two bitmaps: one active, one inactive. 53 + ORIG_IMG=$TEST_IMG 54 + TEST_IMG=$TEST_IMG.orig 55 + _make_test_img -b "$ORIG_IMG.base" -F $IMGFMT 10M 56 + $QEMU_IO -c 'w 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io 57 + $QEMU_IMG bitmap --add -g 512k -f $IMGFMT "$TEST_IMG" b1 58 + $QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b2 59 + $QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io 60 + $QEMU_IMG bitmap --clear -f $IMGFMT "$TEST_IMG" b1 61 + $QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io 62 + $QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1 63 + $QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2 64 + $QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io 65 + 66 + echo 67 + echo "=== Bitmap preservation not possible to non-qcow2 ===" 68 + echo 69 + 70 + TEST_IMG=$ORIG_IMG 71 + $QEMU_IMG convert --bitmaps -O raw "$TEST_IMG.orig" "$TEST_IMG" && 72 + echo "unexpected success" 73 + 74 + echo 75 + echo "=== Convert with bitmap preservation ===" 76 + echo 77 + 78 + # Only bitmaps from the active layer are copied 79 + $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG.orig" "$TEST_IMG" 80 + $QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific 81 + # But we can also merge in bitmaps from other layers. This test is a bit 82 + # contrived to cover more code paths, in reality, you could merge directly 83 + # into b0 without going through tmp 84 + $QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b0 85 + $QEMU_IMG bitmap --add --merge b0 -b "$TEST_IMG.base" -F $IMGFMT \ 86 + -f $IMGFMT "$TEST_IMG" tmp 87 + $QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0 88 + $QEMU_IMG bitmap --remove --image-opts \ 89 + driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp 90 + $QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific 91 + 92 + echo 93 + echo "=== Check bitmap contents ===" 94 + echo 95 + 96 + # x-dirty-bitmap is a hack for reading bitmaps; it abuses block status to 97 + # report "data":false for portions of the bitmap which are set 98 + IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket" 99 + nbd_server_start_unix_socket -r -f qcow2 -B b0 "$TEST_IMG" 100 + $QEMU_IMG map --output=json --image-opts \ 101 + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b0" | _filter_qemu_img_map 102 + nbd_server_start_unix_socket -r -f qcow2 -B b1 "$TEST_IMG" 103 + $QEMU_IMG map --output=json --image-opts \ 104 + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b1" | _filter_qemu_img_map 105 + nbd_server_start_unix_socket -r -f qcow2 -B b2 "$TEST_IMG" 106 + $QEMU_IMG map --output=json --image-opts \ 107 + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map 108 + 109 + # success, all done 110 + echo '*** done' 111 + rm -f $seq.full 112 + status=0
+80
tests/qemu-iotests/291.out
··· 1 + QA output created by 291 2 + 3 + === Initial image setup === 4 + 5 + Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=10485760 6 + wrote 1048576/1048576 bytes at offset 3145728 7 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 8 + Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=10485760 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT 9 + wrote 1048576/1048576 bytes at offset 0 10 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 11 + wrote 1048576/1048576 bytes at offset 3145728 12 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 13 + wrote 1048576/1048576 bytes at offset 1048576 14 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 15 + wrote 1048576/1048576 bytes at offset 2097152 16 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 17 + 18 + === Bitmap preservation not possible to non-qcow2 === 19 + 20 + qemu-img: Format driver 'raw' does not support bitmaps 21 + 22 + === Convert with bitmap preservation === 23 + 24 + image: TEST_DIR/t.IMGFMT 25 + file format: IMGFMT 26 + virtual size: 10 MiB (10485760 bytes) 27 + disk size: 4.39 MiB 28 + Format specific information: 29 + compat: 1.1 30 + compression type: zlib 31 + lazy refcounts: false 32 + bitmaps: 33 + [0]: 34 + flags: 35 + name: b1 36 + granularity: 524288 37 + [1]: 38 + flags: 39 + [0]: auto 40 + name: b2 41 + granularity: 65536 42 + refcount bits: 16 43 + corrupt: false 44 + image: TEST_DIR/t.IMGFMT 45 + file format: IMGFMT 46 + virtual size: 10 MiB (10485760 bytes) 47 + disk size: 4.48 MiB 48 + Format specific information: 49 + compat: 1.1 50 + compression type: zlib 51 + lazy refcounts: false 52 + bitmaps: 53 + [0]: 54 + flags: 55 + name: b1 56 + granularity: 524288 57 + [1]: 58 + flags: 59 + [0]: auto 60 + name: b2 61 + granularity: 65536 62 + [2]: 63 + flags: 64 + name: b0 65 + granularity: 65536 66 + refcount bits: 16 67 + corrupt: false 68 + 69 + === Check bitmap contents === 70 + 71 + [{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, 72 + { "start": 3145728, "length": 1048576, "depth": 0, "zero": false, "data": false}, 73 + { "start": 4194304, "length": 6291456, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] 74 + [{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, 75 + { "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": false}, 76 + { "start": 2097152, "length": 8388608, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] 77 + [{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, 78 + { "start": 2097152, "length": 1048576, "depth": 0, "zero": false, "data": false}, 79 + { "start": 3145728, "length": 7340032, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] 80 + *** done
+1
tests/qemu-iotests/group
··· 299 299 288 quick 300 300 289 rw quick 301 301 290 rw auto quick 302 + 291 rw quick 302 303 292 rw auto quick 303 304 297 meta