diff options
43 files changed, 1582 insertions, 161 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 5ad1b919bc..d4190602d1 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1728,8 +1728,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) CPUArchState *env = cpu->env_ptr; #endif TranslationBlock *tb; - uint32_t n, flags; - target_ulong pc, cs_base; + uint32_t n; tb_lock(); tb = tb_find_pc(retaddr); @@ -1737,44 +1736,33 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) cpu_abort(cpu, "cpu_io_recompile: could not find TB for pc=%p", (void *)retaddr); } - n = cpu->icount_decr.u16.low + tb->icount; cpu_restore_state_from_tb(cpu, tb, retaddr); - /* Calculate how many instructions had been executed before the fault - occurred. */ - n = n - cpu->icount_decr.u16.low; - /* Generate a new TB ending on the I/O insn. */ - n++; + /* On MIPS and SH, delay slot instructions can only be restarted if they were already the first instruction in the TB. If this is not the first instruction in a TB then re-execute the preceding branch. */ + n = 1; #if defined(TARGET_MIPS) - if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { + if ((env->hflags & MIPS_HFLAG_BMASK) != 0 + && env->active_tc.PC != tb->pc) { env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); cpu->icount_decr.u16.low++; env->hflags &= ~MIPS_HFLAG_BMASK; + n = 2; } #elif defined(TARGET_SH4) if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 - && n > 1) { + && env->pc != tb->pc) { env->pc -= 2; cpu->icount_decr.u16.low++; env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + n = 2; } #endif - /* This should never happen. */ - if (n > CF_COUNT_MASK) { - cpu_abort(cpu, "TB too big during recompile"); - } - pc = tb->pc; - cs_base = tb->cs_base; - flags = tb->flags; - tb_phys_invalidate(tb, -1); - - /* Execute one IO instruction without caching - instead of creating large TB. */ - cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | CF_NOCACHE | 1; + /* Generate a new TB executing the I/O insn. */ + cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | n; if (tb->cflags & CF_NOCACHE) { if (tb->orig_tb) { @@ -1785,11 +1773,6 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) tb_remove(tb); } - /* Generate new TB instead of the current one. */ - /* FIXME: In theory this could raise an exception. In practice - we have already translated the block once so it's probably ok. */ - tb_gen_code(cpu, pc, cs_base, flags, curr_cflags() | CF_LAST_IO | n); - /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not * the first in the TB) then we end up generating a whole new TB and * repeating the fault, which is horribly inefficient. 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-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/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/chardev/char-fe.c b/chardev/char-fe.c index 392db78b13..b1f228e8b5 100644 --- a/chardev/char-fe.c +++ b/chardev/char-fe.c @@ -198,19 +198,21 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp) { int tag = 0; - if (CHARDEV_IS_MUX(s)) { - MuxChardev *d = MUX_CHARDEV(s); + if (s) { + if (CHARDEV_IS_MUX(s)) { + MuxChardev *d = MUX_CHARDEV(s); + + if (d->mux_cnt >= MAX_MUX) { + goto unavailable; + } - if (d->mux_cnt >= MAX_MUX) { + d->backends[d->mux_cnt] = b; + tag = d->mux_cnt++; + } else if (s->be) { goto unavailable; + } else { + s->be = b; } - - d->backends[d->mux_cnt] = b; - tag = d->mux_cnt++; - } else if (s->be) { - goto unavailable; - } else { - s->be = b; } b->fe_open = false; diff --git a/chardev/char-socket.c b/chardev/char-socket.c index d057192ced..159e69c3b1 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -550,12 +550,10 @@ static void tcp_chr_connect(void *opaque) s->is_listen, s->is_telnet); s->connected = 1; - if (s->ioc) { - chr->gsource = io_add_watch_poll(chr, s->ioc, - tcp_chr_read_poll, - tcp_chr_read, - chr, chr->gcontext); - } + chr->gsource = io_add_watch_poll(chr, s->ioc, + tcp_chr_read_poll, + tcp_chr_read, + chr, chr->gcontext); s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP); g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup, @@ -2496,7 +2496,9 @@ if test "$whpx" != "no" ; then #include <WinHvEmulation.h> int main(void) { WHV_CAPABILITY whpx_cap; - WHvGetCapability(WHvCapabilityCodeFeatures, &whpx_cap, sizeof(whpx_cap)); + UINT32 writtenSize; + WHvGetCapability(WHvCapabilityCodeFeatures, &whpx_cap, sizeof(whpx_cap), + &writtenSize); return 0; } EOF diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 096e8e98d7..aaebec1839 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -28,6 +28,7 @@ #include "hw/isa/isa.h" #include "hw/qdev.h" #include "qemu/timer.h" +#include "qapi/error.h" /* Missing features: @@ -663,8 +664,13 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp) CSState *s = CS4231A (dev); IsaDmaClass *k; - isa_init_irq (d, &s->pic, s->irq); s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->dma); + if (!s->isa_dma) { + error_setg(errp, "ISA controller does not support DMA"); + return; + } + + isa_init_irq(d, &s->pic, s->irq); k = ISADMA_GET_CLASS(s->isa_dma); k->register_channel(s->isa_dma, s->dma, cs_dma_read, s); diff --git a/hw/audio/gus.c b/hw/audio/gus.c index 3e864cd36d..8e0b27e0f2 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -241,6 +241,12 @@ static void gus_realizefn (DeviceState *dev, Error **errp) IsaDmaClass *k; struct audsettings as; + s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->emu.gusdma); + if (!s->isa_dma) { + error_setg(errp, "ISA controller does not support DMA"); + return; + } + AUD_register_card ("gus", &s->card); as.freq = s->freq; @@ -272,7 +278,6 @@ static void gus_realizefn (DeviceState *dev, Error **errp) isa_register_portio_list(d, &s->portio_list2, (s->port + 0x100) & 0xf00, gus_portio_list2, s, "gus"); - s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->emu.gusdma); k = ISADMA_GET_CLASS(s->isa_dma); k->register_channel(s->isa_dma, s->emu.gusdma, GUS_read_DMA, s); s->emu.himemaddr = s->himem; diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 31de264ab7..5a4d32364e 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -1371,6 +1371,13 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) SB16State *s = SB16 (dev); IsaDmaClass *k; + s->isa_hdma = isa_get_dma(isa_bus_from_device(isadev), s->hdma); + s->isa_dma = isa_get_dma(isa_bus_from_device(isadev), s->dma); + if (!s->isa_dma || !s->isa_hdma) { + error_setg(errp, "ISA controller does not support DMA"); + return; + } + isa_init_irq (isadev, &s->pic, s->irq); s->mixer_regs[0x80] = magic_of_irq (s->irq); @@ -1389,11 +1396,9 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) isa_register_portio_list(isadev, &s->portio_list, s->port, sb16_ioport_list, s, "sb16"); - s->isa_hdma = isa_get_dma(isa_bus_from_device(isadev), s->hdma); k = ISADMA_GET_CLASS(s->isa_hdma); k->register_channel(s->isa_hdma, s->hdma, SB_read_DMA, s); - s->isa_dma = isa_get_dma(isa_bus_from_device(isadev), s->dma); k = ISADMA_GET_CLASS(s->isa_dma); k->register_channel(s->isa_dma, s->dma, SB_read_DMA, s); diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 7b7dd41296..cd29e27d8f 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2695,7 +2695,10 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp) fdctrl->dma_chann = isa->dma; if (fdctrl->dma_chann != -1) { fdctrl->dma = isa_get_dma(isa_bus_from_device(isadev), isa->dma); - assert(fdctrl->dma); + if (!fdctrl->dma) { + error_setg(errp, "ISA controller does not support DMA"); + return; + } } qdev_set_legacy_instance_id(dev, isa->iobase, 2); diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index 629323312c..9a85038c8a 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -866,6 +866,10 @@ int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus) { s->bus_client.info = &can_sja_bus_client_info; + if (!bus) { + return -EINVAL; + } + if (can_bus_insert_client(bus, &s->bus_client) < 0) { return -1; } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 5b7a48f5a5..f5ab767ab5 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2607,9 +2607,10 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) /* check we are using a driver managing SG_IO (version 3 and after) */ rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { - error_setg(errp, "cannot get SG_IO version number: %s. " - "Is this a SCSI device?", - strerror(-rc)); + error_setg_errno(errp, -rc, "cannot get SG_IO version number"); + if (rc != -EPERM) { + error_append_hint(errp, "Is this a SCSI device?\n"); + } return; } if (sg_version < 30000) { diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7414fe2d67..4753f8738f 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -500,9 +500,10 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) /* check we are using a driver managing SG_IO (version 3 and after */ rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { - error_setg(errp, "cannot get SG_IO version number: %s. " - "Is this a SCSI device?", - strerror(-rc)); + error_setg_errno(errp, -rc, "cannot get SG_IO version number"); + if (rc != -EPERM) { + error_append_hint(errp, "Is this a SCSI device?\n"); + } return; } if (sg_version < 30000) { 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/iothread.c b/iothread.c index 1b3463cb00..e675c38442 100644 --- a/iothread.c +++ b/iothread.c @@ -31,11 +31,15 @@ typedef ObjectClass IOThreadClass; #define IOTHREAD_CLASS(klass) \ OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) +#ifdef CONFIG_POSIX /* Benchmark results from 2016 on NVMe SSD drives show max polling times around * 16-32 microseconds yield IOPS improvements for both iodepth=1 and iodepth=32 * workloads. */ #define IOTHREAD_POLL_MAX_NS_DEFAULT 32768ULL +#else +#define IOTHREAD_POLL_MAX_NS_DEFAULT 0ULL +#endif static __thread IOThread *my_iothread; 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/device-crash-test b/scripts/device-crash-test index f04f34924e..24c7bf5a16 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -218,11 +218,7 @@ ERROR_WHITELIST = [ {'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR}, {'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR}, {'exitcode':-6, 'device':'isa-fdc', 'loglevel':logging.ERROR, 'expected':True}, - {'exitcode':-11, 'device':'gus', 'loglevel':logging.ERROR, 'expected':True}, {'exitcode':-11, 'device':'isa-serial', 'loglevel':logging.ERROR, 'expected':True}, - {'exitcode':-11, 'device':'sb16', 'loglevel':logging.ERROR, 'expected':True}, - {'exitcode':-11, 'device':'cs4231a', 'loglevel':logging.ERROR, 'expected':True}, - {'exitcode':-11, 'machine':'isapc', 'device':'.*-iommu', 'loglevel':logging.ERROR, 'expected':True}, {'exitcode':-11, 'device':'mioe3680_pci', 'loglevel':logging.ERROR, 'expected':True}, {'exitcode':-11, 'device':'pcm3680_pci', 'loglevel':logging.ERROR, 'expected':True}, {'exitcode':-11, 'device':'kvaser_pci', 'loglevel':logging.ERROR, 'expected':True}, diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 07369aa8ea..43fb5f512f 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -381,8 +381,8 @@ foreach my $file (@ARGV) { ##if $file is a directory and it lacks a trailing slash, add one if ((-d $file)) { $file =~ s@([^/])$@$1/@; - } elsif (!(-f $file)) { - die "$P: file '${file}' not found\n"; + } elsif (!(stat $file)) { + die "$P: file '${file}' not found: $!\n"; } } if ($from_filename) { diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 3facbba170..21e1b8ea60 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -903,12 +903,12 @@ static int drop_privileges(void) int main(int argc, char **argv) { - const char *sopt = "hVk:fdT:u:g:vq"; + const char *sopt = "hVk:f:dT:u:g:vq"; struct option lopt[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "socket", required_argument, NULL, 'k' }, - { "pidfile", no_argument, NULL, 'f' }, + { "pidfile", required_argument, NULL, 'f' }, { "daemon", no_argument, NULL, 'd' }, { "trace", required_argument, NULL, 'T' }, { "user", required_argument, NULL, 'u' }, @@ -952,7 +952,8 @@ int main(int argc, char **argv) } break; case 'f': - pidfile = optarg; + g_free(pidfile); + pidfile = g_strdup(optarg); break; #ifdef CONFIG_LIBCAP case 'u': { diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c index 940bbe590d..bf33d320bf 100644 --- a/target/i386/whpx-all.c +++ b/target/i386/whpx-all.c @@ -153,7 +153,7 @@ struct whpx_vcpu { bool interruptable; uint64_t tpr; uint64_t apic_base; - WHV_X64_PENDING_INTERRUPTION_REGISTER interrupt_in_flight; + bool interruption_pending; /* Must be the last field as it may have a tail */ WHV_RUN_VP_EXIT_CONTEXT exit_ctx; @@ -695,7 +695,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) qemu_mutex_lock_iothread(); /* Inject NMI */ - if (!vcpu->interrupt_in_flight.InterruptionPending && + if (!vcpu->interruption_pending && cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) { if (cpu->interrupt_request & CPU_INTERRUPT_NMI) { cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; @@ -724,7 +724,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) } /* Get pending hard interruption or replay one that was overwritten */ - if (!vcpu->interrupt_in_flight.InterruptionPending && + if (!vcpu->interruption_pending && vcpu->interruptable && (env->eflags & IF_MASK)) { assert(!new_int.InterruptionPending); if (cpu->interrupt_request & CPU_INTERRUPT_HARD) { @@ -781,44 +781,25 @@ static void whpx_vcpu_pre_run(CPUState *cpu) static void whpx_vcpu_post_run(CPUState *cpu) { - HRESULT hr; - struct whpx_state *whpx = &whpx_global; struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); X86CPU *x86_cpu = X86_CPU(cpu); - WHV_REGISTER_VALUE reg_values[4]; - const WHV_REGISTER_NAME reg_names[4] = { - WHvX64RegisterRflags, - WHvX64RegisterCr8, - WHvRegisterPendingInterruption, - WHvRegisterInterruptState, - }; - hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, - reg_names, 4, reg_values); - if (FAILED(hr)) { - error_report("WHPX: Failed to get interrupt state regusters," - " hr=%08lx", hr); - vcpu->interruptable = false; - return; - } + env->eflags = vcpu->exit_ctx.VpContext.Rflags; - assert(reg_names[0] == WHvX64RegisterRflags); - env->eflags = reg_values[0].Reg64; - - assert(reg_names[1] == WHvX64RegisterCr8); - if (vcpu->tpr != reg_values[1].Reg64) { - vcpu->tpr = reg_values[1].Reg64; + uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8; + if (vcpu->tpr != tpr) { + vcpu->tpr = tpr; qemu_mutex_lock_iothread(); cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr); qemu_mutex_unlock_iothread(); } - assert(reg_names[2] == WHvRegisterPendingInterruption); - vcpu->interrupt_in_flight = reg_values[2].PendingInterruption; + vcpu->interruption_pending = + vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending; - assert(reg_names[3] == WHvRegisterInterruptState); - vcpu->interruptable = !reg_values[3].InterruptState.InterruptShadow; + vcpu->interruptable = + !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow; return; } @@ -1254,6 +1235,7 @@ static int whpx_accel_init(MachineState *ms) int ret; HRESULT hr; WHV_CAPABILITY whpx_cap; + UINT32 whpx_cap_size; WHV_PARTITION_PROPERTY prop; whpx = &whpx_global; @@ -1262,7 +1244,7 @@ static int whpx_accel_init(MachineState *ms) whpx->mem_quota = ms->ram_size; hr = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &whpx_cap, - sizeof(whpx_cap)); + sizeof(whpx_cap), &whpx_cap_size); if (FAILED(hr) || !whpx_cap.HypervisorPresent) { error_report("WHPX: No accelerator found, hr=%08lx", hr); ret = -ENOSPC; @@ -1277,9 +1259,9 @@ static int whpx_accel_init(MachineState *ms) } memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); - prop.PropertyCode = WHvPartitionPropertyCodeProcessorCount; prop.ProcessorCount = smp_cpus; hr = WHvSetPartitionProperty(whpx->partition, + WHvPartitionPropertyCodeProcessorCount, &prop, sizeof(WHV_PARTITION_PROPERTY)); 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/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 diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index 22e9202b8d..61d997253c 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -18,6 +18,7 @@ #include "qemu/range.h" #include "qemu/sockets.h" #include "chardev/char-fe.h" +#include "qemu/memfd.h" #include "sysemu/sysemu.h" #include "libqos/libqos.h" #include "libqos/pci-pc.h" @@ -40,23 +41,14 @@ #define HAVE_MONOTONIC_TIME #endif -#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM,"\ +#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \ "mem-path=%s,share=on -numa node,memdev=mem" +#define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \ + " -numa node,memdev=mem" #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s" #define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce" #define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0" -#define QEMU_CMD QEMU_CMD_MEM QEMU_CMD_CHR \ - QEMU_CMD_NETDEV QEMU_CMD_NET - -#define GET_QEMU_CMD(s) \ - g_strdup_printf(QEMU_CMD, 512, 512, (root), (s)->chr_name, \ - (s)->socket_path, "", (s)->chr_name) - -#define GET_QEMU_CMDE(s, mem, chr_opts, extra, ...) \ - g_strdup_printf(QEMU_CMD extra, (mem), (mem), (root), (s)->chr_name, \ - (s)->socket_path, (chr_opts), (s)->chr_name, ##__VA_ARGS__) - #define HUGETLBFS_MAGIC 0x958458f6 /*********** FROM hw/virtio/vhost-user.c *************************************/ @@ -175,6 +167,33 @@ static void test_server_listen(TestServer *server); static const char *tmpfs; static const char *root; +enum test_memfd { + TEST_MEMFD_AUTO, + TEST_MEMFD_YES, + TEST_MEMFD_NO, +}; + +static char *get_qemu_cmd(TestServer *s, + int mem, enum test_memfd memfd, const char *mem_path, + const char *chr_opts, const char *extra) +{ + if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check()) { + memfd = TEST_MEMFD_YES; + } + + if (memfd == TEST_MEMFD_YES) { + return g_strdup_printf(QEMU_CMD_MEMFD QEMU_CMD_CHR + QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem, + s->chr_name, s->socket_path, + chr_opts, s->chr_name, extra); + } else { + return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR + QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem, + mem_path, s->chr_name, s->socket_path, + chr_opts, s->chr_name, extra); + } +} + static void init_virtio_dev(TestServer *s, uint32_t features_mask) { uint32_t features; @@ -494,6 +513,7 @@ static void test_server_create_chr(TestServer *server, const gchar *opt) chr = qemu_chr_new(server->chr_name, chr_path); g_free(chr_path); + g_assert_nonnull(chr); qemu_chr_fe_init(&server->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, chr_event, NULL, server, NULL, true); @@ -640,16 +660,18 @@ GSourceFuncs test_migrate_source_funcs = { .check = test_migrate_source_check, }; -static void test_read_guest_mem(void) +static void test_read_guest_mem(const void *arg) { + enum test_memfd memfd = GPOINTER_TO_INT(arg); TestServer *server = NULL; char *qemu_cmd = NULL; QTestState *s = NULL; - server = test_server_new("test"); + server = test_server_new(memfd == TEST_MEMFD_YES ? + "read-guest-memfd" : "read-guest-mem"); test_server_listen(server); - qemu_cmd = GET_QEMU_CMD(server); + qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", ""); s = qtest_start(qemu_cmd); g_free(qemu_cmd); @@ -671,7 +693,7 @@ static void test_migrate(void) char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path); QTestState *global = global_qtest, *from, *to; GSource *source; - gchar *cmd; + gchar *cmd, *tmp; QDict *rsp; guint8 *log; guint64 size; @@ -679,7 +701,7 @@ static void test_migrate(void) test_server_listen(s); test_server_listen(dest); - cmd = GET_QEMU_CMDE(s, 2, "", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", ""); from = qtest_start(cmd); g_free(cmd); @@ -688,7 +710,9 @@ static void test_migrate(void) size = get_log_size(s); g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8)); - cmd = GET_QEMU_CMDE(dest, 2, "", " -incoming %s", uri); + tmp = g_strdup_printf(" -incoming %s", uri); + cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp); + g_free(tmp); to = qtest_init(cmd); g_free(cmd); @@ -801,7 +825,7 @@ static void test_reconnect_subprocess(void) char *cmd; g_thread_new("connect", connect_thread, s); - cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -839,7 +863,7 @@ static void test_connect_fail_subprocess(void) s->test_fail = true; g_thread_new("connect", connect_thread, s); - cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -869,7 +893,7 @@ static void test_flags_mismatch_subprocess(void) s->test_flags = TEST_FLAGS_DISCONNECT; g_thread_new("connect", connect_thread, s); - cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -904,11 +928,21 @@ static void test_multiqueue(void) s->queues = 2; test_server_listen(s); - cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " - "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", - 512, 512, root, s->chr_name, - s->socket_path, "", s->chr_name, - s->queues, s->queues * 2 + 2); + if (qemu_memfd_check()) { + cmd = g_strdup_printf( + QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " + "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", + 512, 512, s->chr_name, + s->socket_path, "", s->chr_name, + s->queues, s->queues * 2 + 2); + } else { + cmd = g_strdup_printf( + QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " + "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", + 512, 512, root, s->chr_name, + s->socket_path, "", s->chr_name, + s->queues, s->queues * 2 + 2); + } qtest_start(cmd); g_free(cmd); @@ -954,7 +988,13 @@ int main(int argc, char **argv) /* run the main loop thread so the chardev may operate */ thread = g_thread_new(NULL, thread_function, loop); - qtest_add_func("/vhost-user/read-guest-mem", test_read_guest_mem); + if (qemu_memfd_check()) { + qtest_add_data_func("/vhost-user/read-guest-mem/memfd", + GINT_TO_POINTER(TEST_MEMFD_YES), + test_read_guest_mem); + } + qtest_add_data_func("/vhost-user/read-guest-mem/memfile", + GINT_TO_POINTER(TEST_MEMFD_NO), test_read_guest_mem); qtest_add_func("/vhost-user/migrate", test_migrate); qtest_add_func("/vhost-user/multiqueue", test_multiqueue); diff --git a/util/aio-win32.c b/util/aio-win32.c index d6d5e02f00..a67b00c6ad 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -410,5 +410,7 @@ void aio_context_setup(AioContext *ctx) void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, int64_t grow, int64_t shrink, Error **errp) { - error_setg(errp, "AioContext polling is not implemented on Windows"); + if (max_ns) { + error_setg(errp, "AioContext polling is not implemented on Windows"); + } } |