aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml55
-rw-r--r--block.c21
-rw-r--r--block/blkdebug.c22
-rw-r--r--block/raw-posix.c18
-rw-r--r--block/vpc.c44
-rw-r--r--blockdev.c103
-rwxr-xr-xconfigure18
-rw-r--r--docs/blkdebug.txt161
-rw-r--r--docs/qapi-code-gen.txt100
-rw-r--r--include/qemu/option.h1
-rw-r--r--include/sysemu/blockdev.h1
-rw-r--r--os-posix.c83
-rw-r--r--qemu-img.c6
-rw-r--r--qemu-nbd.c2
-rwxr-xr-xscripts/kvm/vmxcap10
-rw-r--r--stubs/Makefile.objs1
-rw-r--r--stubs/blockdev.c12
-rw-r--r--tests/.gitignore3
-rw-r--r--tests/Makefile35
-rw-r--r--tests/libqos/virtio.c50
-rw-r--r--tests/libqos/virtio.h13
-rwxr-xr-xtests/qemu-iotests/05123
-rw-r--r--tests/qemu-iotests/051.out45
-rw-r--r--tests/qemu-iotests/087.out2
-rw-r--r--tests/qemu-iotests/common10
-rw-r--r--tests/virtio-blk-test.c55
-rw-r--r--util/qemu-option.c4
27 files changed, 675 insertions, 223 deletions
diff --git a/.travis.yml b/.travis.yml
index 89c30aefa7..ad66e5bca3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ notifications:
on_failure: always
env:
global:
- - TEST_CMD="make check"
+ - TEST_CMD=""
- EXTRA_CONFIG=""
# Development packages, EXTRA_PKGS saved for additional builds
- CORE_PKGS="libusb-1.0-0-dev libiscsi-dev librados-dev libncurses5-dev"
@@ -20,31 +20,51 @@ env:
- GUI_PKGS="libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev"
- EXTRA_PKGS=""
matrix:
+ # Group major targets together with their linux-user counterparts
- TARGETS=alpha-softmmu,alpha-linux-user
- - TARGETS=arm-softmmu,arm-linux-user
- - TARGETS=aarch64-softmmu,aarch64-linux-user
- - TARGETS=cris-softmmu
- - TARGETS=i386-softmmu,x86_64-softmmu
- - TARGETS=lm32-softmmu
- - TARGETS=m68k-softmmu
- - TARGETS=microblaze-softmmu,microblazeel-softmmu
+ - TARGETS=arm-softmmu,arm-linux-user,armeb-linux-user,aarch64-softmmu,aarch64-linux-user
+ - TARGETS=cris-softmmu,cris-linux-user
+ - TARGETS=i386-softmmu,i386-linux-user,x86_64-softmmu,x86_64-linux-user
+ - TARGETS=m68k-softmmu,m68k-linux-user
+ - TARGETS=microblaze-softmmu,microblazeel-softmmu,microblaze-linux-user,microblazeel-linux-user
- TARGETS=mips-softmmu,mips64-softmmu,mips64el-softmmu,mipsel-softmmu
- - TARGETS=moxie-softmmu
- - TARGETS=or32-softmmu,
- - TARGETS=ppc-softmmu,ppc64-softmmu,ppcemb-softmmu
- - TARGETS=s390x-softmmu
- - TARGETS=sh4-softmmu,sh4eb-softmmu
- - TARGETS=sparc-softmmu,sparc64-softmmu
- - TARGETS=unicore32-softmmu
- - TARGETS=xtensa-softmmu,xtensaeb-softmmu
+ - TARGETS=mips-linux-user,mips64-linux-user,mips64el-linux-user,mipsel-linux-user,mipsn32-linux-user,mipsn32el-linux-user
+ - TARGETS=or32-softmmu,or32-linux-user
+ - TARGETS=ppc-softmmu,ppc64-softmmu,ppcemb-softmmu,ppc-linux-user,ppc64-linux-user,ppc64abi32-linux-user,ppc64le-linux-user
+ - TARGETS=s390x-softmmu,s390x-linux-user
+ - TARGETS=sh4-softmmu,sh4eb-softmmu,sh4-linux-user sh4eb-linux-user
+ - TARGETS=sparc-softmmu,sparc64-softmmu,sparc-linux-user,sparc32plus-linux-user,sparc64-linux-user
+ - TARGETS=unicore32-softmmu,unicore32-linux-user
+ # Group remaining softmmu only targets into one build
+ - TARGETS=lm32-softmmu,moxie-softmmu,tricore-softmmu,xtensa-softmmu,xtensaeb-softmmu
+git:
+ # we want to do this ourselves
+ submodules: false
before_install:
+ - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
- git submodule update --init --recursive
- sudo apt-get update -qq
- sudo apt-get install -qq ${CORE_PKGS} ${NET_PKGS} ${GUI_PKGS} ${EXTRA_PKGS}
-script: "./configure --target-list=${TARGETS} ${EXTRA_CONFIG} && make && ${TEST_CMD}"
+before_script:
+ - ./configure --target-list=${TARGETS} --enable-debug-tcg ${EXTRA_CONFIG}
+script:
+ - make -j2 && ${TEST_CMD}
matrix:
# We manually include a number of additional build for non-standard bits
include:
+ # Make check target (we only do this once)
+ - env:
+ - TARGETS=alpha-softmmu,arm-softmmu,aarch64-softmmu,cris-softmmu,
+ i386-softmmu,x86_64-softmmu,m68k-softmmu,microblaze-softmmu,
+ microblazeel-softmmu,mips-softmmu,mips64-softmmu,
+ mips64el-softmmu,mipsel-softmmu,or32-softmmu,ppc-softmmu,
+ ppc64-softmmu,ppcemb-softmmu,s390x-softmmu,sh4-softmmu,
+ sh4eb-softmmu,sparc-softmmu,sparc64-softmmu,
+ unicore32-softmmu,unicore32-linux-user,
+ lm32-softmmu,moxie-softmmu,tricore-softmmu,xtensa-softmmu,
+ xtensaeb-softmmu
+ TEST_CMD="make check"
+ compiler: gcc
# Debug related options
- env: TARGETS=i386-softmmu,x86_64-softmmu
EXTRA_CONFIG="--enable-debug"
@@ -73,7 +93,6 @@ matrix:
compiler: gcc
- env: TARGETS=i386-softmmu,x86_64-softmmu
EXTRA_CONFIG="--enable-trace-backends=ftrace"
- TEST_CMD=""
compiler: gcc
- env: TARGETS=i386-softmmu,x86_64-softmmu
EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
diff --git a/block.c b/block.c
index a857913fc2..c5a251c57e 100644
--- a/block.c
+++ b/block.c
@@ -29,6 +29,7 @@
#include "qemu/module.h"
#include "qapi/qmp/qjson.h"
#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h" /* FIXME layering violation */
#include "qemu/notify.h"
#include "block/coroutine.h"
#include "block/qapi.h"
@@ -334,19 +335,30 @@ void bdrv_register(BlockDriver *bdrv)
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
}
+static bool bdrv_is_valid_name(const char *name)
+{
+ return qemu_opts_id_wellformed(name);
+}
+
/* create a new block device (by default it is empty) */
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
{
BlockDriverState *bs;
int i;
+ if (*device_name && !bdrv_is_valid_name(device_name)) {
+ error_setg(errp, "Invalid device name");
+ return NULL;
+ }
+
if (bdrv_find(device_name)) {
error_setg(errp, "Device with id '%s' already exists",
device_name);
return NULL;
}
if (bdrv_find_node(device_name)) {
- error_setg(errp, "Device with node-name '%s' already exists",
+ error_setg(errp,
+ "Device name '%s' conflicts with an existing node name",
device_name);
return NULL;
}
@@ -861,9 +873,9 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
return;
}
- /* empty string node name is invalid */
- if (node_name[0] == '\0') {
- error_setg(errp, "Empty node name");
+ /* Check for empty string or invalid characters */
+ if (!bdrv_is_valid_name(node_name)) {
+ error_setg(errp, "Invalid node name");
return;
}
@@ -2110,6 +2122,7 @@ static void bdrv_delete(BlockDriverState *bs)
/* remove from list, if necessary */
bdrv_make_anon(bs);
+ drive_info_del(drive_get_by_blockdev(bs));
g_free(bs);
}
diff --git a/block/blkdebug.c b/block/blkdebug.c
index ced0b600f9..f8fbb0f3d4 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -214,6 +214,7 @@ static int get_event_by_name(const char *name, BlkDebugEvent *event)
struct add_rule_data {
BDRVBlkdebugState *s;
int action;
+ Error **errp;
};
static int add_rule(QemuOpts *opts, void *opaque)
@@ -226,7 +227,11 @@ static int add_rule(QemuOpts *opts, void *opaque)
/* Find the right event for the rule */
event_name = qemu_opt_get(opts, "event");
- if (!event_name || get_event_by_name(event_name, &event) < 0) {
+ if (!event_name) {
+ error_setg(d->errp, "Missing event name for rule");
+ return -1;
+ } else if (get_event_by_name(event_name, &event) < 0) {
+ error_setg(d->errp, "Invalid event name \"%s\"", event_name);
return -1;
}
@@ -312,10 +317,21 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
d.s = s;
d.action = ACTION_INJECT_ERROR;
- qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
+ d.errp = &local_err;
+ qemu_opts_foreach(&inject_error_opts, add_rule, &d, 1);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail;
+ }
d.action = ACTION_SET_STATE;
- qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
+ qemu_opts_foreach(&set_state_opts, add_rule, &d, 1);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail;
+ }
ret = 0;
fail:
diff --git a/block/raw-posix.c b/block/raw-posix.c
index a253697427..86ce4f2607 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1416,16 +1416,21 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
goto out_close;
}
- if (prealloc == PREALLOC_MODE_FALLOC) {
+ switch (prealloc) {
+#ifdef CONFIG_POSIX_FALLOCATE
+ case PREALLOC_MODE_FALLOC:
/* posix_fallocate() doesn't set errno. */
result = -posix_fallocate(fd, 0, total_size);
if (result != 0) {
error_setg_errno(errp, -result,
"Could not preallocate data for the new file");
}
- } else if (prealloc == PREALLOC_MODE_FULL) {
- buf = g_malloc0(65536);
+ break;
+#endif
+ case PREALLOC_MODE_FULL:
+ {
int64_t num = 0, left = total_size;
+ buf = g_malloc0(65536);
while (left > 0) {
num = MIN(left, 65536);
@@ -1440,10 +1445,15 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
}
fsync(fd);
g_free(buf);
- } else if (prealloc != PREALLOC_MODE_OFF) {
+ break;
+ }
+ case PREALLOC_MODE_OFF:
+ break;
+ default:
result = -EINVAL;
error_setg(errp, "Unsupported preallocation mode: %s",
PreallocMode_lookup[prealloc]);
+ break;
}
out_close:
diff --git a/block/vpc.c b/block/vpc.c
index 4947369d48..e08144a76e 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -207,7 +207,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
"incorrect.\n", bs->filename);
/* Write 'checksum' back to footer, or else will leave it with zero. */
- footer->checksum = be32_to_cpu(checksum);
+ footer->checksum = cpu_to_be32(checksum);
// The visible size of a image in Virtual PC depends on the geometry
// rather than on the size stored in the footer (the size in the footer
@@ -472,7 +472,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
// Write BAT entry to disk
bat_offset = s->bat_offset + (4 * index);
- bat_value = be32_to_cpu(s->pagetable[index]);
+ bat_value = cpu_to_be32(s->pagetable[index]);
ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
if (ret < 0)
goto fail;
@@ -699,13 +699,13 @@ static int create_dynamic_disk(BlockDriverState *bs, uint8_t *buf,
* Note: The spec is actually wrong here for data_offset, it says
* 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
*/
- dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
- dyndisk_header->table_offset = be64_to_cpu(3 * 512);
- dyndisk_header->version = be32_to_cpu(0x00010000);
- dyndisk_header->block_size = be32_to_cpu(block_size);
- dyndisk_header->max_table_entries = be32_to_cpu(num_bat_entries);
+ dyndisk_header->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
+ dyndisk_header->table_offset = cpu_to_be64(3 * 512);
+ dyndisk_header->version = cpu_to_be32(0x00010000);
+ dyndisk_header->block_size = cpu_to_be32(block_size);
+ dyndisk_header->max_table_entries = cpu_to_be32(num_bat_entries);
- dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
+ dyndisk_header->checksum = cpu_to_be32(vpc_checksum(buf, 1024));
// Write the header
offset = 512;
@@ -810,36 +810,36 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
memcpy(footer->creator_app, "qemu", 4);
memcpy(footer->creator_os, "Wi2k", 4);
- footer->features = be32_to_cpu(0x02);
- footer->version = be32_to_cpu(0x00010000);
+ footer->features = cpu_to_be32(0x02);
+ footer->version = cpu_to_be32(0x00010000);
if (disk_type == VHD_DYNAMIC) {
- footer->data_offset = be64_to_cpu(HEADER_SIZE);
+ footer->data_offset = cpu_to_be64(HEADER_SIZE);
} else {
- footer->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
+ footer->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
}
- footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+ footer->timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE);
/* Version of Virtual PC 2007 */
- footer->major = be16_to_cpu(0x0005);
- footer->minor = be16_to_cpu(0x0003);
+ footer->major = cpu_to_be16(0x0005);
+ footer->minor = cpu_to_be16(0x0003);
if (disk_type == VHD_DYNAMIC) {
- footer->orig_size = be64_to_cpu(total_sectors * 512);
- footer->size = be64_to_cpu(total_sectors * 512);
+ footer->orig_size = cpu_to_be64(total_sectors * 512);
+ footer->size = cpu_to_be64(total_sectors * 512);
} else {
- footer->orig_size = be64_to_cpu(total_size);
- footer->size = be64_to_cpu(total_size);
+ footer->orig_size = cpu_to_be64(total_size);
+ footer->size = cpu_to_be64(total_size);
}
- footer->cyls = be16_to_cpu(cyls);
+ footer->cyls = cpu_to_be16(cyls);
footer->heads = heads;
footer->secs_per_cyl = secs_per_cyl;
- footer->type = be32_to_cpu(disk_type);
+ footer->type = cpu_to_be32(disk_type);
#if defined(CONFIG_UUID)
uuid_generate(footer->uuid);
#endif
- footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+ footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE));
if (disk_type == VHD_DYNAMIC) {
ret = create_dynamic_disk(bs, buf, total_sectors);
diff --git a/blockdev.c b/blockdev.c
index b361fbb964..ad436488b7 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -216,11 +216,17 @@ static void bdrv_format_print(void *opaque, const char *name)
void drive_del(DriveInfo *dinfo)
{
+ bdrv_unref(dinfo->bdrv);
+}
+
+void drive_info_del(DriveInfo *dinfo)
+{
+ if (!dinfo) {
+ return;
+ }
if (dinfo->opts) {
qemu_opts_del(dinfo->opts);
}
-
- bdrv_unref(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo->serial);
@@ -301,6 +307,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
int ro = 0;
int bdrv_flags = 0;
int on_read_error, on_write_error;
+ BlockDriverState *bs;
DriveInfo *dinfo;
ThrottleConfig cfg;
int snapshot = 0;
@@ -456,26 +463,27 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
}
/* init */
- dinfo = g_malloc0(sizeof(*dinfo));
- dinfo->id = g_strdup(qemu_opts_id(opts));
- dinfo->bdrv = bdrv_new(dinfo->id, &error);
- if (error) {
- error_propagate(errp, error);
- goto bdrv_new_err;
+ bs = bdrv_new(qemu_opts_id(opts), errp);
+ if (!bs) {
+ goto early_err;
}
- dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
- dinfo->bdrv->read_only = ro;
- dinfo->bdrv->detect_zeroes = detect_zeroes;
- QTAILQ_INSERT_TAIL(&drives, dinfo, next);
+ bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
+ bs->read_only = ro;
+ bs->detect_zeroes = detect_zeroes;
- bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
+ bdrv_set_on_error(bs, on_read_error, on_write_error);
/* disk I/O throttling */
if (throttle_enabled(&cfg)) {
- bdrv_io_limits_enable(dinfo->bdrv);
- bdrv_set_io_limits(dinfo->bdrv, &cfg);
+ bdrv_io_limits_enable(bs);
+ bdrv_set_io_limits(bs, &cfg);
}
+ dinfo = g_malloc0(sizeof(*dinfo));
+ dinfo->id = g_strdup(qemu_opts_id(opts));
+ dinfo->bdrv = bs;
+ QTAILQ_INSERT_TAIL(&drives, dinfo, next);
+
if (!file || !*file) {
if (has_driver_specific_opts) {
file = NULL;
@@ -502,7 +510,8 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
QINCREF(bs_opts);
- ret = bdrv_open(&dinfo->bdrv, file, NULL, bs_opts, bdrv_flags, drv, &error);
+ ret = bdrv_open(&bs, file, NULL, bs_opts, bdrv_flags, drv, &error);
+ assert(bs == dinfo->bdrv);
if (ret < 0) {
error_setg(errp, "could not open disk image %s: %s",
@@ -511,8 +520,9 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
goto err;
}
- if (bdrv_key_required(dinfo->bdrv))
+ if (bdrv_key_required(bs)) {
autostart = 0;
+ }
QDECREF(bs_opts);
qemu_opts_del(opts);
@@ -520,11 +530,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
return dinfo;
err:
- bdrv_unref(dinfo->bdrv);
- QTAILQ_REMOVE(&drives, dinfo, next);
-bdrv_new_err:
- g_free(dinfo->id);
- g_free(dinfo);
+ bdrv_unref(bs);
early_err:
qemu_opts_del(opts);
err_no_opts:
@@ -532,12 +538,18 @@ err_no_opts:
return NULL;
}
-static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to)
+static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
+ Error **errp)
{
const char *value;
value = qemu_opt_get(opts, from);
if (value) {
+ if (qemu_opt_find(opts, to)) {
+ error_setg(errp, "'%s' and its alias '%s' can't be used at the "
+ "same time", to, from);
+ return;
+ }
qemu_opt_set(opts, to, value);
qemu_opt_unset(opts, from);
}
@@ -641,28 +653,43 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
const char *serial;
const char *filename;
Error *local_err = NULL;
+ int i;
/* Change legacy command line options into QMP ones */
- qemu_opt_rename(all_opts, "iops", "throttling.iops-total");
- qemu_opt_rename(all_opts, "iops_rd", "throttling.iops-read");
- qemu_opt_rename(all_opts, "iops_wr", "throttling.iops-write");
+ static const struct {
+ const char *from;
+ const char *to;
+ } opt_renames[] = {
+ { "iops", "throttling.iops-total" },
+ { "iops_rd", "throttling.iops-read" },
+ { "iops_wr", "throttling.iops-write" },
- qemu_opt_rename(all_opts, "bps", "throttling.bps-total");
- qemu_opt_rename(all_opts, "bps_rd", "throttling.bps-read");
- qemu_opt_rename(all_opts, "bps_wr", "throttling.bps-write");
+ { "bps", "throttling.bps-total" },
+ { "bps_rd", "throttling.bps-read" },
+ { "bps_wr", "throttling.bps-write" },
- qemu_opt_rename(all_opts, "iops_max", "throttling.iops-total-max");
- qemu_opt_rename(all_opts, "iops_rd_max", "throttling.iops-read-max");
- qemu_opt_rename(all_opts, "iops_wr_max", "throttling.iops-write-max");
+ { "iops_max", "throttling.iops-total-max" },
+ { "iops_rd_max", "throttling.iops-read-max" },
+ { "iops_wr_max", "throttling.iops-write-max" },
- qemu_opt_rename(all_opts, "bps_max", "throttling.bps-total-max");
- qemu_opt_rename(all_opts, "bps_rd_max", "throttling.bps-read-max");
- qemu_opt_rename(all_opts, "bps_wr_max", "throttling.bps-write-max");
+ { "bps_max", "throttling.bps-total-max" },
+ { "bps_rd_max", "throttling.bps-read-max" },
+ { "bps_wr_max", "throttling.bps-write-max" },
- qemu_opt_rename(all_opts,
- "iops_size", "throttling.iops-size");
+ { "iops_size", "throttling.iops-size" },
- qemu_opt_rename(all_opts, "readonly", "read-only");
+ { "readonly", "read-only" },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(opt_renames); i++) {
+ qemu_opt_rename(all_opts, opt_renames[i].from, opt_renames[i].to,
+ &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
+ return NULL;
+ }
+ }
value = qemu_opt_get(all_opts, "cache");
if (value) {
diff --git a/configure b/configure
index a2c0f2a02a..681abfc669 100755
--- a/configure
+++ b/configure
@@ -3308,6 +3308,21 @@ if compile_prog "" "" ; then
fallocate_punch_hole=yes
fi
+# check for posix_fallocate
+posix_fallocate=no
+cat > $TMPC << EOF
+#include <fcntl.h>
+
+int main(void)
+{
+ posix_fallocate(0, 0, 0);
+ return 0;
+}
+EOF
+if compile_prog "" "" ; then
+ posix_fallocate=yes
+fi
+
# check for sync_file_range
sync_file_range=no
cat > $TMPC << EOF
@@ -4522,6 +4537,9 @@ fi
if test "$fallocate_punch_hole" = "yes" ; then
echo "CONFIG_FALLOCATE_PUNCH_HOLE=y" >> $config_host_mak
fi
+if test "$posix_fallocate" = "yes" ; then
+ echo "CONFIG_POSIX_FALLOCATE=y" >> $config_host_mak
+fi
if test "$sync_file_range" = "yes" ; then
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
fi
diff --git a/docs/blkdebug.txt b/docs/blkdebug.txt
new file mode 100644
index 0000000000..5dde07234f
--- /dev/null
+++ b/docs/blkdebug.txt
@@ -0,0 +1,161 @@
+Block I/O error injection using blkdebug
+----------------------------------------
+Copyright (C) 2014 Red Hat Inc
+
+This work is licensed under the terms of the GNU GPL, version 2 or later. See
+the COPYING file in the top-level directory.
+
+The blkdebug block driver is a rule-based error injection engine. It can be
+used to exercise error code paths in block drivers including ENOSPC (out of
+space) and EIO.
+
+This document gives an overview of the features available in blkdebug.
+
+Background
+----------
+Block drivers have many error code paths that handle I/O errors. Image formats
+are especially complex since metadata I/O errors during cluster allocation or
+while updating tables happen halfway through request processing and require
+discipline to keep image files consistent.
+
+Error injection allows test cases to trigger I/O errors at specific points.
+This way, all error paths can be tested to make sure they are correct.
+
+Rules
+-----
+The blkdebug block driver takes a list of "rules" that tell the error injection
+engine when to fail an I/O request.
+
+Each I/O request is evaluated against the rules. If a rule matches the request
+then its "action" is executed.
+
+Rules can be placed in a configuration file; the configuration file
+follows the same .ini-like format used by QEMU's -readconfig option, and
+each section of the file represents a rule.
+
+The following configuration file defines a single rule:
+
+ $ cat blkdebug.conf
+ [inject-error]
+ event = "read_aio"
+ errno = "28"
+
+This rule fails all aio read requests with ENOSPC (28). Note that the errno
+value depends on the host. On Linux, see
+/usr/include/asm-generic/errno-base.h for errno values.
+
+Invoke QEMU as follows:
+
+ $ qemu-system-x86_64
+ -drive if=none,cache=none,file=blkdebug:blkdebug.conf:test.img,id=drive0 \
+ -device virtio-blk-pci,drive=drive0,id=virtio-blk-pci0
+
+Rules support the following attributes:
+
+ event - which type of operation to match (e.g. read_aio, write_aio,
+ flush_to_os, flush_to_disk). See the "Events" section for
+ information on events.
+
+ state - (optional) the engine must be in this state number in order for this
+ rule to match. See the "State transitions" section for information
+ on states.
+
+ errno - the numeric errno value to return when a request matches this rule.
+ The errno values depend on the host since the numeric values are not
+ standarized in the POSIX specification.
+
+ sector - (optional) a sector number that the request must overlap in order to
+ match this rule
+
+ once - (optional, default "off") only execute this action on the first
+ matching request
+
+ immediately - (optional, default "off") return a NULL BlockDriverAIOCB
+ pointer and fail without an errno instead. This exercises the
+ code path where BlockDriverAIOCB fails and the caller's
+ BlockDriverCompletionFunc is not invoked.
+
+Events
+------
+Block drivers provide information about the type of I/O request they are about
+to make so rules can match specific types of requests. For example, the qcow2
+block driver tells blkdebug when it accesses the L1 table so rules can match
+only L1 table accesses and not other metadata or guest data requests.
+
+The core events are:
+
+ read_aio - guest data read
+
+ write_aio - guest data write
+
+ flush_to_os - write out unwritten block driver state (e.g. cached metadata)
+
+ flush_to_disk - flush the host block device's disk cache
+
+See block/blkdebug.c:event_names[] for the full list of events. You may need
+to grep block driver source code to understand the meaning of specific events.
+
+State transitions
+-----------------
+There are cases where more power is needed to match a particular I/O request in
+a longer sequence of requests. For example:
+
+ write_aio
+ flush_to_disk
+ write_aio
+
+How do we match the 2nd write_aio but not the first? This is where state
+transitions come in.
+
+The error injection engine has an integer called the "state" that always starts
+initialized to 1. The state integer is internal to blkdebug and cannot be
+observed from outside but rules can interact with it for powerful matching
+behavior.
+
+Rules can be conditional on the current state and they can transition to a new
+state.
+
+When a rule's "state" attribute is non-zero then the current state must equal
+the attribute in order for the rule to match.
+
+For example, to match the 2nd write_aio:
+
+ [set-state]
+ event = "write_aio"
+ state = "1"
+ new_state = "2"
+
+ [inject-error]
+ event = "write_aio"
+ state = "2"
+ errno = "5"
+
+The first write_aio request matches the set-state rule and transitions from
+state 1 to state 2. Once state 2 has been entered, the set-state rule no
+longer matches since it requires state 1. But the inject-error rule now
+matches the next write_aio request and injects EIO (5).
+
+State transition rules support the following attributes:
+
+ event - which type of operation to match (e.g. read_aio, write_aio,
+ flush_to_os, flush_to_disk). See the "Events" section for
+ information on events.
+
+ state - (optional) the engine must be in this state number in order for this
+ rule to match
+
+ new_state - transition to this state number
+
+Suspend and resume
+------------------
+Exercising code paths in block drivers may require specific ordering amongst
+concurrent requests. The "breakpoint" feature allows requests to be halted on
+a blkdebug event and resumed later. This makes it possible to achieve
+deterministic ordering when multiple requests are in flight.
+
+Breakpoints on blkdebug events are associated with a user-defined "tag" string.
+This tag serves as an identifier by which the request can be resumed at a later
+point.
+
+See the qemu-io(1) break, resume, remove_break, and wait_break commands for
+details.
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index a6197a9133..8313ba6af8 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -1,10 +1,5 @@
= How to use the QAPI code generator =
-* Note: as of this writing, QMP does not use QAPI. Eventually QMP
-commands will be converted to use QAPI internally. The following
-information describes QMP/QAPI as it will exist after the
-conversion.
-
QAPI is a native C API within QEMU which provides management-level
functionality to internal/external users. For external
users/processes, this interface is made available by a JSON-based
@@ -19,7 +14,7 @@ marshaling/dispatch code for the guest agent server running in the
guest.
This document will describe how the schemas, scripts, and resulting
-code is used.
+code are used.
== QMP/Guest agent schema ==
@@ -234,6 +229,7 @@ Resulting in this JSON object:
"data": { "b": "test string" },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+
== Code generation ==
Schemas are fed into 3 scripts to generate all the code/files that, paired
@@ -256,6 +252,8 @@ command which takes that type as a parameter and returns the same type:
'data': {'arg1': 'UserDefOne'},
'returns': 'UserDefOne' }
+ { 'event': 'MY_EVENT' }
+
=== scripts/qapi-types.py ===
Used to generate the C types defined by a schema. The following files are
@@ -277,7 +275,7 @@ Example:
$ cat qapi-generated/example-qapi-types.c
[Uninteresting stuff omitted...]
- void qapi_free_UserDefOneList(UserDefOneList * obj)
+ void qapi_free_UserDefOneList(UserDefOneList *obj)
{
QapiDeallocVisitor *md;
Visitor *v;
@@ -292,7 +290,7 @@ Example:
qapi_dealloc_visitor_cleanup(md);
}
- void qapi_free_UserDefOne(UserDefOne * obj)
+ void qapi_free_UserDefOne(UserDefOne *obj)
{
QapiDeallocVisitor *md;
Visitor *v;
@@ -331,11 +329,11 @@ Example:
struct UserDefOne
{
int64_t integer;
- char * string;
+ char *string;
};
- void qapi_free_UserDefOneList(UserDefOneList * obj);
- void qapi_free_UserDefOne(UserDefOne * obj);
+ void qapi_free_UserDefOneList(UserDefOneList *obj);
+ void qapi_free_UserDefOne(UserDefOne *obj);
#endif
@@ -364,7 +362,7 @@ Example:
$ cat qapi-generated/example-qapi-visit.c
[Uninteresting stuff omitted...]
- static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
+ static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne **obj, Error **errp)
{
Error *err = NULL;
visit_type_int(m, &(*obj)->integer, "integer", &err);
@@ -380,7 +378,7 @@ Example:
error_propagate(errp, err);
}
- void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
+ void visit_type_UserDefOne(Visitor *m, UserDefOne **obj, const char *name, Error **errp)
{
Error *err = NULL;
@@ -394,7 +392,7 @@ Example:
error_propagate(errp, err);
}
- void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
+ void visit_type_UserDefOneList(Visitor *m, UserDefOneList **obj, const char *name, Error **errp)
{
Error *err = NULL;
GenericList *i, **prev;
@@ -427,8 +425,8 @@ Example:
[Visitors for builtin types omitted...]
- void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
- void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
+ void visit_type_UserDefOne(Visitor *m, UserDefOne **obj, const char *name, Error **errp);
+ void visit_type_UserDefOneList(Visitor *m, UserDefOneList **obj, const char *name, Error **errp);
#endif
@@ -451,10 +449,12 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
Example:
+ $ python scripts/qapi-commands.py --output-dir="qapi-generated"
+ --prefix="example-" --input-file=example-schema.json
$ cat qapi-generated/example-qmp-marshal.c
[Uninteresting stuff omitted...]
- static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
+ static void qmp_marshal_output_my_command(UserDefOne *ret_in, QObject **ret_out, Error **errp)
{
Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new();
@@ -480,11 +480,11 @@ Example:
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
{
Error *local_err = NULL;
- UserDefOne * retval = NULL;
+ UserDefOne *retval = NULL;
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
Visitor *v;
- UserDefOne * arg1 = NULL;
+ UserDefOne *arg1 = NULL;
v = qmp_input_get_visitor(mi);
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
@@ -525,6 +525,66 @@ Example:
#include "qapi/qmp/qdict.h"
#include "qapi/error.h"
- UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
+ UserDefOne *qmp_my_command(UserDefOne *arg1, Error **errp);
+
+ #endif
+
+=== scripts/qapi-event.py ===
+
+Used to generate the event-related C code defined by a schema. The
+following files are created:
+
+$(prefix)qapi-event.h - Function prototypes for each event type, plus an
+ enumeration of all event names
+$(prefix)qapi-event.c - Implementation of functions to send an event
+
+Example:
+
+ $ python scripts/qapi-event.py --output-dir="qapi-generated"
+ --prefix="example-" --input-file=example-schema.json
+ $ cat qapi-generated/example-qapi-event.c
+[Uninteresting stuff omitted...]
+
+ void qapi_event_send_my_event(Error **errp)
+ {
+ QDict *qmp;
+ Error *local_err = NULL;
+ QMPEventFuncEmit emit;
+ emit = qmp_event_get_func_emit();
+ if (!emit) {
+ return;
+ }
+
+ qmp = qmp_event_build_dict("MY_EVENT");
+
+ emit(EXAMPLE_QAPI_EVENT_MY_EVENT, qmp, &local_err);
+
+ error_propagate(errp, local_err);
+ QDECREF(qmp);
+ }
+
+ const char *EXAMPLE_QAPIEvent_lookup[] = {
+ "MY_EVENT",
+ NULL,
+ };
+ $ cat qapi-generated/example-qapi-event.h
+[Uninteresting stuff omitted...]
+
+ #ifndef EXAMPLE_QAPI_EVENT_H
+ #define EXAMPLE_QAPI_EVENT_H
+
+ #include "qapi/error.h"
+ #include "qapi/qmp/qdict.h"
+ #include "example-qapi-types.h"
+
+
+ void qapi_event_send_my_event(Error **errp);
+
+ extern const char *EXAMPLE_QAPIEvent_lookup[];
+ typedef enum EXAMPLE_QAPIEvent
+ {
+ EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
+ EXAMPLE_QAPI_EVENT_MAX = 1,
+ } EXAMPLE_QAPIEvent;
#endif
diff --git a/include/qemu/option.h b/include/qemu/option.h
index 59bea759a2..945347cc8f 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -103,6 +103,7 @@ typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaq
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
int abort_on_failure);
+int qemu_opts_id_wellformed(const char *id);
QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id);
QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
int fail_if_exists, Error **errp);
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 23a5d10c68..abec381049 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -56,6 +56,7 @@ QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
const char *optstr);
DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type);
void drive_del(DriveInfo *dinfo);
+void drive_info_del(DriveInfo *dinfo);
/* device-hotplug */
diff --git a/os-posix.c b/os-posix.c
index cb2a7f7ad7..4898ebf4a2 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -204,45 +204,49 @@ static void change_root(void)
void os_daemonize(void)
{
if (daemonize) {
- pid_t pid;
+ pid_t pid;
- if (pipe(fds) == -1)
- exit(1);
+ if (pipe(fds) == -1) {
+ exit(1);
+ }
- pid = fork();
- if (pid > 0) {
- uint8_t status;
- ssize_t len;
+ pid = fork();
+ if (pid > 0) {
+ uint8_t status;
+ ssize_t len;
- close(fds[1]);
+ close(fds[1]);
- again:
+ again:
len = read(fds[0], &status, 1);
- if (len == -1 && (errno == EINTR))
+ if (len == -1 && (errno == EINTR)) {
goto again;
-
- if (len != 1)
+ }
+ if (len != 1) {
exit(1);
+ }
else if (status == 1) {
- fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
+ fprintf(stderr, "Could not acquire pidfile\n");
exit(1);
- } else
+ } else {
exit(0);
- } else if (pid < 0)
- exit(1);
-
- close(fds[0]);
- qemu_set_cloexec(fds[1]);
+ }
+ } else if (pid < 0) {
+ exit(1);
+ }
- setsid();
+ close(fds[0]);
+ qemu_set_cloexec(fds[1]);
- pid = fork();
- if (pid > 0)
- exit(0);
- else if (pid < 0)
- exit(1);
+ setsid();
- umask(027);
+ pid = fork();
+ if (pid > 0) {
+ exit(0);
+ } else if (pid < 0) {
+ exit(1);
+ }
+ umask(027);
signal(SIGTSTP, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
@@ -255,24 +259,25 @@ void os_setup_post(void)
int fd = 0;
if (daemonize) {
- uint8_t status = 0;
- ssize_t len;
+ uint8_t status = 0;
+ ssize_t len;
again1:
- len = write(fds[1], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again1;
-
- if (len != 1)
- exit(1);
-
+ len = write(fds[1], &status, 1);
+ if (len == -1 && (errno == EINTR)) {
+ goto again1;
+ }
+ if (len != 1) {
+ exit(1);
+ }
if (chdir("/")) {
perror("not able to chdir to /");
exit(1);
}
- TFR(fd = qemu_open("/dev/null", O_RDWR));
- if (fd == -1)
- exit(1);
+ TFR(fd = qemu_open("/dev/null", O_RDWR));
+ if (fd == -1) {
+ exit(1);
+ }
}
change_root();
@@ -314,6 +319,8 @@ int qemu_create_pidfile(const char *filename)
return -1;
}
if (lockf(fd, F_TLOCK, 0) == -1) {
+ fprintf(stderr, "lock file '%s' failed: %s\n",
+ filename, strerror(errno));
close(fd);
return -1;
}
diff --git a/qemu-img.c b/qemu-img.c
index dbf0904dc0..ea4bbae546 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1011,14 +1011,14 @@ static int img_compare(int argc, char **argv)
goto out3;
}
- bs1 = bdrv_new_open("image 1", filename1, fmt1, flags, true, quiet);
+ bs1 = bdrv_new_open("image_1", filename1, fmt1, flags, true, quiet);
if (!bs1) {
error_report("Can't open file %s", filename1);
ret = 2;
goto out3;
}
- bs2 = bdrv_new_open("image 2", filename2, fmt2, flags, true, quiet);
+ bs2 = bdrv_new_open("image_2", filename2, fmt2, flags, true, quiet);
if (!bs2) {
error_report("Can't open file %s", filename2);
ret = 2;
@@ -1359,7 +1359,7 @@ static int img_convert(int argc, char **argv)
total_sectors = 0;
for (bs_i = 0; bs_i < bs_n; bs_i++) {
- char *id = bs_n > 1 ? g_strdup_printf("source %d", bs_i)
+ char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i)
: g_strdup("source");
bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, src_flags,
true, quiet);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index de9963f8fb..fa603382d4 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -773,7 +773,7 @@ int main(int argc, char **argv)
}
} while (state != TERMINATED);
- bdrv_close(bs);
+ bdrv_unref(bs);
if (sockpath) {
unlink(sockpath);
}
diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap
index c90eda497a..8f0371f498 100755
--- a/scripts/kvm/vmxcap
+++ b/scripts/kvm/vmxcap
@@ -99,7 +99,7 @@ controls = [
Misc(
name = 'Basic VMX Information',
bits = {
- (0, 31): 'Revision',
+ (0, 30): 'Revision',
(32,44): 'VMCS size',
48: 'VMCS restricted to 32 bit addresses',
49: 'Dual-monitor support',
@@ -169,7 +169,9 @@ controls = [
12: 'Enable INVPCID',
13: 'Enable VM functions',
14: 'VMCS shadowing',
- 18: 'EPT-violation #VE'
+ 16: 'RDSEED exiting',
+ 18: 'EPT-violation #VE',
+ 20: 'Enable XSAVES/XRSTORS',
},
cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2,
),
@@ -195,7 +197,7 @@ controls = [
name = 'VM-Entry controls',
bits = {
2: 'Load debug controls',
- 9: 'IA-64 mode guest',
+ 9: 'IA-32e mode guest',
10: 'Entry to SMM',
11: 'Deactivate dual-monitor treatment',
13: 'Load IA32_PERF_GLOBAL_CTRL',
@@ -216,7 +218,7 @@ controls = [
8: 'Wait-for-SIPI activity state',
15: 'IA32_SMBASE support',
(16,24): 'Number of CR3-target values',
- (25,27): 'MSR-load/store count recommenation',
+ (25,27): 'MSR-load/store count recommendation',
28: 'IA32_SMM_MONITOR_CTL[2] can be set to 1',
29: 'VMWRITE to VM-exit information fields',
(32,63): 'MSEG revision identifier',
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 5e347d04bd..c0b1f6a320 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -1,5 +1,6 @@
stub-obj-y += arch-query-cpu-def.o
stub-obj-y += bdrv-commit-all.o
+stub-obj-y += blockdev.o
stub-obj-y += chr-baum-init.o
stub-obj-y += chr-msmouse.o
stub-obj-y += chr-testdev.o
diff --git a/stubs/blockdev.c b/stubs/blockdev.c
new file mode 100644
index 0000000000..5d0a79c3a6
--- /dev/null
+++ b/stubs/blockdev.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include "sysemu/blockdev.h"
+
+DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
+{
+ return NULL;
+}
+
+void drive_info_del(DriveInfo *dinfo)
+{
+ assert(!dinfo);
+}
diff --git a/tests/.gitignore b/tests/.gitignore
index c71c11020e..e2e4957332 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -14,11 +14,14 @@ test-int128
test-iov
test-mul64
test-opts-visitor
+test-qapi-event.[ch]
test-qapi-types.[ch]
test-qapi-visit.[ch]
test-qdev-global-props
+test-qemu-opts
test-qmp-commands
test-qmp-commands.h
+test-qmp-event
test-qmp-input-strict
test-qmp-input-visitor
test-qmp-marshal.c
diff --git a/tests/Makefile b/tests/Makefile
index f5de29c0b9..834279cd0d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -193,26 +193,27 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
# qom-test works for all sysemu architectures:
$(foreach target,$(SYSEMU_TARGET_LIST), \
- $(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF)))
+ $(if $(findstring tests/qom-test$(EXESUF), $(check-qtest-$(target)-y)),, \
+ $(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF))))
check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
- comments.json empty.json funny-char.json indented-expr.json \
- missing-colon.json missing-comma-list.json \
- missing-comma-object.json non-objects.json \
- qapi-schema-test.json quoted-structural-chars.json \
- trailing-comma-list.json trailing-comma-object.json \
- unclosed-list.json unclosed-object.json unclosed-string.json \
- duplicate-key.json union-invalid-base.json flat-union-no-base.json \
- flat-union-invalid-discriminator.json \
- flat-union-invalid-branch-key.json flat-union-reverse-define.json \
- flat-union-string-discriminator.json \
- include-simple.json include-relpath.json include-format-err.json \
- include-non-file.json include-no-file.json include-before-err.json \
- include-nested-err.json include-self-cycle.json include-cycle.json \
- include-repetition.json event-nest-struct.json)
+ comments.json empty.json funny-char.json indented-expr.json \
+ missing-colon.json missing-comma-list.json \
+ missing-comma-object.json non-objects.json \
+ qapi-schema-test.json quoted-structural-chars.json \
+ trailing-comma-list.json trailing-comma-object.json \
+ unclosed-list.json unclosed-object.json unclosed-string.json \
+ duplicate-key.json union-invalid-base.json flat-union-no-base.json \
+ flat-union-invalid-discriminator.json \
+ flat-union-invalid-branch-key.json flat-union-reverse-define.json \
+ flat-union-string-discriminator.json \
+ include-simple.json include-relpath.json include-format-err.json \
+ include-non-file.json include-no-file.json include-before-err.json \
+ include-nested-err.json include-self-cycle.json include-cycle.json \
+ include-repetition.json event-nest-struct.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \
- tests/test-qmp-commands.h tests/test-qapi-event.h
+ tests/test-qmp-commands.h tests/test-qapi-event.h
test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \
@@ -224,7 +225,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/test-opts-visitor.o tests/test-qmp-event.o
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
- tests/test-qapi-event.o
+ tests/test-qapi-event.o
$(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 9b6de2c0a7..a061289249 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -78,30 +78,54 @@ void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d)
QVIRTIO_DRIVER_OK | QVIRTIO_DRIVER | QVIRTIO_ACKNOWLEDGE);
}
-bool qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d,
- QVirtQueue *vq, uint64_t timeout)
+void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d,
+ QVirtQueue *vq, gint64 timeout_us)
{
- do {
+ gint64 start_time = g_get_monotonic_time();
+
+ for (;;) {
clock_step(100);
if (bus->get_queue_isr_status(d, vq)) {
- break; /* It has ended */
+ return;
}
- } while (--timeout);
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
+ }
+}
+
+/* Wait for the status byte at given guest memory address to be set
+ *
+ * The virtqueue interrupt must not be raised, making this useful for testing
+ * event_index functionality.
+ */
+uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus,
+ QVirtioDevice *d,
+ QVirtQueue *vq,
+ uint64_t addr,
+ gint64 timeout_us)
+{
+ gint64 start_time = g_get_monotonic_time();
+ uint8_t val;
- return timeout != 0;
+ while ((val = readb(addr)) == 0xff) {
+ clock_step(100);
+ g_assert(!bus->get_queue_isr_status(d, vq));
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
+ }
+ return val;
}
-bool qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d,
- uint64_t timeout)
+void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d,
+ gint64 timeout_us)
{
- do {
+ gint64 start_time = g_get_monotonic_time();
+
+ for (;;) {
clock_step(100);
if (bus->get_config_isr_status(d)) {
- break; /* It has ended */
+ return;
}
- } while (--timeout);
-
- return timeout != 0;
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
+ }
}
void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr)
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 70b3376360..29fbacbc99 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -160,10 +160,15 @@ void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d);
void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d);
void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d);
-bool qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d,
- QVirtQueue *vq, uint64_t timeout);
-bool qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d,
- uint64_t timeout);
+void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d,
+ QVirtQueue *vq, gint64 timeout_us);
+uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus,
+ QVirtioDevice *d,
+ QVirtQueue *vq,
+ uint64_t addr,
+ gint64 timeout_us);
+void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d,
+ gint64 timeout_us);
QVirtQueue *qvirtqueue_setup(const QVirtioBus *bus, QVirtioDevice *d,
QGuestAllocator *alloc, uint16_t index);
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index a41334e022..11c858f27d 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -199,6 +199,29 @@ run_qemu -drive file.driver=raw
run_qemu -drive foo=bar
echo
+echo === Specifying both an option and its legacy alias ===
+echo
+
+run_qemu -drive file="$TEST_IMG",iops=1234,throttling.iops-total=5678
+run_qemu -drive file="$TEST_IMG",iops_rd=1234,throttling.iops-read=5678
+run_qemu -drive file="$TEST_IMG",iops_wr=1234,throttling.iops-write=5678
+
+run_qemu -drive file="$TEST_IMG",bps=1234,throttling.bps-total=5678
+run_qemu -drive file="$TEST_IMG",bps_rd=1234,throttling.bps-read=5678
+run_qemu -drive file="$TEST_IMG",bps_wr=1234,throttling.bps-write=5678
+
+run_qemu -drive file="$TEST_IMG",iops_max=1234,throttling.iops-total-max=5678
+run_qemu -drive file="$TEST_IMG",iops_rd_max=1234,throttling.iops-read-max=5678
+run_qemu -drive file="$TEST_IMG",iops_wr_max=1234,throttling.iops-write-max=5678
+
+run_qemu -drive file="$TEST_IMG",bps_max=1234,throttling.bps-total-max=5678
+run_qemu -drive file="$TEST_IMG",bps_rd_max=1234,throttling.bps-read-max=5678
+run_qemu -drive file="$TEST_IMG",bps_wr_max=1234,throttling.bps-write-max=5678
+
+run_qemu -drive file="$TEST_IMG",iops_size=1234,throttling.iops-size=5678
+run_qemu -drive file="$TEST_IMG",readonly=on,read-only=off
+
+echo
echo === Parsing protocol from file name ===
echo
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index a3f28209c8..2c7e808765 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -274,6 +274,51 @@ Testing: -drive foo=bar
QEMU_PROG: -drive foo=bar: could not open disk image ide0-hd0: Must specify either driver or file
+=== Specifying both an option and its legacy alias ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678: 'throttling.iops-total' and its alias 'iops' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678: 'throttling.iops-read' and its alias 'iops_rd' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678: 'throttling.iops-write' and its alias 'iops_wr' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678: 'throttling.bps-total' and its alias 'bps' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678: 'throttling.bps-read' and its alias 'bps_rd' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678: 'throttling.bps-write' and its alias 'bps_wr' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678: 'throttling.iops-total-max' and its alias 'iops_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678: 'throttling.iops-read-max' and its alias 'iops_rd_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678: 'throttling.iops-write-max' and its alias 'iops_wr_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678: 'throttling.bps-total-max' and its alias 'bps_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678: 'throttling.bps-read-max' and its alias 'bps_rd_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678: 'throttling.bps-write-max' and its alias 'bps_wr_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678: 'throttling.iops-size' and its alias 'iops_size' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' and its alias 'readonly' can't be used at the same time
+
+
=== Parsing protocol from file name ===
Testing: -hda foo:bar
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index f16bad0ab6..e8795b3a10 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -20,7 +20,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}}
-{"error": {"class": "GenericError", "desc": "Device with node-name 'test-node' already exists"}}
+{"error": {"class": "GenericError", "desc": "Device name 'test-node' conflicts with an existing node name"}}
main-loop: WARNING: I/O thread spun for 1000 iterations
{"error": {"class": "GenericError", "desc": "could not open disk image disk2: node-name=disk is conflicting with a device id"}}
{"error": {"class": "GenericError", "desc": "could not open disk image disk2: Duplicate node name"}}
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index 89c6dde263..9e12bec2bf 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -376,10 +376,16 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
echo $id >>$tmp.list
else
# oops
- echo "$id - unknown test, ignored"
+ if [ "$start" == "$end" -a "$id" == "$end" ]
+ then
+ echo "$id - unknown test"
+ exit 1
+ else
+ echo "$id - unknown test, ignored"
+ fi
fi
fi
- done
+ done || exit 1
fi
done
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 588666cff1..5ce6e79757 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -41,7 +41,7 @@
#define QVIRTIO_BLK_T_GET_ID 8
#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
-#define QVIRTIO_BLK_TIMEOUT 100
+#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
#define PCI_SLOT 0x04
#define PCI_FN 0x00
@@ -183,8 +183,8 @@ static void pci_basic(void)
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -205,8 +205,8 @@ static void pci_basic(void)
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -233,8 +233,8 @@ static void pci_basic(void)
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -256,8 +256,8 @@ static void pci_basic(void)
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -329,8 +329,8 @@ static void pci_indirect(void)
free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -354,8 +354,8 @@ static void pci_indirect(void)
free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -396,8 +396,7 @@ static void pci_config(void)
qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
" 'size': %d } }", n_size);
- g_assert(qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
g_assert_cmpint(capacity, ==, n_size / 512);
@@ -452,8 +451,7 @@ static void pci_msix(void)
qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
" 'size': %d } }", n_size);
- g_assert(qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
g_assert_cmpint(capacity, ==, n_size / 512);
@@ -473,8 +471,8 @@ static void pci_msix(void)
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -497,8 +495,8 @@ static void pci_msix(void)
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -574,8 +572,8 @@ static void pci_idx(void)
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
/* Write request */
req.type = QVIRTIO_BLK_T_OUT;
@@ -595,10 +593,9 @@ static void pci_idx(void)
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
/* No notification expected */
- g_assert(!qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
-
- status = readb(req_addr + 528);
+ status = qvirtio_wait_status_byte_no_isr(&qvirtio_pci, &dev->vdev,
+ &vqpci->vq, req_addr + 528,
+ QVIRTIO_BLK_TIMEOUT_US);
g_assert_cmpint(status, ==, 0);
guest_free(alloc, req_addr);
@@ -619,8 +616,8 @@ static void pci_idx(void)
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
- g_assert(qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT));
+ qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
+ QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 6dc27ce04f..0cf9960fc5 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -641,7 +641,7 @@ QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
return NULL;
}
-static int id_wellformed(const char *id)
+int qemu_opts_id_wellformed(const char *id)
{
int i;
@@ -662,7 +662,7 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
QemuOpts *opts = NULL;
if (id) {
- if (!id_wellformed(id)) {
+ if (!qemu_opts_id_wellformed(id)) {
error_set(errp,QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
#if 0 /* conversion from qerror_report() to error_set() broke this: */
error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n");