diff options
34 files changed, 1473 insertions, 56 deletions
diff --git a/block/blkreplay.c b/block/blkreplay.c index 61e44a1949..fe5a9b4a98 100755 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -129,10 +129,9 @@ static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs) static BlockDriver bdrv_blkreplay = { .format_name = "blkreplay", - .protocol_name = "blkreplay", .instance_size = 0, - .bdrv_file_open = blkreplay_open, + .bdrv_open = blkreplay_open, .bdrv_close = blkreplay_close, .bdrv_child_perm = bdrv_filter_default_perms, .bdrv_getlength = blkreplay_getlength, diff --git a/block/crypto.c b/block/crypto.c index e0b8856f74..bc6c7e3795 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -357,7 +357,11 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset, BlockCrypto *crypto = bs->opaque; uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); - assert(payload_offset < (INT64_MAX - offset)); + + if (payload_offset > INT64_MAX - offset) { + error_setg(errp, "The requested file size is too large"); + return -EFBIG; + } offset += payload_offset; diff --git a/block/parallels.c b/block/parallels.c index e2515dec81..799215e079 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -526,6 +526,11 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts, cl_size = DEFAULT_CLUSTER_SIZE; } + /* XXX What is the real limit here? This is an insanely large maximum. */ + if (cl_size >= INT64_MAX / MAX_PARALLELS_IMAGE_FACTOR) { + error_setg(errp, "Cluster size is too large"); + return -EINVAL; + } if (total_size >= MAX_PARALLELS_IMAGE_FACTOR * cl_size) { error_setg(errp, "Image size is too large for this cluster size"); return -E2BIG; diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 3010adb909..6e93ec43e1 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1004,7 +1004,8 @@ fail: return false; } -int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) +int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp) { BDRVQcow2State *s = bs->opaque; Qcow2BitmapList *bm_list; @@ -1012,6 +1013,10 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) GSList *ro_dirty_bitmaps = NULL; int ret = 0; + if (header_updated != NULL) { + *header_updated = false; + } + if (s->nb_bitmaps == 0) { /* No bitmaps - nothing to do */ return 0; @@ -1055,6 +1060,9 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) error_setg_errno(errp, -ret, "Can't update bitmap directory"); goto out; } + if (header_updated != NULL) { + *header_updated = true; + } g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, false); } @@ -1065,6 +1073,11 @@ out: return ret; } +int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) +{ + return qcow2_reopen_bitmaps_rw_hint(bs, NULL, errp); +} + /* store_bitmap_data() * Store bitmap to image, filling bitmap table accordingly. */ diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 362deaf303..6b8b63514a 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -839,6 +839,13 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, qcow2_cache_put(s->refcount_block_cache, &refcount_block); } ret = alloc_refcount_block(bs, cluster_index, &refcount_block); + /* If the caller needs to restart the search for free clusters, + * try the same ones first to see if they're still free. */ + if (ret == -EAGAIN) { + if (s->free_cluster_index > (start >> s->cluster_bits)) { + s->free_cluster_index = (start >> s->cluster_bits); + } + } if (ret < 0) { goto fail; } diff --git a/block/qcow2.c b/block/qcow2.c index cf4f3becae..486f3e83b7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1480,7 +1480,22 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; } - if (qcow2_load_dirty_bitmaps(bs, &local_err)) { + if (bdrv_dirty_bitmap_next(bs, NULL)) { + /* It's some kind of reopen with already existing dirty bitmaps. There + * are no known cases where we need loading bitmaps in such situation, + * so it's safer don't load them. + * + * Moreover, if we have some readonly bitmaps and we are reopening for + * rw we should reopen bitmaps correspondingly. + */ + if (bdrv_has_readonly_bitmaps(bs) && + !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) + { + bool header_updated = false; + qcow2_reopen_bitmaps_rw_hint(bs, &header_updated, &local_err); + update_header = update_header && !header_updated; + } + } else if (qcow2_load_dirty_bitmaps(bs, &local_err)) { update_header = false; } if (local_err != NULL) { diff --git a/block/qcow2.h b/block/qcow2.h index ccb92a9696..d301f77cea 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -671,6 +671,8 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size); bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp); +int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp); int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp); int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); diff --git a/block/quorum.c b/block/quorum.c index 14333c18aa..cfe484a945 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1098,11 +1098,10 @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) static BlockDriver bdrv_quorum = { .format_name = "quorum", - .protocol_name = "quorum", .instance_size = sizeof(BDRVQuorumState), - .bdrv_file_open = quorum_open, + .bdrv_open = quorum_open, .bdrv_close = quorum_close, .bdrv_refresh_filename = quorum_refresh_filename, diff --git a/block/replication.c b/block/replication.c index f98ef094b9..6c0c7186d9 100644 --- a/block/replication.c +++ b/block/replication.c @@ -703,7 +703,6 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) BlockDriver bdrv_replication = { .format_name = "replication", - .protocol_name = "replication", .instance_size = sizeof(BDRVReplicationState), .bdrv_open = replication_open, diff --git a/block/throttle.c b/block/throttle.c index 5f4d43d0fc..95ed06acd8 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -215,10 +215,9 @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs) static BlockDriver bdrv_throttle = { .format_name = "throttle", - .protocol_name = "throttle", .instance_size = sizeof(ThrottleGroupMember), - .bdrv_file_open = throttle_open, + .bdrv_open = throttle_open, .bdrv_close = throttle_close, .bdrv_co_flush = throttle_co_flush, diff --git a/block/vdi.c b/block/vdi.c index d939b034c4..4a2d1ff88d 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -235,7 +235,6 @@ static void vdi_header_to_le(VdiHeader *header) qemu_uuid_bswap(&header->uuid_parent); } -#if defined(CONFIG_VDI_DEBUG) static void vdi_header_print(VdiHeader *header) { char uuid[37]; @@ -257,16 +256,15 @@ static void vdi_header_print(VdiHeader *header) logout("block extra 0x%04x\n", header->block_extra); logout("blocks tot. 0x%04x\n", header->blocks_in_image); logout("blocks all. 0x%04x\n", header->blocks_allocated); - uuid_unparse(header->uuid_image, uuid); + qemu_uuid_unparse(&header->uuid_image, uuid); logout("uuid image %s\n", uuid); - uuid_unparse(header->uuid_last_snap, uuid); + qemu_uuid_unparse(&header->uuid_last_snap, uuid); logout("uuid snap %s\n", uuid); - uuid_unparse(header->uuid_link, uuid); + qemu_uuid_unparse(&header->uuid_link, uuid); logout("uuid link %s\n", uuid); - uuid_unparse(header->uuid_parent, uuid); + qemu_uuid_unparse(&header->uuid_parent, uuid); logout("uuid parent %s\n", uuid); } -#endif static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix) @@ -387,9 +385,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, } vdi_header_to_cpu(&header); -#if defined(CONFIG_VDI_DEBUG) - vdi_header_print(&header); -#endif + if (VDI_DEBUG) { + vdi_header_print(&header); + } if (header.disk_size > VDI_DISK_SIZE_MAX) { error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64 @@ -728,7 +726,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, int ret = 0; uint64_t bytes = 0; uint32_t blocks; - uint32_t image_type = VDI_TYPE_DYNAMIC; + uint32_t image_type; VdiHeader header; size_t i; size_t bmap_size; @@ -744,9 +742,22 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, /* Validate options and set default values */ bytes = vdi_opts->size; - if (vdi_opts->q_static) { + + if (!vdi_opts->has_preallocation) { + vdi_opts->preallocation = PREALLOC_MODE_OFF; + } + switch (vdi_opts->preallocation) { + case PREALLOC_MODE_OFF: + image_type = VDI_TYPE_DYNAMIC; + break; + case PREALLOC_MODE_METADATA: image_type = VDI_TYPE_STATIC; + break; + default: + error_setg(errp, "Preallocation mode not supported for vdi"); + return -EINVAL; } + #ifndef CONFIG_VDI_STATIC_IMAGE if (image_type == VDI_TYPE_STATIC) { ret = -ENOTSUP; @@ -812,9 +823,9 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, qemu_uuid_generate(&header.uuid_image); qemu_uuid_generate(&header.uuid_last_snap); /* There is no need to set header.uuid_link or header.uuid_parent here. */ -#if defined(CONFIG_VDI_DEBUG) - vdi_header_print(&header); -#endif + if (VDI_DEBUG) { + vdi_header_print(&header); + } vdi_header_to_le(&header); ret = blk_pwrite(blk, offset, &header, sizeof(header), 0); if (ret < 0) { @@ -874,6 +885,7 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, BlockdevCreateOptions *create_options = NULL; BlockDriverState *bs_file = NULL; uint64_t block_size = DEFAULT_CLUSTER_SIZE; + bool is_static = false; Visitor *v; Error *local_err = NULL; int ret; @@ -895,6 +907,9 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, goto done; } #endif + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) { + is_static = true; + } qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true); @@ -913,6 +928,9 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, qdict_put_str(qdict, "driver", "vdi"); qdict_put_str(qdict, "file", bs_file->node_name); + if (is_static) { + qdict_put_str(qdict, "preallocation", "metadata"); + } /* Get the QAPI object */ v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); diff --git a/block/vhdx.c b/block/vhdx.c index d2c54b7891..6ac0424f61 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1822,17 +1822,21 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, /* Validate options and set default values */ image_size = vhdx_opts->size; if (image_size > VHDX_MAX_IMAGE_SIZE) { - error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB"); + error_setg(errp, "Image size too large; max of 64TB"); return -EINVAL; } if (!vhdx_opts->has_log_size) { log_size = DEFAULT_LOG_SIZE; } else { + if (vhdx_opts->log_size > UINT32_MAX) { + error_setg(errp, "Log size must be smaller than 4 GB"); + return -EINVAL; + } log_size = vhdx_opts->log_size; } if (log_size < MiB || (log_size % MiB) != 0) { - error_setg_errno(errp, EINVAL, "Log size must be a multiple of 1 MB"); + error_setg(errp, "Log size must be a multiple of 1 MB"); return -EINVAL; } @@ -1874,12 +1878,15 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, } if (block_size < MiB || (block_size % MiB) != 0) { - error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB"); + error_setg(errp, "Block size must be a multiple of 1 MB"); + return -EINVAL; + } + if (!is_power_of_2(block_size)) { + error_setg(errp, "Block size must be a power of two"); return -EINVAL; } if (block_size > VHDX_BLOCK_SIZE_MAX) { - error_setg_errno(errp, EINVAL, "Block size must not exceed %d", - VHDX_BLOCK_SIZE_MAX); + error_setg(errp, "Block size must not exceed %d", VHDX_BLOCK_SIZE_MAX); return -EINVAL; } diff --git a/block/vmdk.c b/block/vmdk.c index f94c49a9c0..84f8bbe480 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -47,6 +47,8 @@ #define VMDK4_FLAG_MARKER (1 << 17) #define VMDK4_GD_AT_END 0xffffffffffffffffULL +#define VMDK_EXTENT_MAX_SECTORS (1ULL << 32) + #define VMDK_GTE_ZEROED 0x1 /* VMDK internal error codes */ @@ -1250,6 +1252,10 @@ static int get_cluster_offset(BlockDriverState *bs, return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; } + if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) { + return VMDK_ERROR; + } + cluster_sector = extent->next_cluster_sector; extent->next_cluster_sector += extent->cluster_sectors; diff --git a/include/block/block_int.h b/include/block/block_int.h index 27e17addba..c4dd1d4bb8 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -126,6 +126,8 @@ struct BlockDriver { int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags, Error **errp); + + /* Protocol drivers should implement this instead of bdrv_open */ int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags, Error **errp); void (*bdrv_close)(BlockDriverState *bs); @@ -251,6 +253,12 @@ struct BlockDriver { */ int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); + /* + * Drivers setting this field must be able to work with just a plain + * filename with '<protocol_name>:' as a prefix, and no other options. + * Options may be extracted from the filename by implementing + * bdrv_parse_filename. + */ const char *protocol_name; int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset, PreallocMode prealloc, Error **errp); diff --git a/qapi/block-core.json b/qapi/block-core.json index 1088ab0c78..c50517bff3 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3943,16 +3943,15 @@ # # @file Node to create the image format on # @size Size of the virtual disk in bytes -# @static Whether to create a statically (true) or -# dynamically (false) allocated image -# (default: false, i.e. dynamic) +# @preallocation Preallocation mode for the new image (allowed values: off, +# metadata; default: off) # # Since: 2.12 ## { 'struct': 'BlockdevCreateOptionsVdi', 'data': { 'file': 'BlockdevRef', 'size': 'size', - '*static': 'bool' } } + '*preallocation': 'PreallocMode' } } ## # @BlockdevVhdxSubformat: diff --git a/replication.h b/replication.h index 8faefe005f..4c8354de23 100644 --- a/replication.h +++ b/replication.h @@ -67,7 +67,6 @@ typedef struct ReplicationState ReplicationState; * * BlockDriver bdrv_replication = { * .format_name = "replication", - * .protocol_name = "replication", * .instance_size = sizeof(BDRVReplicationState), * * .bdrv_open = replication_open, diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 41301c84aa..277f9a9bba 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -972,6 +972,7 @@ def main(): global input_file global insnwidth global insntype + global insnmask decode_function = 'decode' decode_scope = 'static ' diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 19dd12a93e..861bbb1f16 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -305,8 +305,8 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, target_ulong *pc, incomplete virtual address. This also means that we must separate out current cpu priviledge from the low bits of IAOQ_F. */ #ifdef CONFIG_USER_ONLY - *pc = env->iaoq_f; - *cs_base = env->iaoq_b; + *pc = env->iaoq_f & -4; + *cs_base = env->iaoq_b & -4; #else /* ??? E, T, H, L, B, P bits need to be here, when implemented. */ flags |= env->psw & (PSW_W | PSW_C | PSW_D); diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 6499b392f9..c532889b1f 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -1909,9 +1909,6 @@ static DisasJumpType do_ibranch(DisasContext *ctx, TCGv_reg dest, */ static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset) { -#ifdef CONFIG_USER_ONLY - return offset; -#else TCGv_reg dest; switch (ctx->privilege) { case 0: @@ -1931,7 +1928,6 @@ static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset) break; } return dest; -#endif } #ifdef CONFIG_USER_ONLY @@ -1967,7 +1963,7 @@ static DisasJumpType do_page_zero(DisasContext *ctx) goto do_sigill; } - switch (ctx->iaoq_f) { + switch (ctx->iaoq_f & -4) { case 0x00: /* Null pointer call */ gen_excp_1(EXCP_IMP); return DISAS_NORETURN; @@ -1978,7 +1974,7 @@ static DisasJumpType do_page_zero(DisasContext *ctx) case 0xe0: /* SET_THREAD_POINTER */ tcg_gen_st_reg(cpu_gr[26], cpu_env, offsetof(CPUHPPAState, cr[27])); - tcg_gen_mov_reg(cpu_iaoq_f, cpu_gr[31]); + tcg_gen_ori_reg(cpu_iaoq_f, cpu_gr[31], 3); tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4); return DISAS_IAQ_N_UPDATED; @@ -4697,8 +4693,8 @@ static int hppa_tr_init_disas_context(DisasContextBase *dcbase, #ifdef CONFIG_USER_ONLY ctx->privilege = MMU_USER_IDX; ctx->mmu_idx = MMU_USER_IDX; - ctx->iaoq_f = ctx->base.pc_first; - ctx->iaoq_b = ctx->base.tb->cs_base; + ctx->iaoq_f = ctx->base.pc_first | MMU_USER_IDX; + ctx->iaoq_b = ctx->base.tb->cs_base | MMU_USER_IDX; #else ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; ctx->mmu_idx = (ctx->tb_flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX); diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025 index f5e672e6b3..70dd5f10aa 100755 --- a/tests/qemu-iotests/025 +++ b/tests/qemu-iotests/025 @@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.filter . ./common.pattern -_supported_fmt raw qcow2 qed +_supported_fmt raw qcow2 qed luks _supported_proto file sheepdog rbd nfs _supported_os Linux @@ -62,6 +62,13 @@ length EOF _check_test_img +# bdrv_truncate() doesn't zero the new space, so we need to do that explicitly. +# We still want to test automatic zeroing for other formats even though +# bdrv_truncate() doesn't guarantee it. +if [ "$IMGFMT" == "luks" ]; then + $QEMU_IO -c "write -z $small_size $((big_size - small_size))" "$TEST_IMG" > /dev/null +fi + echo echo "=== Verifying image size after reopen" $QEMU_IO -c "length" "$TEST_IMG" diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out index 86a50a2e13..8e89416a86 100644 --- a/tests/qemu-iotests/026.out +++ b/tests/qemu-iotests/026.out @@ -533,7 +533,7 @@ Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device -11 leaked clusters were found on the image. +10 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -561,7 +561,7 @@ Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device -11 leaked clusters were found on the image. +10 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -589,7 +589,7 @@ Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device -11 leaked clusters were found on the image. +10 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121 index 1307b4e327..6d6f55a5dc 100755 --- a/tests/qemu-iotests/121 +++ b/tests/qemu-iotests/121 @@ -93,6 +93,26 @@ $QEMU_IO -c 'write 63M 130K' "$TEST_IMG" | _filter_qemu_io _check_test_img +echo +echo '=== Allocating a new refcount block must not leave holes in the image ===' +echo + +IMGOPTS='cluster_size=512,refcount_bits=16' _make_test_img 1M + +# This results in an image with 256 used clusters: the qcow2 header, +# the refcount table, one refcount block, the L1 table, four L2 tables +# and 248 data clusters +$QEMU_IO -c 'write 0 124k' "$TEST_IMG" | _filter_qemu_io + +# 256 clusters of 512 bytes each give us a 128K image +stat -c "size=%s (expected 131072)" $TEST_IMG + +# All 256 entries of the refcount block are used, so writing a new +# data cluster also allocates a new refcount block +$QEMU_IO -c 'write 124k 512' "$TEST_IMG" | _filter_qemu_io + +# Two more clusters, the image size should be 129K now +stat -c "size=%s (expected 132096)" $TEST_IMG # success, all done echo diff --git a/tests/qemu-iotests/121.out b/tests/qemu-iotests/121.out index 5961a44cd9..613d56185e 100644 --- a/tests/qemu-iotests/121.out +++ b/tests/qemu-iotests/121.out @@ -20,4 +20,14 @@ wrote 133120/133120 bytes at offset 66060288 130 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. +=== Allocating a new refcount block must not leave holes in the image === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +wrote 126976/126976 bytes at offset 0 +124 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +size=131072 (expected 131072) +wrote 512/512 bytes at offset 126976 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +size=132096 (expected 132096) + *** done diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169 index 3a8db91f6f..153b10b6e7 100755 --- a/tests/qemu-iotests/169 +++ b/tests/qemu-iotests/169 @@ -140,16 +140,14 @@ def inject_test_case(klass, name, method, *args, **kwargs): mc = operator.methodcaller(method, *args, **kwargs) setattr(klass, 'test_' + name, new.instancemethod(mc, None, klass)) -for cmb in list(itertools.product((True, False), repeat=3)): +for cmb in list(itertools.product((True, False), repeat=4)): name = ('_' if cmb[0] else '_not_') + 'persistent_' name += ('_' if cmb[1] else '_not_') + 'migbitmap_' name += '_online' if cmb[2] else '_offline' - - # TODO fix shared-storage bitmap migration and enable cases for it - args = list(cmb) + [False] + name += '_shared' if cmb[3] else '_nonshared' inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration', - *args) + *list(cmb)) if __name__ == '__main__': diff --git a/tests/qemu-iotests/169.out b/tests/qemu-iotests/169.out index 594c16f49f..b6f257674e 100644 --- a/tests/qemu-iotests/169.out +++ b/tests/qemu-iotests/169.out @@ -1,5 +1,5 @@ -........ +................ ---------------------------------------------------------------------- -Ran 8 tests +Ran 16 tests OK diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 index 96a5213e77..e607c0d296 100755 --- a/tests/qemu-iotests/210 +++ b/tests/qemu-iotests/210 @@ -204,6 +204,43 @@ run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \ { "execute": "quit" } EOF +echo +echo "=== Resize image with invalid sizes ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \ + -blockdev driver=luks,file=node0,key-secret=keysec0,node-name=node1 \ + -object secret,id=keysec0,data="foo" <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "block_resize", + "arguments": { + "node-name": "node1", + "size": 9223372036854775296 + } +} +{ "execute": "block_resize", + "arguments": { + "node-name": "node1", + "size": 9223372036854775808 + } +} +{ "execute": "block_resize", + "arguments": { + "node-name": "node1", + "size": 18446744073709551104 + } +} +{ "execute": "block_resize", + "arguments": { + "node-name": "node1", + "size": -9223372036854775808 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out index 8fcab65909..8198f8c829 100644 --- a/tests/qemu-iotests/210.out +++ b/tests/qemu-iotests/210.out @@ -133,4 +133,20 @@ QMP_VERSION {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +=== Resize image with invalid sizes === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -blockdev driver=IMGFMT,file=node0,key-secret=keysec0,node-name=node1 -object secret,id=keysec0,data=foo +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "The requested file size is too large"}} +{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} +{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} +{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"} +file format: IMGFMT +virtual size: 0 (0 bytes) *** done diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 new file mode 100755 index 0000000000..1edec26517 --- /dev/null +++ b/tests/qemu-iotests/211 @@ -0,0 +1,246 @@ +#!/bin/bash +# +# Test VDI and file image creation +# +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt vdi +_supported_proto file +_supported_os Linux + +function do_run_qemu() +{ + echo Testing: "$@" + $QEMU -nographic -qmp stdio -serial none "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ + | _filter_actual_image_size +} + +echo +echo "=== Successful image creation (defaults) ===" +echo + +size=$((128 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "blockdev-add", + "arguments": { + "driver": "file", + "node-name": "imgfile", + "filename": "$TEST_IMG" + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "imgfile", + "size": $size + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific +$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map + +echo +echo "=== Successful image creation (explicit defaults) ===" +echo + +# Choose a different size to show that we got a new image +size=$((64 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + }, + "size": $size, + "preallocation": "off" + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific +$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map + +echo +echo "=== Successful image creation (with non-default options) ===" +echo + +# Choose a different size to show that we got a new image +size=$((32 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + }, + "size": $size, + "preallocation": "metadata" + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific +$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map + +echo +echo "=== Invalid BlockdevRef ===" +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "this doesn't exist", + "size": $size + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Zero size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 0 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + +echo +echo "=== Maximum size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 562949819203584 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + +echo +echo "=== Invalid sizes ===" +echo + +# TODO Negative image sizes aren't handled correctly, but this is a problem +# with QAPI's implementation of the 'size' type and affects other commands as +# well. Once this is fixed, we may want to add a test case here. + +# 1. 2^64 - 512 +# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this) +# 3. 0x1fffff8000001 (one byte more than maximum image size for VDI) + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 18446744073709551104 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 9223372036854775808 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 562949819203585 + } +} +{ "execute": "quit" } +EOF + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out new file mode 100644 index 0000000000..3247bbaa64 --- /dev/null +++ b/tests/qemu-iotests/211.out @@ -0,0 +1,97 @@ +QA output created by 211 + +=== Successful image creation (defaults) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 128M (134217728 bytes) +[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}] + +=== Successful image creation (explicit defaults) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] + +=== Successful image creation (with non-default options) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32M (33554432 bytes) +[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": OFFSET}] + +=== Invalid BlockdevRef === + +Testing: +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + +=== Zero size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 0 (0 bytes) + +=== Maximum size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 512T (562949819203584 bytes) + +=== Invalid sizes === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)"}} +{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)"}} +{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +*** done diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 new file mode 100755 index 0000000000..e5a1ba77ce --- /dev/null +++ b/tests/qemu-iotests/212 @@ -0,0 +1,326 @@ +#!/bin/bash +# +# Test parallels and file image creation +# +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt parallels +_supported_proto file +_supported_os Linux + +function do_run_qemu() +{ + echo Testing: "$@" + $QEMU -nographic -qmp stdio -serial none "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ + | _filter_actual_image_size +} + +echo +echo "=== Successful image creation (defaults) ===" +echo + +size=$((128 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "blockdev-add", + "arguments": { + "driver": "file", + "node-name": "imgfile", + "filename": "$TEST_IMG" + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "imgfile", + "size": $size + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific + +echo +echo "=== Successful image creation (explicit defaults) ===" +echo + +# Choose a different size to show that we got a new image +size=$((64 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + }, + "size": $size, + "cluster-size": 1048576 + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific + +echo +echo "=== Successful image creation (with non-default options) ===" +echo + +# Choose a different size to show that we got a new image +size=$((32 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + }, + "size": $size, + "cluster-size": 65536 + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific + +echo +echo "=== Invalid BlockdevRef ===" +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "this doesn't exist", + "size": $size + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Zero size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 0 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + +echo +echo "=== Maximum size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 4503599627369984 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + +echo +echo "=== Invalid sizes ===" +echo + +# TODO Negative image sizes aren't handled correctly, but this is a problem +# with QAPI's implementation of the 'size' type and affects other commands as +# well. Once this is fixed, we may want to add a test case here. + +# 1. Misaligned image size +# 2. 2^64 - 512 +# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this) +# 4. 2^63 - 512 (generally valid, but with the image header the file will +# exceed 63 bits) +# 5. 2^52 (512 bytes more than maximum image size) + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 1234 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 18446744073709551104 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 9223372036854775808 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 9223372036854775296 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 4503599627370497 + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Invalid cluster size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "cluster-size": 1234 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "cluster-size": 128 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "cluster-size": 4294967296 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "cluster-size": 9223372036854775808 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "cluster-size": 18446744073709551104 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "cluster-size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 281474976710656, + "cluster-size": 512 + } +} +{ "execute": "quit" } +EOF + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out new file mode 100644 index 0000000000..587de6fad0 --- /dev/null +++ b/tests/qemu-iotests/212.out @@ -0,0 +1,111 @@ +QA output created by 212 + +=== Successful image creation (defaults) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 128M (134217728 bytes) + +=== Successful image creation (explicit defaults) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) + +=== Successful image creation (with non-default options) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32M (33554432 bytes) + +=== Invalid BlockdevRef === + +Testing: +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + +=== Zero size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 0 (0 bytes) + +=== Maximum size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 4096T (4503599627369984 bytes) + +=== Invalid sizes === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}} +{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}} +{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}} +{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}} +{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + +=== Invalid cluster size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}} +{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}} +{"error": {"class": "GenericError", "desc": "Cluster size is too large"}} +{"error": {"class": "GenericError", "desc": "Cluster size is too large"}} +{"error": {"class": "GenericError", "desc": "Cluster size is too large"}} +{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}} +{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +*** done diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 new file mode 100755 index 0000000000..3a00a0f6d6 --- /dev/null +++ b/tests/qemu-iotests/213 @@ -0,0 +1,349 @@ +#!/bin/bash +# +# Test vhdx and file image creation +# +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt vhdx +_supported_proto file +_supported_os Linux + +function do_run_qemu() +{ + echo Testing: "$@" + $QEMU -nographic -qmp stdio -serial none "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ + | _filter_actual_image_size +} + +echo +echo "=== Successful image creation (defaults) ===" +echo + +size=$((128 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "blockdev-add", + "arguments": { + "driver": "file", + "node-name": "imgfile", + "filename": "$TEST_IMG" + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "imgfile", + "size": $size + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific + +echo +echo "=== Successful image creation (explicit defaults) ===" +echo + +# Choose a different size to show that we got a new image +size=$((64 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + }, + "size": $size, + "log-size": 1048576, + "block-size": 8388608, + "subformat": "dynamic", + "block-state-zero": true + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific + +echo +echo "=== Successful image creation (with non-default options) ===" +echo + +# Choose a different size to show that we got a new image +size=$((32 * 1024 * 1024)) + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "file", + "filename": "$TEST_IMG", + "size": 0 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + }, + "size": $size, + "log-size": 8388608, + "block-size": 268435456, + "subformat": "fixed", + "block-state-zero": false + } +} +{ "execute": "quit" } +EOF + +_img_info --format-specific | _filter_img_info --format-specific + +echo +echo "=== Invalid BlockdevRef ===" +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "this doesn't exist", + "size": $size + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Zero size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 0 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + +echo +echo "=== Maximum size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 70368744177664 + } +} +{ "execute": "quit" } +EOF + +_img_info | _filter_img_info + +echo +echo "=== Invalid sizes ===" +echo + +# TODO Negative image sizes aren't handled correctly, but this is a problem +# with QAPI's implementation of the 'size' type and affects other commands as +# well. Once this is fixed, we may want to add a test case here. + +# 1. 2^64 - 512 +# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this) +# 3. 2^63 - 512 (generally valid, but with the image header the file will +# exceed 63 bits) +# 4. 2^46 + 1 (one byte more than maximum image size) + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 18446744073709551104 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 9223372036854775808 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 9223372036854775296 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 70368744177665 + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Invalid block size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "block-size": 1234567 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "block-size": 128 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "block-size": 3145728 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "block-size": 536870912 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "block-size": 0 + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Invalid log size ===" +echo + +run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "log-size": 1234567 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "log-size": 128 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "log-size": 4294967296 + } +} +{ "execute": "x-blockdev-create", + "arguments": { + "driver": "$IMGFMT", + "file": "node0", + "size": 67108864, + "log-size": 0 + } +} +{ "execute": "quit" } +EOF + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out new file mode 100644 index 0000000000..8e8fc29cbc --- /dev/null +++ b/tests/qemu-iotests/213.out @@ -0,0 +1,121 @@ +QA output created by 213 + +=== Successful image creation (defaults) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 128M (134217728 bytes) + +=== Successful image creation (explicit defaults) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) + +=== Successful image creation (with non-default options) === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32M (33554432 bytes) + +=== Invalid BlockdevRef === + +Testing: +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + +=== Zero size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 0 (0 bytes) + +=== Maximum size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64T (70368744177664 bytes) + +=== Invalid sizes === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}} +{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}} +{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}} +{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + +=== Invalid block size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}} +{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}} +{"error": {"class": "GenericError", "desc": "Block size must be a power of two"}} +{"error": {"class": "GenericError", "desc": "Block size must not exceed 268435456"}} +{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + +=== Invalid log size === + +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 +QMP_VERSION +{"return": {}} +{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}} +{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}} +{"error": {"class": "GenericError", "desc": "Log size must be smaller than 4 GB"}} +{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index efe0e958f2..52a80f3f9e 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -167,7 +167,7 @@ 159 rw auto quick 160 rw auto quick 162 auto quick -163 rw auto quick +163 rw auto 165 rw auto quick 169 rw auto quick 170 rw auto quick @@ -209,3 +209,6 @@ 208 rw auto quick 209 rw auto quick 210 rw auto +211 rw auto quick +212 rw auto quick +213 rw auto quick |