aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel/tcg/translate-all.c37
-rwxr-xr-xblock/blkreplay.c3
-rw-r--r--block/crypto.c6
-rw-r--r--block/parallels.c5
-rw-r--r--block/qcow2-refcount.c7
-rw-r--r--block/quorum.c3
-rw-r--r--block/replication.c1
-rw-r--r--block/throttle.c3
-rw-r--r--block/vdi.c46
-rw-r--r--block/vhdx.c17
-rw-r--r--chardev/char-fe.c22
-rw-r--r--chardev/char-socket.c10
-rwxr-xr-xconfigure4
-rw-r--r--hw/audio/cs4231a.c8
-rw-r--r--hw/audio/gus.c7
-rw-r--r--hw/audio/sb16.c9
-rw-r--r--hw/block/fdc.c5
-rw-r--r--hw/net/can/can_sja1000.c4
-rw-r--r--hw/scsi/scsi-disk.c7
-rw-r--r--hw/scsi/scsi-generic.c7
-rw-r--r--include/block/block_int.h8
-rw-r--r--iothread.c4
-rw-r--r--qapi/block-core.json7
-rw-r--r--replication.h1
-rwxr-xr-xscripts/device-crash-test4
-rwxr-xr-xscripts/get_maintainer.pl4
-rw-r--r--scsi/qemu-pr-helper.c7
-rw-r--r--target/i386/whpx-all.c46
-rwxr-xr-xtests/qemu-iotests/0259
-rw-r--r--tests/qemu-iotests/026.out6
-rwxr-xr-xtests/qemu-iotests/12120
-rw-r--r--tests/qemu-iotests/121.out10
-rwxr-xr-xtests/qemu-iotests/21037
-rw-r--r--tests/qemu-iotests/210.out16
-rwxr-xr-xtests/qemu-iotests/211246
-rw-r--r--tests/qemu-iotests/211.out97
-rwxr-xr-xtests/qemu-iotests/212326
-rw-r--r--tests/qemu-iotests/212.out111
-rwxr-xr-xtests/qemu-iotests/213349
-rw-r--r--tests/qemu-iotests/213.out121
-rw-r--r--tests/qemu-iotests/group5
-rw-r--r--tests/vhost-user-test.c94
-rw-r--r--util/aio-win32.c4
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,
diff --git a/configure b/configure
index 8376cb151a..4d0e92c96c 100755
--- a/configure
+++ b/configure
@@ -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");
+ }
}