diff options
151 files changed, 2066 insertions, 1282 deletions
@@ -232,23 +232,35 @@ qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + " GEN $@") qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + " GEN $@") qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + " GEN $@") qapi-types.c qapi-types.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." -b < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ + $(gen-out-type) -o "." -b -i $<, \ + " GEN $@") qapi-visit.c qapi-visit.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." -b < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ + $(gen-out-type) -o "." -b -i $<, \ + " GEN $@") qmp-commands.h qmp-marshal.c :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ + $(gen-out-type) -o "." -m -i $<, \ + " GEN $@") QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) @@ -775,6 +775,16 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) } /* + * Returns the flags that a temporary snapshot should get, based on the + * originally requested flags (the originally requested image will have flags + * like a backing file) + */ +static int bdrv_temp_snapshot_flags(int flags) +{ + return (flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY; +} + +/* * Returns the flags that bs->file should get, based on the given flags for * the parent BDS */ @@ -787,11 +797,6 @@ static int bdrv_inherited_flags(int flags) * so we can enable both unconditionally on lower layers. */ flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP; - /* The backing file of a temporary snapshot is read-only */ - if (flags & BDRV_O_SNAPSHOT) { - flags &= ~BDRV_O_RDWR; - } - /* Clear flags that only apply to the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); @@ -817,11 +822,6 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags | BDRV_O_CACHE_WB; - /* The backing file of a temporary snapshot is read-only */ - if (flags & BDRV_O_SNAPSHOT) { - open_flags &= ~BDRV_O_RDWR; - } - /* * Clear flags that are internal to the block layer before opening the * image. @@ -1206,7 +1206,7 @@ done: return ret; } -void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) +void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) { /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ char *tmp_filename = g_malloc0(PATH_MAX + 1); @@ -1262,8 +1262,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) bs_snapshot = bdrv_new("", &error_abort); ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options, - (bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY, - bdrv_qcow2, &local_err); + flags, bdrv_qcow2, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -1298,6 +1297,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, BlockDriverState *file = NULL, *bs; const char *drvname; Error *local_err = NULL; + int snapshot_flags = 0; assert(pbs); @@ -1358,6 +1358,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, if (flags & BDRV_O_RDWR) { flags |= BDRV_O_ALLOW_RDWR; } + if (flags & BDRV_O_SNAPSHOT) { + snapshot_flags = bdrv_temp_snapshot_flags(flags); + flags = bdrv_backing_flags(flags); + } assert(file == NULL); ret = bdrv_open_image(&file, filename, options, "file", @@ -1417,8 +1421,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, /* For snapshot=on, create a temporary qcow2 overlay. bs points to the * temporary snapshot afterwards. */ - if (flags & BDRV_O_SNAPSHOT) { - bdrv_append_temp_snapshot(bs, &local_err); + if (snapshot_flags) { + bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err); if (local_err) { error_propagate(errp, local_err); goto close_and_fail; diff --git a/block/gluster.c b/block/gluster.c index 8836085646..d0726ec92c 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -207,6 +207,11 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename, "volume=%s image=%s transport=%s", gconf->server, gconf->port, gconf->volname, gconf->image, gconf->transport); + + /* glfs_init sometimes doesn't set errno although docs suggest that */ + if (errno == 0) + errno = EINVAL; + goto out; } return glfs; @@ -482,7 +487,7 @@ static int qemu_gluster_create(const char *filename, glfs = qemu_gluster_init(gconf, filename, errp); if (!glfs) { - ret = -EINVAL; + ret = -errno; goto out; } diff --git a/block/iscsi.c b/block/iscsi.c index a30202b4fe..52355b8bce 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2,7 +2,7 @@ * QEMU Block driver for iSCSI images * * Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com> - * Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de> + * Copyright (c) 2012-2014 Peter Lieven <pl@kamp.de> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/block/nfs.c b/block/nfs.c index 9fa831f160..539bd951df 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -256,6 +256,10 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename, error_setg(errp, "Invalid URL specified"); goto fail; } + if (!uri->server) { + error_setg(errp, "Invalid URL specified"); + goto fail; + } strp = strrchr(uri->path, '/'); if (strp == NULL) { error_setg(errp, "Invalid URL specified"); diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index e79895d11d..9507aef847 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -656,7 +656,9 @@ retry: /* Make sure that all offsets in the "allocated" range are representable * in an int64_t */ - if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) { + if (s->free_cluster_index > 0 && + s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) + { return -EFBIG; } diff --git a/block/raw-posix.c b/block/raw-posix.c index 3ce026db58..6586a0c9e1 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -146,6 +146,9 @@ typedef struct BDRVRawState { bool has_discard:1; bool has_write_zeroes:1; bool discard_zeroes:1; +#ifdef CONFIG_FIEMAP + bool skip_fiemap; +#endif } BDRVRawState; typedef struct BDRVRawReopenState { @@ -1272,53 +1275,29 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, return result; } -/* - * Returns true iff the specified sector is present in the disk image. Drivers - * not implementing the functionality are assumed to not support backing files, - * hence all their sectors are reported as allocated. - * - * If 'sector_num' is beyond the end of the disk image the return value is 0 - * and 'pnum' is set to 0. - * - * 'pnum' is set to the number of sectors (including and immediately following - * the specified sector) that are known to be in the same - * allocated/unallocated state. - * - * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes - * beyond the end of the disk image it will be clamped. - */ -static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, - int64_t sector_num, - int nb_sectors, int *pnum) +static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data, + off_t *hole, int nb_sectors, int *pnum) { - off_t start, data, hole; - int64_t ret; - - ret = fd_open(bs); - if (ret < 0) { - return ret; - } - - start = sector_num * BDRV_SECTOR_SIZE; - ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; - #ifdef CONFIG_FIEMAP - BDRVRawState *s = bs->opaque; + int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; struct { struct fiemap fm; struct fiemap_extent fe; } f; + if (s->skip_fiemap) { + return -ENOTSUP; + } + f.fm.fm_start = start; f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE; f.fm.fm_flags = 0; f.fm.fm_extent_count = 1; f.fm.fm_reserved = 0; if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) { - /* Assume everything is allocated. */ - *pnum = nb_sectors; - return ret; + s->skip_fiemap = true; + return -errno; } if (f.fm.fm_mapped_extents == 0) { @@ -1326,44 +1305,92 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, * f.fm.fm_start + f.fm.fm_length must be clamped to the file size! */ off_t length = lseek(s->fd, 0, SEEK_END); - hole = f.fm.fm_start; - data = MIN(f.fm.fm_start + f.fm.fm_length, length); + *hole = f.fm.fm_start; + *data = MIN(f.fm.fm_start + f.fm.fm_length, length); } else { - data = f.fe.fe_logical; - hole = f.fe.fe_logical + f.fe.fe_length; + *data = f.fe.fe_logical; + *hole = f.fe.fe_logical + f.fe.fe_length; if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) { ret |= BDRV_BLOCK_ZERO; } } -#elif defined SEEK_HOLE && defined SEEK_DATA + return ret; +#else + return -ENOTSUP; +#endif +} +static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data, + off_t *hole, int *pnum) +{ +#if defined SEEK_HOLE && defined SEEK_DATA BDRVRawState *s = bs->opaque; - hole = lseek(s->fd, start, SEEK_HOLE); - if (hole == -1) { + *hole = lseek(s->fd, start, SEEK_HOLE); + if (*hole == -1) { /* -ENXIO indicates that sector_num was past the end of the file. * There is a virtual hole there. */ assert(errno != -ENXIO); - /* Most likely EINVAL. Assume everything is allocated. */ - *pnum = nb_sectors; - return ret; + return -errno; } - if (hole > start) { - data = start; + if (*hole > start) { + *data = start; } else { /* On a hole. We need another syscall to find its end. */ - data = lseek(s->fd, start, SEEK_DATA); - if (data == -1) { - data = lseek(s->fd, 0, SEEK_END); + *data = lseek(s->fd, start, SEEK_DATA); + if (*data == -1) { + *data = lseek(s->fd, 0, SEEK_END); } } + + return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; #else - data = 0; - hole = start + nb_sectors * BDRV_SECTOR_SIZE; + return -ENOTSUP; #endif +} + +/* + * Returns true iff the specified sector is present in the disk image. Drivers + * not implementing the functionality are assumed to not support backing files, + * hence all their sectors are reported as allocated. + * + * If 'sector_num' is beyond the end of the disk image the return value is 0 + * and 'pnum' is set to 0. + * + * 'pnum' is set to the number of sectors (including and immediately following + * the specified sector) that are known to be in the same + * allocated/unallocated state. + * + * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes + * beyond the end of the disk image it will be clamped. + */ +static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, int *pnum) +{ + off_t start, data = 0, hole = 0; + int64_t ret; + + ret = fd_open(bs); + if (ret < 0) { + return ret; + } + + start = sector_num * BDRV_SECTOR_SIZE; + + ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum); + if (ret < 0) { + ret = try_seek_hole(bs, start, &data, &hole, pnum); + if (ret < 0) { + /* Assume everything is allocated. */ + data = 0; + hole = start + nb_sectors * BDRV_SECTOR_SIZE; + ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; + } + } if (data <= start) { /* On a data extent, compute sectors to the end of the extent. */ diff --git a/block/vmdk.c b/block/vmdk.c index 06a1f9f93b..480ea37d7c 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1496,6 +1496,19 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, return ret; } +static int vmdk_write_compressed(BlockDriverState *bs, + int64_t sector_num, + const uint8_t *buf, + int nb_sectors) +{ + BDRVVmdkState *s = bs->opaque; + if (s->num_extents == 1 && s->extents[0].compressed) { + return vmdk_write(bs, sector_num, buf, nb_sectors, false, false); + } else { + return -ENOTSUP; + } +} + static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors, @@ -2063,6 +2076,26 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) return spec_info; } +static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + int i; + BDRVVmdkState *s = bs->opaque; + assert(s->num_extents); + bdi->needs_compressed_writes = s->extents[0].compressed; + if (!s->extents[0].flat) { + bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; + } + /* See if we have multiple extents but they have different cases */ + for (i = 1; i < s->num_extents; i++) { + if (bdi->needs_compressed_writes != s->extents[i].compressed || + (bdi->cluster_size && bdi->cluster_size != + s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) { + return -ENOTSUP; + } + } + return 0; +} + static QEMUOptionParameter vmdk_create_options[] = { { .name = BLOCK_OPT_SIZE, @@ -2109,6 +2142,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_reopen_prepare = vmdk_reopen_prepare, .bdrv_read = vmdk_co_read, .bdrv_write = vmdk_co_write, + .bdrv_write_compressed = vmdk_write_compressed, .bdrv_co_write_zeroes = vmdk_co_write_zeroes, .bdrv_close = vmdk_close, .bdrv_create = vmdk_create, @@ -2118,6 +2152,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_has_zero_init = vmdk_has_zero_init, .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, + .bdrv_get_info = vmdk_get_info, .create_options = vmdk_create_options, }; @@ -4150,7 +4150,9 @@ echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" echo "vhost-scsi support $vhost_scsi" echo "Trace backend $trace_backend" +if test "$trace_backend" = "simple"; then echo "Trace output file $trace_file-<pid>" +fi if test "$spice" = "yes"; then echo "spice support $spice ($spice_protocol_version/$spice_server_version)" else @@ -4766,6 +4768,12 @@ if test "$gcov" = "yes" ; then echo "GCOV=$gcov_tool" >> $config_host_mak fi +iotests_common_env="tests/qemu-iotests/common.env" + +echo "# Automatically generated by configure - do not modify" > $iotests_common_env +echo >> $iotests_common_env +echo "PYTHON='$python'" >> $iotests_common_env + # use included Linux headers if test "$linux" = "yes" ; then mkdir -p linux-headers diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index d78921f875..26312d84e8 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -40,6 +40,17 @@ enumeration types and union types. Generally speaking, types definitions should always use CamelCase for the type names. Command names should be all lower case with words separated by a hyphen. + +=== Includes === + +The QAPI schema definitions can be modularized using the 'include' directive: + + { 'include': 'path/to/file.json'} + +The directive is evaluated recursively, and include paths are relative to the +file using the directive. + + === Complex types === A complex type is a dictionary containing a single key whose value is a @@ -49,10 +60,34 @@ example of a complex type is: { 'type': 'MyType', 'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } } -The use of '*' as a prefix to the name means the member is optional. Optional -members should always be added to the end of the dictionary to preserve -backwards compatibility. +The use of '*' as a prefix to the name means the member is optional. + +The default initialization value of an optional argument should not be changed +between versions of QEMU unless the new default maintains backward +compatibility to the user-visible behavior of the old default. + +With proper documentation, this policy still allows some flexibility; for +example, documenting that a default of 0 picks an optimal buffer size allows +one release to declare the optimal size at 512 while another release declares +the optimal size at 4096 - the user-visible behavior is not the bytes used by +the buffer, but the fact that the buffer was optimal size. + +On input structures (only mentioned in the 'data' side of a command), changing +from mandatory to optional is safe (older clients will supply the option, and +newer clients can benefit from the default); changing from optional to +mandatory is backwards incompatible (older clients may be omitting the option, +and must continue to work). + +On output structures (only mentioned in the 'returns' side of a command), +changing from mandatory to optional is in general unsafe (older clients may be +expecting the field, and could crash if it is missing), although it can be done +if the only way that the optional argument will be omitted is when it is +triggered by the presence of a new input flag to the command that older clients +don't know to send. Changing from optional to mandatory is safe. +A structure that is used in both input and output of various commands +must consider the backwards compatibility constraints of both directions +of use. A complex type definition can specify another complex type as its base. In this case, the fields of the base type are included as top-level fields @@ -221,7 +256,7 @@ created code. Example: mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \ - --output-dir="qapi-generated" --prefix="example-" < example-schema.json + --output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c /* AUTOMATICALLY GENERATED, DO NOT MODIFY */ @@ -291,7 +326,7 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor Example: mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \ - --output-dir="qapi-generated" --prefix="example-" < example-schema.json + --output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt index 3930a9ba70..4d86c2477b 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/writing-qmp-commands.txt @@ -308,12 +308,12 @@ Here's the implementation of the "hello-world" HMP command: void hmp_hello_world(Monitor *mon, const QDict *qdict) { const char *message = qdict_get_try_str(qdict, "message"); - Error *errp = NULL; + Error *err = NULL; - qmp_hello_world(!!message, message, &errp); - if (errp) { - monitor_printf(mon, "%s\n", error_get_pretty(errp)); - error_free(errp); + qmp_hello_world(!!message, message, &err); + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + error_free(err); return; } } @@ -328,7 +328,7 @@ There are three important points to be noticed: 2. hmp_hello_world() performs error checking. In this example we just print the error description to the user, but we could do more, like taking different actions depending on the error qmp_hello_world() returns -3. The "errp" variable must be initialized to NULL before performing the +3. The "err" variable must be initialized to NULL before performing the QMP call There's one last step to actually make the command available to monitor users, @@ -480,12 +480,12 @@ Here's the HMP counterpart of the query-alarm-clock command: void hmp_info_alarm_clock(Monitor *mon) { QemuAlarmClock *clock; - Error *errp = NULL; + Error *err = NULL; - clock = qmp_query_alarm_clock(&errp); - if (errp) { + clock = qmp_query_alarm_clock(&err); + if (err) { monitor_printf(mon, "Could not query alarm clock information\n"); - error_free(errp); + error_free(err); return; } @@ -631,12 +631,12 @@ has to traverse the list, it's shown below for reference: void hmp_info_alarm_methods(Monitor *mon) { TimerAlarmMethodList *method_list, *method; - Error *errp = NULL; + Error *err = NULL; - method_list = qmp_query_alarm_methods(&errp); - if (errp) { + method_list = qmp_query_alarm_methods(&err); + if (err) { monitor_printf(mon, "Could not query alarm methods\n"); - error_free(errp); + error_free(err); return; } @@ -86,7 +86,6 @@ typedef struct DumpState { bool has_filter; int64_t begin; int64_t length; - Error **errp; uint8_t *note_buf; /* buffer for notes */ size_t note_buf_offset; /* the writing place in note_buf */ @@ -1570,7 +1569,6 @@ static int dump_init(DumpState *s, int fd, bool has_format, nr_cpus++; } - s->errp = errp; s->fd = fd; s->has_filter = has_filter; s->begin = begin; @@ -1780,11 +1778,11 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, } if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { - if (create_kdump_vmcore(s) < 0 && !error_is_set(s->errp)) { + if (create_kdump_vmcore(s) < 0) { error_set(errp, QERR_IO_ERROR); } } else { - if (create_vmcore(s) < 0 && !error_is_set(s->errp)) { + if (create_vmcore(s) < 0) { error_set(errp, QERR_IO_ERROR); } } @@ -28,7 +28,8 @@ static void hmp_handle_error(Monitor *mon, Error **errp) { - if (error_is_set(errp)) { + assert(errp); + if (*errp) { monitor_printf(mon, "%s\n", error_get_pretty(*errp)); error_free(*errp); } @@ -754,10 +755,10 @@ void hmp_memsave(Monitor *mon, const QDict *qdict) uint32_t size = qdict_get_int(qdict, "size"); const char *filename = qdict_get_str(qdict, "filename"); uint64_t addr = qdict_get_int(qdict, "val"); - Error *errp = NULL; + Error *err = NULL; - qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &errp); - hmp_handle_error(mon, &errp); + qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &err); + hmp_handle_error(mon, &err); } void hmp_pmemsave(Monitor *mon, const QDict *qdict) @@ -765,21 +766,21 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) uint32_t size = qdict_get_int(qdict, "size"); const char *filename = qdict_get_str(qdict, "filename"); uint64_t addr = qdict_get_int(qdict, "val"); - Error *errp = NULL; + Error *err = NULL; - qmp_pmemsave(addr, size, filename, &errp); - hmp_handle_error(mon, &errp); + qmp_pmemsave(addr, size, filename, &err); + hmp_handle_error(mon, &err); } void hmp_ringbuf_write(Monitor *mon, const QDict *qdict) { const char *chardev = qdict_get_str(qdict, "device"); const char *data = qdict_get_str(qdict, "data"); - Error *errp = NULL; + Error *err = NULL; - qmp_ringbuf_write(chardev, data, false, 0, &errp); + qmp_ringbuf_write(chardev, data, false, 0, &err); - hmp_handle_error(mon, &errp); + hmp_handle_error(mon, &err); } void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) @@ -787,13 +788,13 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) uint32_t size = qdict_get_int(qdict, "size"); const char *chardev = qdict_get_str(qdict, "device"); char *data; - Error *errp = NULL; + Error *err = NULL; int i; - data = qmp_ringbuf_read(chardev, size, false, 0, &errp); - if (errp) { - monitor_printf(mon, "%s\n", error_get_pretty(errp)); - error_free(errp); + data = qmp_ringbuf_read(chardev, size, false, 0, &err); + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + error_free(err); return; } @@ -828,7 +829,7 @@ static bool key_is_missing(const BlockInfo *bdev) void hmp_cont(Monitor *mon, const QDict *qdict) { BlockInfoList *bdev_list, *bdev; - Error *errp = NULL; + Error *err = NULL; bdev_list = qmp_query_block(NULL); for (bdev = bdev_list; bdev; bdev = bdev->next) { @@ -839,8 +840,8 @@ void hmp_cont(Monitor *mon, const QDict *qdict) } } - qmp_cont(&errp); - hmp_handle_error(mon, &errp); + qmp_cont(&err); + hmp_handle_error(mon, &err); out: qapi_free_BlockInfoList(bdev_list); @@ -853,41 +854,41 @@ void hmp_system_wakeup(Monitor *mon, const QDict *qdict) void hmp_inject_nmi(Monitor *mon, const QDict *qdict) { - Error *errp = NULL; + Error *err = NULL; - qmp_inject_nmi(&errp); - hmp_handle_error(mon, &errp); + qmp_inject_nmi(&err); + hmp_handle_error(mon, &err); } void hmp_set_link(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_str(qdict, "name"); int up = qdict_get_bool(qdict, "up"); - Error *errp = NULL; + Error *err = NULL; - qmp_set_link(name, up, &errp); - hmp_handle_error(mon, &errp); + qmp_set_link(name, up, &err); + hmp_handle_error(mon, &err); } void hmp_block_passwd(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); const char *password = qdict_get_str(qdict, "password"); - Error *errp = NULL; + Error *err = NULL; - qmp_block_passwd(true, device, false, NULL, password, &errp); - hmp_handle_error(mon, &errp); + qmp_block_passwd(true, device, false, NULL, password, &err); + hmp_handle_error(mon, &err); } void hmp_balloon(Monitor *mon, const QDict *qdict) { int64_t value = qdict_get_int(qdict, "value"); - Error *errp = NULL; + Error *err = NULL; - qmp_balloon(value, &errp); - if (errp) { - monitor_printf(mon, "balloon: %s\n", error_get_pretty(errp)); - error_free(errp); + qmp_balloon(value, &err); + if (err) { + monitor_printf(mon, "balloon: %s\n", error_get_pretty(err)); + error_free(err); } } @@ -895,10 +896,10 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); int64_t size = qdict_get_int(qdict, "size"); - Error *errp = NULL; + Error *err = NULL; - qmp_block_resize(true, device, false, NULL, size, &errp); - hmp_handle_error(mon, &errp); + qmp_block_resize(true, device, false, NULL, size, &err); + hmp_handle_error(mon, &err); } void hmp_drive_mirror(Monitor *mon, const QDict *qdict) @@ -909,11 +910,11 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) int reuse = qdict_get_try_bool(qdict, "reuse", 0); int full = qdict_get_try_bool(qdict, "full", 0); enum NewImageMode mode; - Error *errp = NULL; + Error *err = NULL; if (!filename) { - error_set(&errp, QERR_MISSING_PARAMETER, "target"); - hmp_handle_error(mon, &errp); + error_set(&err, QERR_MISSING_PARAMETER, "target"); + hmp_handle_error(mon, &err); return; } @@ -926,8 +927,8 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) qmp_drive_mirror(device, filename, !!format, format, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, true, mode, false, 0, false, 0, false, 0, - false, 0, false, 0, &errp); - hmp_handle_error(mon, &errp); + false, 0, false, 0, &err); + hmp_handle_error(mon, &err); } void hmp_drive_backup(Monitor *mon, const QDict *qdict) @@ -938,11 +939,11 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict) int reuse = qdict_get_try_bool(qdict, "reuse", 0); int full = qdict_get_try_bool(qdict, "full", 0); enum NewImageMode mode; - Error *errp = NULL; + Error *err = NULL; if (!filename) { - error_set(&errp, QERR_MISSING_PARAMETER, "target"); - hmp_handle_error(mon, &errp); + error_set(&err, QERR_MISSING_PARAMETER, "target"); + hmp_handle_error(mon, &err); return; } @@ -954,8 +955,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict) qmp_drive_backup(device, filename, !!format, format, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, - true, mode, false, 0, false, 0, false, 0, &errp); - hmp_handle_error(mon, &errp); + true, mode, false, 0, false, 0, false, 0, &err); + hmp_handle_error(mon, &err); } void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) @@ -965,13 +966,13 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) const char *format = qdict_get_try_str(qdict, "format"); int reuse = qdict_get_try_bool(qdict, "reuse", 0); enum NewImageMode mode; - Error *errp = NULL; + Error *err = NULL; if (!filename) { /* In the future, if 'snapshot-file' is not specified, the snapshot will be taken internally. Today it's actually required. */ - error_set(&errp, QERR_MISSING_PARAMETER, "snapshot-file"); - hmp_handle_error(mon, &errp); + error_set(&err, QERR_MISSING_PARAMETER, "snapshot-file"); + hmp_handle_error(mon, &err); return; } @@ -979,18 +980,18 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) qmp_blockdev_snapshot_sync(true, device, false, NULL, filename, false, NULL, !!format, format, - true, mode, &errp); - hmp_handle_error(mon, &errp); + true, mode, &err); + hmp_handle_error(mon, &err); } void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); const char *name = qdict_get_str(qdict, "name"); - Error *errp = NULL; + Error *err = NULL; - qmp_blockdev_snapshot_internal_sync(device, name, &errp); - hmp_handle_error(mon, &errp); + qmp_blockdev_snapshot_internal_sync(device, name, &err); + hmp_handle_error(mon, &err); } void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict) @@ -998,11 +999,11 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict) const char *device = qdict_get_str(qdict, "device"); const char *name = qdict_get_str(qdict, "name"); const char *id = qdict_get_try_str(qdict, "id"); - Error *errp = NULL; + Error *err = NULL; qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id, - true, name, &errp); - hmp_handle_error(mon, &errp); + true, name, &err); + hmp_handle_error(mon, &err); } void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) @@ -1310,7 +1311,7 @@ void hmp_device_del(Monitor *mon, const QDict *qdict) void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) { - Error *errp = NULL; + Error *err = NULL; int paging = qdict_get_try_bool(qdict, "paging", 0); int zlib = qdict_get_try_bool(qdict, "zlib", 0); int lzo = qdict_get_try_bool(qdict, "lzo", 0); @@ -1324,8 +1325,8 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) char *prot; if (zlib + lzo + snappy > 1) { - error_setg(&errp, "only one of '-z|-l|-s' can be set"); - hmp_handle_error(mon, &errp); + error_setg(&err, "only one of '-z|-l|-s' can be set"); + hmp_handle_error(mon, &err); return; } @@ -1351,8 +1352,8 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) prot = g_strconcat("file:", file, NULL); qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length, - true, dump_format, &errp); - hmp_handle_error(mon, &errp); + true, dump_format, &err); + hmp_handle_error(mon, &err); g_free(prot); } @@ -1444,19 +1445,19 @@ out: void hmp_getfd(Monitor *mon, const QDict *qdict) { const char *fdname = qdict_get_str(qdict, "fdname"); - Error *errp = NULL; + Error *err = NULL; - qmp_getfd(fdname, &errp); - hmp_handle_error(mon, &errp); + qmp_getfd(fdname, &err); + hmp_handle_error(mon, &err); } void hmp_closefd(Monitor *mon, const QDict *qdict) { const char *fdname = qdict_get_str(qdict, "fdname"); - Error *errp = NULL; + Error *err = NULL; - qmp_closefd(fdname, &errp); - hmp_handle_error(mon, &errp); + qmp_closefd(fdname, &err); + hmp_handle_error(mon, &err); } void hmp_send_key(Monitor *mon, const QDict *qdict) @@ -1606,10 +1607,10 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict) void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict) { - Error *errp = NULL; + Error *err = NULL; - qmp_nbd_server_stop(&errp); - hmp_handle_error(mon, &errp); + qmp_nbd_server_stop(&err); + hmp_handle_error(mon, &err); } void hmp_cpu_add(Monitor *mon, const QDict *qdict) diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index a825871d8a..e55421adcd 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -394,9 +394,10 @@ static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start) return 0; } -static int assigned_dev_register_regions(PCIRegion *io_regions, - unsigned long regions_num, - AssignedDevice *pci_dev) +static void assigned_dev_register_regions(PCIRegion *io_regions, + unsigned long regions_num, + AssignedDevice *pci_dev, + Error **errp) { uint32_t i; PCIRegion *cur_region = io_regions; @@ -425,9 +426,9 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) { pci_dev->v_addrs[i].u.r_virtbase = NULL; - error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!", - __func__, cur_region->base_addr); - return -1; + error_setg_errno(errp, errno, "Couldn't mmap 0x%" PRIx64 "!", + cur_region->base_addr); + return; } pci_dev->v_addrs[i].r_size = cur_region->size; @@ -496,10 +497,10 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, } /* success */ - return 0; } -static int get_real_id(const char *devpath, const char *idname, uint16_t *val) +static void get_real_id(const char *devpath, const char *idname, uint16_t *val, + Error **errp) { FILE *f; char name[128]; @@ -508,39 +509,39 @@ static int get_real_id(const char *devpath, const char *idname, uint16_t *val) snprintf(name, sizeof(name), "%s%s", devpath, idname); f = fopen(name, "r"); if (f == NULL) { - error_report("%s: %s: %m", __func__, name); - return -1; + error_setg_file_open(errp, errno, name); + return; } if (fscanf(f, "%li\n", &id) == 1) { *val = id; } else { - fclose(f); - return -1; + error_setg(errp, "Failed to parse contents of '%s'", name); } fclose(f); - - return 0; } -static int get_real_vendor_id(const char *devpath, uint16_t *val) +static void get_real_vendor_id(const char *devpath, uint16_t *val, + Error **errp) { - return get_real_id(devpath, "vendor", val); + get_real_id(devpath, "vendor", val, errp); } -static int get_real_device_id(const char *devpath, uint16_t *val) +static void get_real_device_id(const char *devpath, uint16_t *val, + Error **errp) { - return get_real_id(devpath, "device", val); + get_real_id(devpath, "device", val, errp); } -static int get_real_device(AssignedDevice *pci_dev) +static void get_real_device(AssignedDevice *pci_dev, Error **errp) { char dir[128], name[128]; - int fd, r = 0, v; + int fd, r = 0; FILE *f; uint64_t start, end, size, flags; uint16_t id; PCIRegion *rp; PCIDevRegions *dev = &pci_dev->real_device; + Error *local_err = NULL; dev->region_number = 0; @@ -551,16 +552,19 @@ static int get_real_device(AssignedDevice *pci_dev) snprintf(name, sizeof(name), "%sconfig", dir); if (pci_dev->configfd_name && *pci_dev->configfd_name) { - dev->config_fd = monitor_handle_fd_param(cur_mon, pci_dev->configfd_name); - if (dev->config_fd < 0) { - return 1; + dev->config_fd = monitor_handle_fd_param2(cur_mon, + pci_dev->configfd_name, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } } else { dev->config_fd = open(name, O_RDWR); if (dev->config_fd == -1) { - error_report("%s: %s: %m", __func__, name); - return 1; + error_setg_file_open(errp, errno, name); + return; } } again: @@ -570,7 +574,10 @@ again: if (errno == EINTR || errno == EAGAIN) { goto again; } - error_report("%s: read failed, errno = %d", __func__, errno); + error_setg_errno(errp, errno, "read(\"%s\")", + (pci_dev->configfd_name && *pci_dev->configfd_name) ? + pci_dev->configfd_name : name); + return; } /* Restore or clear multifunction, this is always controlled by qemu */ @@ -590,8 +597,8 @@ again: f = fopen(name, "r"); if (f == NULL) { - error_report("%s: %s: %m", __func__, name); - return 1; + error_setg_file_open(errp, errno, name); + return; } for (r = 0; r < PCI_ROM_SLOT; r++) { @@ -634,17 +641,19 @@ again: fclose(f); /* read and fill vendor ID */ - v = get_real_vendor_id(dir, &id); - if (v) { - return 1; + get_real_vendor_id(dir, &id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } pci_dev->dev.config[0] = id & 0xff; pci_dev->dev.config[1] = (id & 0xff00) >> 8; /* read and fill device ID */ - v = get_real_device_id(dir, &id); - if (v) { - return 1; + get_real_device_id(dir, &id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } pci_dev->dev.config[2] = id & 0xff; pci_dev->dev.config[3] = (id & 0xff00) >> 8; @@ -653,7 +662,6 @@ again: PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE); dev->region_number = r; - return 0; } static void free_msi_virqs(AssignedDevice *dev) @@ -726,11 +734,17 @@ static void free_assigned_device(AssignedDevice *dev) free_msi_virqs(dev); } -static void assign_failed_examine(AssignedDevice *dev) +/* This function tries to determine the cause of the PCI assignment failure. It + * always returns the cause as a dynamically allocated, human readable string. + * If the function fails to determine the cause for any internal reason, then + * the returned string will state that fact. + */ +static char *assign_failed_examine(const AssignedDevice *dev) { char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns; uint16_t vendor_id, device_id; int r; + Error *local_err = NULL; snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", dev->host.domain, dev->host.bus, dev->host.slot, @@ -751,13 +765,17 @@ static void assign_failed_examine(AssignedDevice *dev) ns++; - if (get_real_vendor_id(dir, &vendor_id) || - get_real_device_id(dir, &device_id)) { + if ((get_real_vendor_id(dir, &vendor_id, &local_err), local_err) || + (get_real_device_id(dir, &device_id, &local_err), local_err)) { + /* We're already analyzing an assignment error, so we suppress this + * one just like the others above. + */ + error_free(local_err); goto fail; } - error_printf("*** The driver '%s' is occupying your device " - "%04x:%02x:%02x.%x.\n" + return g_strdup_printf( + "*** The driver '%s' is occupying your device %04x:%02x:%02x.%x.\n" "***\n" "*** You can try the following commands to free it:\n" "***\n" @@ -773,13 +791,11 @@ static void assign_failed_examine(AssignedDevice *dev) ns, dev->host.domain, dev->host.bus, dev->host.slot, dev->host.function, vendor_id, device_id); - return; - fail: - error_report("Couldn't find out why."); + return g_strdup("Couldn't find out why."); } -static int assign_device(AssignedDevice *dev) +static void assign_device(AssignedDevice *dev, Error **errp) { uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU; int r; @@ -787,15 +803,15 @@ static int assign_device(AssignedDevice *dev) /* Only pass non-zero PCI segment to capable module */ if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) && dev->host.domain) { - error_report("Can't assign device inside non-zero PCI segment " - "as this KVM module doesn't support it."); - return -ENODEV; + error_setg(errp, "Can't assign device inside non-zero PCI segment " + "as this KVM module doesn't support it."); + return; } if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) { - error_report("No IOMMU found. Unable to assign device \"%s\"", - dev->dev.qdev.id); - return -ENODEV; + error_setg(errp, "No IOMMU found. Unable to assign device \"%s\"", + dev->dev.qdev.id); + return; } if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK && @@ -805,36 +821,39 @@ static int assign_device(AssignedDevice *dev) r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id); if (r < 0) { - error_report("Failed to assign device \"%s\" : %s", - dev->dev.qdev.id, strerror(-r)); - switch (r) { - case -EBUSY: - assign_failed_examine(dev); + case -EBUSY: { + char *cause; + + cause = assign_failed_examine(dev); + error_setg_errno(errp, -r, "Failed to assign device \"%s\"\n%s", + dev->dev.qdev.id, cause); + g_free(cause); break; + } default: + error_setg_errno(errp, -r, "Failed to assign device \"%s\"", + dev->dev.qdev.id); break; } } - return r; } -static bool check_irqchip_in_kernel(void) +static void verify_irqchip_in_kernel(Error **errp) { if (kvm_irqchip_in_kernel()) { - return true; + return; } - error_report("pci-assign: error: requires KVM with in-kernel irqchip " - "enabled"); - return false; + error_setg(errp, "pci-assign requires KVM with in-kernel irqchip enabled"); } -static int assign_intx(AssignedDevice *dev) +static int assign_intx(AssignedDevice *dev, Error **errp) { AssignedIRQType new_type; PCIINTxRoute intx_route; bool intx_host_msi; int r; + Error *local_err = NULL; /* Interrupt PIN 0 means don't use INTx */ if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) { @@ -842,7 +861,9 @@ static int assign_intx(AssignedDevice *dev) return 0; } - if (!check_irqchip_in_kernel()) { + verify_irqchip_in_kernel(&local_err); + if (local_err) { + error_propagate(errp, local_err); return -ENOTSUP; } @@ -905,10 +926,11 @@ retry: dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK; goto retry; } - error_report("Failed to assign irq for \"%s\": %s", - dev->dev.qdev.id, strerror(-r)); - error_report("Perhaps you are assigning a device " - "that shares an IRQ with another device?"); + error_setg_errno(errp, -r, + "Failed to assign irq for \"%s\"\n" + "Perhaps you are assigning a device " + "that shares an IRQ with another device?", + dev->dev.qdev.id); return r; } @@ -934,8 +956,11 @@ static void assigned_dev_update_irq_routing(PCIDevice *dev) Error *err = NULL; int r; - r = assign_intx(assigned_dev); + r = assign_intx(assigned_dev, &err); if (r < 0) { + error_report("%s", error_get_pretty(err)); + error_free(err); + err = NULL; qdev_unplug(&dev->qdev, &err); assert(!err); } @@ -986,7 +1011,13 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev) assigned_dev->intx_route.irq = -1; assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI; } else { - assign_intx(assigned_dev); + Error *local_err = NULL; + + assign_intx(assigned_dev, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + } } } @@ -1128,7 +1159,13 @@ static void assigned_dev_update_msix(PCIDevice *pci_dev) assigned_dev->intx_route.irq = -1; assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX; } else { - assign_intx(assigned_dev); + Error *local_err = NULL; + + assign_intx(assigned_dev, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + } } } @@ -1214,11 +1251,12 @@ static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset, assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1); } -static int assigned_device_pci_cap_init(PCIDevice *pci_dev) +static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) { AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); PCIRegion *pci_region = dev->real_device.regions; int ret, pos; + Error *local_err = NULL; /* Clear initial capabilities pointer and status copied from hw */ pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0); @@ -1230,13 +1268,17 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) * MSI capability is the 1st capability in capability config */ pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0); if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) { - if (!check_irqchip_in_kernel()) { + verify_irqchip_in_kernel(&local_err); + if (local_err) { + error_propagate(errp, local_err); return -ENOTSUP; } dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI; /* Only 32-bit/no-mask currently supported */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } pci_dev->msi_cap = pos; @@ -1259,12 +1301,16 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) int bar_nr; uint32_t msix_table_entry; - if (!check_irqchip_in_kernel()) { + verify_irqchip_in_kernel(&local_err); + if (local_err) { + error_propagate(errp, local_err); return -ENOTSUP; } dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX; - ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } pci_dev->msix_cap = pos; @@ -1291,8 +1337,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) if (pos) { uint16_t pmc; - ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1330,8 +1378,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) */ size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos); if (size < 0x34) { - error_report("%s: Invalid size PCIe cap-id 0x%x", - __func__, PCI_CAP_ID_EXP); + error_setg(errp, "Invalid size PCIe cap-id 0x%x", + PCI_CAP_ID_EXP); return -EINVAL; } else if (size != 0x3c) { error_report("WARNING, %s: PCIe cap-id 0x%x has " @@ -1352,13 +1400,15 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) } if (size == 0) { - error_report("%s: Unsupported PCI express capability version %d", - __func__, version); + error_setg(errp, "Unsupported PCI express capability version %d", + version); return -EINVAL; } - ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_EXP, pos, size, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1368,8 +1418,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) type = (type & PCI_EXP_FLAGS_TYPE) >> 4; if (type != PCI_EXP_TYPE_ENDPOINT && type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) { - error_report("Device assignment only supports endpoint assignment," - " device type %d", type); + error_setg(errp, "Device assignment only supports endpoint " + "assignment, device type %d", type); return -EINVAL; } @@ -1431,8 +1481,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) uint32_t status; /* Only expose the minimum, 8 byte capability */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PCIX, pos, 8, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1457,8 +1509,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0); if (pos) { /* Direct R/W passthrough */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VPD, pos, 8, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1473,8 +1527,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) pos += PCI_CAP_LIST_NEXT) { uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS); /* Direct R/W passthrough */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VNDR, pos, len, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1602,20 +1658,19 @@ static void assigned_dev_msix_reset(AssignedDevice *dev) } } -static int assigned_dev_register_msix_mmio(AssignedDevice *dev) +static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp) { dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); if (dev->msix_table == MAP_FAILED) { - error_report("fail allocate msix_table! %s", strerror(errno)); - return -EFAULT; + error_setg_errno(errp, errno, "failed to allocate msix_table"); + return; } assigned_dev_msix_reset(dev); memory_region_init_io(&dev->mmio, OBJECT(dev), &assigned_dev_msix_mmio_ops, dev, "assigned-dev-msix", MSIX_PAGE_SIZE); - return 0; } static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev) @@ -1698,16 +1753,17 @@ static int assigned_initfn(struct PCIDevice *pci_dev) AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); uint8_t e_intx; int r; + Error *local_err = NULL; if (!kvm_enabled()) { - error_report("pci-assign: error: requires KVM support"); - return -1; + error_setg(&local_err, "pci-assign requires KVM support"); + goto exit_with_error; } if (!dev->host.domain && !dev->host.bus && !dev->host.slot && !dev->host.function) { - error_report("pci-assign: error: no host device specified"); - return -1; + error_setg(&local_err, "no host device specified"); + goto exit_with_error; } /* @@ -1730,27 +1786,28 @@ static int assigned_initfn(struct PCIDevice *pci_dev) memcpy(dev->emulate_config_write, dev->emulate_config_read, sizeof(dev->emulate_config_read)); - if (get_real_device(dev)) { - error_report("pci-assign: Error: Couldn't get real device (%s)!", - dev->dev.qdev.id); + get_real_device(dev, &local_err); + if (local_err) { goto out; } - if (assigned_device_pci_cap_init(pci_dev) < 0) { + if (assigned_device_pci_cap_init(pci_dev, &local_err) < 0) { goto out; } /* intercept MSI-X entry page in the MMIO */ if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { - if (assigned_dev_register_msix_mmio(dev)) { + assigned_dev_register_msix_mmio(dev, &local_err); + if (local_err) { goto out; } } /* handle real device's MMIO/PIO BARs */ - if (assigned_dev_register_regions(dev->real_device.regions, - dev->real_device.region_number, - dev)) { + assigned_dev_register_regions(dev->real_device.regions, + dev->real_device.region_number, dev, + &local_err); + if (local_err) { goto out; } @@ -1761,13 +1818,13 @@ static int assigned_initfn(struct PCIDevice *pci_dev) dev->intx_route.irq = -1; /* assign device to guest */ - r = assign_device(dev); - if (r < 0) { + assign_device(dev, &local_err); + if (local_err) { goto out; } /* assign legacy INTx to the device */ - r = assign_intx(dev); + r = assign_intx(dev, &local_err); if (r < 0) { goto assigned_out; } @@ -1780,8 +1837,14 @@ static int assigned_initfn(struct PCIDevice *pci_dev) assigned_out: deassign_device(dev); + out: free_assigned_device(dev); + +exit_with_error: + assert(local_err); + qerror_report_err(local_err); + error_free(local_err); return -1; } diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index 1b228ff4e0..c3682f1b20 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -121,6 +121,9 @@ pic_write(void *opaque, hwaddr addr, case R_CIE: p->regs[R_IER] &= ~value; /* Atomic clear ie. */ break; + case R_MER: + p->regs[R_MER] = value & 0x3; + break; case R_ISR: if ((p->regs[R_MER] & 2)) { break; diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 48d9e7afa4..6bf36d046f 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -148,7 +148,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, big_endian, ELF_MACHINE, 0); } /* Always boot into physical ram. */ - boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff); + boot_info.bootstrap_pc = (uint32_t)entry; /* If it wasn't an ELF image, try an u-boot image. */ if (kernel_size < 0) { @@ -174,9 +174,15 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, high = ROUND_UP(high + kernel_size, 4); boot_info.initrd_start = high; initrd_offset = boot_info.initrd_start - ddr_base; - initrd_size = load_image_targphys(initrd_filename, - boot_info.initrd_start, - ram_size - initrd_offset); + + initrd_size = load_ramdisk(initrd_filename, + boot_info.initrd_start, + ram_size - initrd_offset); + if (initrd_size < 0) { + initrd_size = load_image_targphys(initrd_filename, + boot_info.initrd_start, + ram_size - initrd_offset); + } if (initrd_size < 0) { error_report("qemu: could not load initrd '%s'\n", initrd_filename); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 517ff2a21b..22fe5eec36 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2013,12 +2013,32 @@ static void pci_del_option_rom(PCIDevice *pdev) int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size) { + int ret; + Error *local_err = NULL; + + ret = pci_add_capability2(pdev, cap_id, offset, size, &local_err); + if (local_err) { + assert(ret < 0); + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + } else { + /* success implies a positive offset in config space */ + assert(ret > 0); + } + return ret; +} + +int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id, + uint8_t offset, uint8_t size, + Error **errp) +{ uint8_t *config; int i, overlapping_cap; if (!offset) { offset = pci_find_space(pdev, size); if (!offset) { + error_setg(errp, "out of PCI config space"); return -ENOSPC; } } else { @@ -2029,12 +2049,12 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, for (i = offset; i < offset + size; i++) { overlapping_cap = pci_find_capability_at_offset(pdev, i); if (overlapping_cap) { - fprintf(stderr, "ERROR: %s:%02x:%02x.%x " - "Attempt to add PCI capability %x at offset " - "%x overlaps existing capability %x at offset %x\n", - pci_root_bus_path(pdev), pci_bus_num(pdev->bus), - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - cap_id, offset, overlapping_cap, i); + error_setg(errp, "%s:%02x:%02x.%x " + "Attempt to add PCI capability %x at offset " + "%x overlaps existing capability %x at offset %x", + pci_root_bus_path(pdev), pci_bus_num(pdev->bus), + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + cap_id, offset, overlapping_cap, i); return -EINVAL; } } diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 6113b975bf..3ff1da9caf 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -169,7 +169,7 @@ timer_write(void *opaque, hwaddr addr, if (value & TCSR_TINT) value &= ~TCSR_TINT; - xt->regs[addr] = value; + xt->regs[addr] = value & 0x7ff; if (value & TCSR_ENT) timer_enable(xt); break; diff --git a/include/block/block.h b/include/block/block.h index 467fb2ba0a..1b119aac24 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -34,6 +34,10 @@ typedef struct BlockDriverInfo { * opened with BDRV_O_UNMAP flag for this to work. */ bool can_write_zeroes_with_unmap; + /* + * True if this block driver only supports compressed writes + */ + bool needs_compressed_writes; } BlockDriverInfo; typedef struct BlockFragInfo { @@ -191,7 +195,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, bool allow_none, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); -void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp); +void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp); int bdrv_open(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, BlockDriver *drv, Error **errp); diff --git a/include/glib-compat.h b/include/glib-compat.h index 8d25900700..1280fb2c1f 100644 --- a/include/glib-compat.h +++ b/include/glib-compat.h @@ -24,7 +24,14 @@ static inline guint g_timeout_add_seconds(guint interval, GSourceFunc function, } #endif -#if !GLIB_CHECK_VERSION(2, 20, 0) +#ifdef _WIN32 +/* + * g_poll has a problem on Windows when using + * timeouts < 10ms, so use wrapper. + */ +#define g_poll(fds, nfds, timeout) g_poll_fixed(fds, nfds, timeout) +gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout); +#elif !GLIB_CHECK_VERSION(2, 20, 0) /* * Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly * on older systems. diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 693dd6b658..8c25ae5d1d 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -6,6 +6,7 @@ #include "hw/qdev.h" #include "exec/memory.h" #include "sysemu/dma.h" +#include "qapi/error.h" /* PCI includes legacy ISA access. */ #include "hw/isa/isa.h" @@ -308,6 +309,9 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size); +int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id, + uint8_t offset, uint8_t size, + Error **errp); void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 42d867155b..1c1f56f36b 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -75,6 +75,7 @@ int monitor_read_block_device_key(Monitor *mon, const char *device, int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp); int monitor_handle_fd_param(Monitor *mon, const char *fdname); +int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp); void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); diff --git a/include/qapi/error.h b/include/qapi/error.h index c0f0c3b432..79958011db 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -27,14 +27,16 @@ typedef struct Error Error; * printf-style human message. This function is not meant to be used outside * of QEMU. */ -void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4); +void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) + GCC_FMT_ATTR(3, 4); /** * Set an indirect pointer to an error given a ErrorClass value and a * printf-style human message, followed by a strerror() string if * @os_error is not zero. */ -void error_set_errno(Error **err, int os_error, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5); +void error_set_errno(Error **errp, int os_error, ErrorClass err_class, + const char *fmt, ...) GCC_FMT_ATTR(4, 5); #ifdef _WIN32 /** @@ -42,19 +44,22 @@ void error_set_errno(Error **err, int os_error, ErrorClass err_class, const char * printf-style human message, followed by a g_win32_error_message() string if * @win32_err is not zero. */ -void error_set_win32(Error **err, int win32_err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5); +void error_set_win32(Error **errp, int win32_err, ErrorClass err_class, + const char *fmt, ...) GCC_FMT_ATTR(4, 5); #endif /** * Same as error_set(), but sets a generic error */ -#define error_setg(err, fmt, ...) \ - error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) -#define error_setg_errno(err, os_error, fmt, ...) \ - error_set_errno(err, os_error, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) +#define error_setg(errp, fmt, ...) \ + error_set(errp, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) +#define error_setg_errno(errp, os_error, fmt, ...) \ + error_set_errno(errp, os_error, ERROR_CLASS_GENERIC_ERROR, \ + fmt, ## __VA_ARGS__) #ifdef _WIN32 -#define error_setg_win32(err, win32_err, fmt, ...) \ - error_set_win32(err, win32_err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) +#define error_setg_win32(errp, win32_err, fmt, ...) \ + error_set_win32(errp, win32_err, ERROR_CLASS_GENERIC_ERROR, \ + fmt, ## __VA_ARGS__) #endif /** @@ -66,7 +71,7 @@ void error_setg_file_open(Error **errp, int os_errno, const char *filename); * Returns true if an indirect pointer to an error is pointing to a valid * error object. */ -bool error_is_set(Error **err); +bool error_is_set(Error **errp); /* * Get the error class of an error object. @@ -88,7 +93,7 @@ const char *error_get_pretty(Error *err); * always transfer ownership of the error reference and handles the case where * dst_err is NULL correctly. Errors after the first are discarded. */ -void error_propagate(Error **dst_err, Error *local_err); +void error_propagate(Error **dst_errp, Error *local_err); /** * Free an error object. diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index cea38181bf..e389697f19 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -50,7 +50,7 @@ void qmp_enable_command(const char *name); bool qmp_command_is_enabled(const QmpCommand *cmd); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); -QObject *qmp_build_error_object(Error *errp); +QObject *qmp_build_error_object(Error *err); typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque); void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque); @@ -2611,16 +2611,33 @@ int monitor_handle_fd_param(Monitor *mon, const char *fdname) int fd; Error *local_err = NULL; - if (!qemu_isdigit(fdname[0]) && mon) { + fd = monitor_handle_fd_param2(mon, fdname, &local_err); + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; +} + +int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp) +{ + int fd; + Error *local_err = NULL; + if (!qemu_isdigit(fdname[0]) && mon) { fd = monitor_get_fd(mon, fdname, &local_err); + } else { + fd = qemu_parse_fd(fdname); if (fd == -1) { - qerror_report_err(local_err); - error_free(local_err); - return -1; + error_setg(&local_err, "Invalid file descriptor number '%s'", + fdname); } + } + if (local_err) { + error_propagate(errp, local_err); + assert(fd == -1); } else { - fd = qemu_parse_fd(fdname); + assert(fd != -1); } return fd; diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 5d830a2b56..87c1c789c9 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -472,13 +472,14 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) val = strtosz_suffix(opt->str ? opt->str : "", &endptr, STRTOSZ_DEFSUFFIX_B); - if (val != -1 && *endptr == '\0') { - *obj = val; - processed(ov, name); + if (val < 0 || *endptr) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, + "a size value representible as a non-negative int64"); return; } - error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, - "a size value representible as a non-negative int64"); + + *obj = val; + processed(ov, name); } diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index d0ea118fe3..dc53545fa5 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -131,7 +131,9 @@ static void qapi_dealloc_end_list(Visitor *v, Error **errp) static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name, Error **errp) { - g_free(*obj); + if (obj) { + g_free(*obj); + } } static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name, diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 9c614494f1..168b083c87 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -62,14 +62,14 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp) static QObject *do_qmp_dispatch(QObject *request, Error **errp) { + Error *local_err = NULL; const char *command; QDict *args, *dict; QmpCommand *cmd; QObject *ret = NULL; - dict = qmp_dispatch_check_obj(request, errp); - if (!dict || error_is_set(errp)) { + if (!dict) { return NULL; } @@ -94,13 +94,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) switch (cmd->type) { case QCT_NORMAL: - cmd->fn(args, &ret, errp); - if (!error_is_set(errp)) { - if (cmd->options & QCO_NO_SUCCESS_RESP) { - g_assert(!ret); - } else if (!ret) { - ret = QOBJECT(qdict_new()); - } + cmd->fn(args, &ret, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } else if (cmd->options & QCO_NO_SUCCESS_RESP) { + g_assert(!ret); + } else if (!ret) { + ret = QOBJECT(qdict_new()); } break; } @@ -110,11 +110,11 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) return ret; } -QObject *qmp_build_error_object(Error *errp) +QObject *qmp_build_error_object(Error *err) { return qobject_from_jsonf("{ 'class': %s, 'desc': %s }", - ErrorClass_lookup[error_get_class(errp)], - error_get_pretty(errp)); + ErrorClass_lookup[error_get_class(err)], + error_get_pretty(err)); } QObject *qmp_dispatch(QObject *request) diff --git a/qemu-img.c b/qemu-img.c index 96f44638b7..04ce02aeb4 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -32,6 +32,7 @@ #include "block/block_int.h" #include "block/qapi.h" #include <getopt.h> +#include <glib.h> #define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \ ", Copyright (c) 2004-2008 Fabrice Bellard\n" @@ -55,9 +56,25 @@ typedef enum OutputFormat { #define BDRV_O_FLAGS BDRV_O_CACHE_WB #define BDRV_DEFAULT_CACHE "writeback" -static void format_print(void *opaque, const char *name) +static gint compare_data(gconstpointer a, gconstpointer b, gpointer user) { - printf(" %s", name); + return g_strcmp0(a, b); +} + +static void print_format(gpointer data, gpointer user) +{ + printf(" %s", (char *)data); +} + +static void add_format_to_seq(void *opaque, const char *fmt_name) +{ + GSequence *seq = opaque; + + if (!g_sequence_lookup(seq, (gpointer)fmt_name, + compare_data, NULL)) { + g_sequence_insert_sorted(seq, (gpointer)fmt_name, + compare_data, NULL); + } } static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) @@ -142,10 +159,15 @@ static void QEMU_NORETURN help(void) " '-f' first image format\n" " '-F' second image format\n" " '-s' run in Strict mode - fail on different image size or sector allocation\n"; + GSequence *seq; printf("%s\nSupported formats:", help_msg); - bdrv_iterate_format(format_print, NULL); + seq = g_sequence_new(NULL); + bdrv_iterate_format(add_format_to_seq, seq); + g_sequence_foreach(seq, print_format, NULL); printf("\n"); + g_sequence_free(seq); + exit(EXIT_SUCCESS); } @@ -1480,6 +1502,7 @@ static int img_convert(int argc, char **argv) goto out; } } else { + compress = compress || bdi.needs_compressed_writes; cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; } diff --git a/qemu-timer.c b/qemu-timer.c index 9be1a4131d..00a5d35c3f 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -126,6 +126,9 @@ static void qemu_clock_init(QEMUClockType type) { QEMUClock *clock = qemu_clock_ptr(type); + /* Assert that the clock of type TYPE has not been initialized yet. */ + assert(main_loop_tlg.tl[type] == NULL); + clock->type = type; clock->enabled = true; clock->last = INT64_MIN; diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 935a4ec14d..34ddba0531 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -53,7 +53,7 @@ extern char **environ; #endif #endif -static void ga_wait_child(pid_t pid, int *status, Error **err) +static void ga_wait_child(pid_t pid, int *status, Error **errp) { pid_t rpid; @@ -64,14 +64,15 @@ static void ga_wait_child(pid_t pid, int *status, Error **err) } while (rpid == -1 && errno == EINTR); if (rpid == -1) { - error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid); + error_setg_errno(errp, errno, "failed to wait for child (pid: %d)", + pid); return; } g_assert(rpid == pid); } -void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) +void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) { const char *shutdown_flag; Error *local_err = NULL; @@ -86,7 +87,7 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) } else if (strcmp(mode, "reboot") == 0) { shutdown_flag = "-r"; } else { - error_setg(err, + error_setg(errp, "mode is invalid (valid values are: halt|powerdown|reboot"); return; } @@ -103,23 +104,23 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) "hypervisor initiated shutdown", (char*)NULL, environ); _exit(EXIT_FAILURE); } else if (pid < 0) { - error_setg_errno(err, errno, "failed to create child process"); + error_setg_errno(errp, errno, "failed to create child process"); return; } ga_wait_child(pid, &status, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return; } if (!WIFEXITED(status)) { - error_setg(err, "child process has terminated abnormally"); + error_setg(errp, "child process has terminated abnormally"); return; } if (WEXITSTATUS(status)) { - error_setg(err, "child process has failed to shutdown"); + error_setg(errp, "child process has failed to shutdown"); return; } @@ -222,8 +223,8 @@ static int64_t guest_file_handle_add(FILE *fh, Error **errp) int64_t handle; handle = ga_get_fd_handle(ga_state, errp); - if (error_is_set(errp)) { - return 0; + if (handle < 0) { + return -1; } gfh = g_malloc0(sizeof(GuestFileHandle)); @@ -234,7 +235,7 @@ static int64_t guest_file_handle_add(FILE *fh, Error **errp) return handle; } -static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) +static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp) { GuestFileHandle *gfh; @@ -245,7 +246,7 @@ static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) } } - error_setg(err, "handle '%" PRId64 "' has not been found", id); + error_setg(errp, "handle '%" PRId64 "' has not been found", id); return NULL; } @@ -275,7 +276,7 @@ static const struct { }; static int -find_open_flag(const char *mode_str, Error **err) +find_open_flag(const char *mode_str, Error **errp) { unsigned mode; @@ -292,7 +293,7 @@ find_open_flag(const char *mode_str, Error **err) } if (mode == ARRAY_SIZE(guest_file_open_modes)) { - error_setg(err, "invalid file open mode '%s'", mode_str); + error_setg(errp, "invalid file open mode '%s'", mode_str); return -1; } return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK; @@ -303,7 +304,7 @@ find_open_flag(const char *mode_str, Error **err) S_IROTH | S_IWOTH) static FILE * -safe_open_or_create(const char *path, const char *mode, Error **err) +safe_open_or_create(const char *path, const char *mode, Error **errp) { Error *local_err = NULL; int oflag; @@ -370,11 +371,12 @@ safe_open_or_create(const char *path, const char *mode, Error **err) } } - error_propagate(err, local_err); + error_propagate(errp, local_err); return NULL; } -int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err) +int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, + Error **errp) { FILE *fh; Error *local_err = NULL; @@ -387,7 +389,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E slog("guest-file-open called, filepath: %s, mode: %s", path, mode); fh = safe_open_or_create(path, mode, &local_err); if (local_err != NULL) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return -1; } @@ -398,14 +400,14 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E ret = fcntl(fd, F_GETFL); ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); if (ret == -1) { - error_setg_errno(err, errno, "failed to make file '%s' non-blocking", + error_setg_errno(errp, errno, "failed to make file '%s' non-blocking", path); fclose(fh); return -1; } - handle = guest_file_handle_add(fh, err); - if (error_is_set(err)) { + handle = guest_file_handle_add(fh, errp); + if (handle < 0) { fclose(fh); return -1; } @@ -414,9 +416,9 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E return handle; } -void qmp_guest_file_close(int64_t handle, Error **err) +void qmp_guest_file_close(int64_t handle, Error **errp) { - GuestFileHandle *gfh = guest_file_handle_find(handle, err); + GuestFileHandle *gfh = guest_file_handle_find(handle, errp); int ret; slog("guest-file-close called, handle: %" PRId64, handle); @@ -426,7 +428,7 @@ void qmp_guest_file_close(int64_t handle, Error **err) ret = fclose(gfh->fh); if (ret == EOF) { - error_setg_errno(err, errno, "failed to close handle"); + error_setg_errno(errp, errno, "failed to close handle"); return; } @@ -435,9 +437,9 @@ void qmp_guest_file_close(int64_t handle, Error **err) } struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, - int64_t count, Error **err) + int64_t count, Error **errp) { - GuestFileHandle *gfh = guest_file_handle_find(handle, err); + GuestFileHandle *gfh = guest_file_handle_find(handle, errp); GuestFileRead *read_data = NULL; guchar *buf; FILE *fh; @@ -450,7 +452,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, if (!has_count) { count = QGA_READ_COUNT_DEFAULT; } else if (count < 0) { - error_setg(err, "value '%" PRId64 "' is invalid for argument count", + error_setg(errp, "value '%" PRId64 "' is invalid for argument count", count); return NULL; } @@ -459,7 +461,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, buf = g_malloc0(count+1); read_count = fread(buf, 1, count, fh); if (ferror(fh)) { - error_setg_errno(err, errno, "failed to read file"); + error_setg_errno(errp, errno, "failed to read file"); slog("guest-file-read failed, handle: %" PRId64, handle); } else { buf[read_count] = 0; @@ -477,13 +479,14 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, } GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, - bool has_count, int64_t count, Error **err) + bool has_count, int64_t count, + Error **errp) { GuestFileWrite *write_data = NULL; guchar *buf; gsize buf_len; int write_count; - GuestFileHandle *gfh = guest_file_handle_find(handle, err); + GuestFileHandle *gfh = guest_file_handle_find(handle, errp); FILE *fh; if (!gfh) { @@ -496,7 +499,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, if (!has_count) { count = buf_len; } else if (count < 0 || count > buf_len) { - error_setg(err, "value '%" PRId64 "' is invalid for argument count", + error_setg(errp, "value '%" PRId64 "' is invalid for argument count", count); g_free(buf); return NULL; @@ -504,7 +507,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, write_count = fwrite(buf, 1, count, fh); if (ferror(fh)) { - error_setg_errno(err, errno, "failed to write to file"); + error_setg_errno(errp, errno, "failed to write to file"); slog("guest-file-write failed, handle: %" PRId64, handle); } else { write_data = g_malloc0(sizeof(GuestFileWrite)); @@ -518,9 +521,9 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, } struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, - int64_t whence, Error **err) + int64_t whence, Error **errp) { - GuestFileHandle *gfh = guest_file_handle_find(handle, err); + GuestFileHandle *gfh = guest_file_handle_find(handle, errp); GuestFileSeek *seek_data = NULL; FILE *fh; int ret; @@ -532,7 +535,7 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, fh = gfh->fh; ret = fseek(fh, offset, whence); if (ret == -1) { - error_setg_errno(err, errno, "failed to seek file"); + error_setg_errno(errp, errno, "failed to seek file"); } else { seek_data = g_new0(GuestFileSeek, 1); seek_data->position = ftell(fh); @@ -543,9 +546,9 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, return seek_data; } -void qmp_guest_file_flush(int64_t handle, Error **err) +void qmp_guest_file_flush(int64_t handle, Error **errp) { - GuestFileHandle *gfh = guest_file_handle_find(handle, err); + GuestFileHandle *gfh = guest_file_handle_find(handle, errp); FILE *fh; int ret; @@ -556,7 +559,7 @@ void qmp_guest_file_flush(int64_t handle, Error **err) fh = gfh->fh; ret = fflush(fh); if (ret == EOF) { - error_setg_errno(err, errno, "failed to flush file"); + error_setg_errno(errp, errno, "failed to flush file"); } } @@ -596,7 +599,7 @@ static void free_fs_mount_list(FsMountList *mounts) /* * Walk the mount table and build a list of local file systems */ -static void build_fs_mount_list(FsMountList *mounts, Error **err) +static void build_fs_mount_list(FsMountList *mounts, Error **errp) { struct mntent *ment; FsMount *mount; @@ -605,7 +608,7 @@ static void build_fs_mount_list(FsMountList *mounts, Error **err) fp = setmntent(mtab, "r"); if (!fp) { - error_setg(err, "failed to open mtab file: '%s'", mtab); + error_setg(errp, "failed to open mtab file: '%s'", mtab); return; } @@ -645,7 +648,7 @@ const char *fsfreeze_hook_arg_string[] = { "freeze", }; -static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) +static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp) { int status; pid_t pid; @@ -658,7 +661,7 @@ static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) return; } if (access(hook, X_OK) != 0) { - error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook); + error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook); return; } @@ -673,24 +676,24 @@ static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) execle(hook, hook, arg_str, NULL, environ); _exit(EXIT_FAILURE); } else if (pid < 0) { - error_setg_errno(err, errno, "failed to create child process"); + error_setg_errno(errp, errno, "failed to create child process"); return; } ga_wait_child(pid, &status, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return; } if (!WIFEXITED(status)) { - error_setg(err, "fsfreeze hook has terminated abnormally"); + error_setg(errp, "fsfreeze hook has terminated abnormally"); return; } status = WEXITSTATUS(status); if (status) { - error_setg(err, "fsfreeze hook has failed with status %d", status); + error_setg(errp, "fsfreeze hook has failed with status %d", status); return; } } @@ -698,7 +701,7 @@ static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) /* * Return status of freeze/thaw */ -GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) +GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp) { if (ga_is_frozen(ga_state)) { return GUEST_FSFREEZE_STATUS_FROZEN; @@ -711,7 +714,7 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) * Walk list of mounted file systems in the guest, and freeze the ones which * are real local file systems. */ -int64_t qmp_guest_fsfreeze_freeze(Error **err) +int64_t qmp_guest_fsfreeze_freeze(Error **errp) { int ret = 0, i = 0; FsMountList mounts; @@ -723,14 +726,14 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return -1; } QTAILQ_INIT(&mounts); build_fs_mount_list(&mounts, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return -1; } @@ -740,7 +743,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) { fd = qemu_open(mount->dirname, O_RDONLY); if (fd == -1) { - error_setg_errno(err, errno, "failed to open %s", mount->dirname); + error_setg_errno(errp, errno, "failed to open %s", mount->dirname); goto error; } @@ -756,7 +759,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) ret = ioctl(fd, FIFREEZE); if (ret == -1) { if (errno != EOPNOTSUPP) { - error_setg_errno(err, errno, "failed to freeze %s", + error_setg_errno(errp, errno, "failed to freeze %s", mount->dirname); close(fd); goto error; @@ -779,7 +782,7 @@ error: /* * Walk list of frozen file systems in the guest, and thaw them. */ -int64_t qmp_guest_fsfreeze_thaw(Error **err) +int64_t qmp_guest_fsfreeze_thaw(Error **errp) { int ret; FsMountList mounts; @@ -790,7 +793,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) QTAILQ_INIT(&mounts); build_fs_mount_list(&mounts, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return 0; } @@ -829,7 +832,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) ga_unset_frozen(ga_state); free_fs_mount_list(&mounts); - execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err); + execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp); return i; } @@ -853,7 +856,7 @@ static void guest_fsfreeze_cleanup(void) /* * Walk list of mounted file systems in the guest, and trim them. */ -void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) +void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) { int ret = 0; FsMountList mounts; @@ -871,14 +874,14 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) QTAILQ_INIT(&mounts); build_fs_mount_list(&mounts, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return; } QTAILQ_FOREACH(mount, &mounts, next) { fd = qemu_open(mount->dirname, O_RDONLY); if (fd == -1) { - error_setg_errno(err, errno, "failed to open %s", mount->dirname); + error_setg_errno(errp, errno, "failed to open %s", mount->dirname); goto error; } @@ -891,7 +894,7 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) ret = ioctl(fd, FITRIM, &r); if (ret == -1) { if (errno != ENOTTY && errno != EOPNOTSUPP) { - error_setg_errno(err, errno, "failed to trim %s", + error_setg_errno(errp, errno, "failed to trim %s", mount->dirname); close(fd); goto error; @@ -911,7 +914,7 @@ error: #define SUSPEND_NOT_SUPPORTED 1 static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, - const char *sysfile_str, Error **err) + const char *sysfile_str, Error **errp) { Error *local_err = NULL; char *pmutils_path; @@ -961,18 +964,18 @@ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, _exit(SUSPEND_NOT_SUPPORTED); } else if (pid < 0) { - error_setg_errno(err, errno, "failed to create child process"); + error_setg_errno(errp, errno, "failed to create child process"); goto out; } ga_wait_child(pid, &status, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); goto out; } if (!WIFEXITED(status)) { - error_setg(err, "child process has terminated abnormally"); + error_setg(errp, "child process has terminated abnormally"); goto out; } @@ -980,11 +983,11 @@ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, case SUSPEND_SUPPORTED: goto out; case SUSPEND_NOT_SUPPORTED: - error_setg(err, + error_setg(errp, "the requested suspend mode is not supported by the guest"); goto out; default: - error_setg(err, + error_setg(errp, "the helper program '%s' returned an unexpected exit status" " code (%d)", pmutils_path, WEXITSTATUS(status)); goto out; @@ -995,7 +998,7 @@ out: } static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, - Error **err) + Error **errp) { Error *local_err = NULL; char *pmutils_path; @@ -1038,23 +1041,23 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, _exit(EXIT_SUCCESS); } else if (pid < 0) { - error_setg_errno(err, errno, "failed to create child process"); + error_setg_errno(errp, errno, "failed to create child process"); goto out; } ga_wait_child(pid, &status, &local_err); if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); goto out; } if (!WIFEXITED(status)) { - error_setg(err, "child process has terminated abnormally"); + error_setg(errp, "child process has terminated abnormally"); goto out; } if (WEXITSTATUS(status)) { - error_setg(err, "child process has failed to suspend"); + error_setg(errp, "child process has failed to suspend"); goto out; } @@ -1062,34 +1065,44 @@ out: g_free(pmutils_path); } -void qmp_guest_suspend_disk(Error **err) +void qmp_guest_suspend_disk(Error **errp) { - bios_supports_mode("pm-is-supported", "--hibernate", "disk", err); - if (error_is_set(err)) { + Error *local_err = NULL; + + bios_supports_mode("pm-is-supported", "--hibernate", "disk", &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } - guest_suspend("pm-hibernate", "disk", err); + guest_suspend("pm-hibernate", "disk", errp); } -void qmp_guest_suspend_ram(Error **err) +void qmp_guest_suspend_ram(Error **errp) { - bios_supports_mode("pm-is-supported", "--suspend", "mem", err); - if (error_is_set(err)) { + Error *local_err = NULL; + + bios_supports_mode("pm-is-supported", "--suspend", "mem", &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } - guest_suspend("pm-suspend", "mem", err); + guest_suspend("pm-suspend", "mem", errp); } -void qmp_guest_suspend_hybrid(Error **err) +void qmp_guest_suspend_hybrid(Error **errp) { - bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err); - if (error_is_set(err)) { + Error *local_err = NULL; + + bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, + &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } - guest_suspend("pm-suspend-hybrid", NULL, err); + guest_suspend("pm-suspend-hybrid", NULL, errp); } static GuestNetworkInterfaceList * @@ -1252,9 +1265,9 @@ error: return NULL; } -#define SYSCONF_EXACT(name, err) sysconf_exact((name), #name, (err)) +#define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp)) -static long sysconf_exact(int name, const char *name_str, Error **err) +static long sysconf_exact(int name, const char *name_str, Error **errp) { long ret; @@ -1262,9 +1275,9 @@ static long sysconf_exact(int name, const char *name_str, Error **err) ret = sysconf(name); if (ret == -1) { if (errno == 0) { - error_setg(err, "sysconf(%s): value indefinite", name_str); + error_setg(errp, "sysconf(%s): value indefinite", name_str); } else { - error_setg_errno(err, errno, "sysconf(%s)", name_str); + error_setg_errno(errp, errno, "sysconf(%s)", name_str); } } return ret; @@ -1410,19 +1423,19 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) #else /* defined(__linux__) */ -void qmp_guest_suspend_disk(Error **err) +void qmp_guest_suspend_disk(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } -void qmp_guest_suspend_ram(Error **err) +void qmp_guest_suspend_ram(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } -void qmp_guest_suspend_hybrid(Error **err) +void qmp_guest_suspend_hybrid(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) @@ -1447,32 +1460,32 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) #if !defined(CONFIG_FSFREEZE) -GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) +GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } -int64_t qmp_guest_fsfreeze_freeze(Error **err) +int64_t qmp_guest_fsfreeze_freeze(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } -int64_t qmp_guest_fsfreeze_thaw(Error **err) +int64_t qmp_guest_fsfreeze_thaw(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } #endif /* CONFIG_FSFREEZE */ #if !defined(CONFIG_FSTRIM) -void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) +void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } #endif diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 0ee07b6e23..d793dd0c85 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -29,16 +29,12 @@ (365 * (1970 - 1601) + \ (1970 - 1601) / 4 - 3)) -static void acquire_privilege(const char *name, Error **err) +static void acquire_privilege(const char *name, Error **errp) { HANDLE token; TOKEN_PRIVILEGES priv; Error *local_err = NULL; - if (error_is_set(err)) { - return; - } - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token)) { @@ -65,27 +61,26 @@ static void acquire_privilege(const char *name, Error **err) out: if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); } } -static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, Error **err) +static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, + Error **errp) { Error *local_err = NULL; - if (error_is_set(err)) { - return; - } HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL); if (!thread) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, "failed to dispatch asynchronous command"); - error_propagate(err, local_err); + error_propagate(errp, local_err); } } -void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) +void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) { + Error *local_err = NULL; UINT shutdown_flag = EWX_FORCE; slog("guest-shutdown called, mode: %s", mode); @@ -97,68 +92,71 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) } else if (strcmp(mode, "reboot") == 0) { shutdown_flag |= EWX_REBOOT; } else { - error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode", + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "mode", "halt|powerdown|reboot"); return; } /* Request a shutdown privilege, but try to shut down the system anyway. */ - acquire_privilege(SE_SHUTDOWN_NAME, err); - if (error_is_set(err)) { + acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) { slog("guest-shutdown failed: %lu", GetLastError()); - error_set(err, QERR_UNDEFINED_ERROR); + error_set(errp, QERR_UNDEFINED_ERROR); } } -int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err) +int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, + Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } -void qmp_guest_file_close(int64_t handle, Error **err) +void qmp_guest_file_close(int64_t handle, Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, - int64_t count, Error **err) + int64_t count, Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, - bool has_count, int64_t count, Error **err) + bool has_count, int64_t count, + Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, - int64_t whence, Error **err) + int64_t whence, Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } -void qmp_guest_file_flush(int64_t handle, Error **err) +void qmp_guest_file_flush(int64_t handle, Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } /* * Return status of freeze/thaw */ -GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) +GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp) { if (!vss_initialized()) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } @@ -173,13 +171,13 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) * Freeze local file systems using Volume Shadow-copy Service. * The frozen state is limited for up to 10 seconds by VSS. */ -int64_t qmp_guest_fsfreeze_freeze(Error **err) +int64_t qmp_guest_fsfreeze_freeze(Error **errp) { int i; Error *local_err = NULL; if (!vss_initialized()) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } @@ -188,14 +186,16 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) /* cannot risk guest agent blocking itself on a write in this state */ ga_set_frozen(ga_state); - qga_vss_fsfreeze(&i, err, true); - if (error_is_set(err)) { + qga_vss_fsfreeze(&i, &local_err, true); + if (local_err) { + error_propagate(errp, local_err); goto error; } return i; error: + local_err = NULL; qmp_guest_fsfreeze_thaw(&local_err); if (local_err) { g_debug("cleanup thaw: %s", error_get_pretty(local_err)); @@ -207,16 +207,16 @@ error: /* * Thaw local file systems using Volume Shadow-copy Service. */ -int64_t qmp_guest_fsfreeze_thaw(Error **err) +int64_t qmp_guest_fsfreeze_thaw(Error **errp) { int i; if (!vss_initialized()) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return 0; } - qga_vss_fsfreeze(&i, err, false); + qga_vss_fsfreeze(&i, errp, false); ga_unset_frozen(ga_state); return i; @@ -246,9 +246,9 @@ static void guest_fsfreeze_cleanup(void) * Walk list of mounted file systems in the guest, and discard unused * areas. */ -void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) +void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } typedef enum { @@ -256,14 +256,11 @@ typedef enum { GUEST_SUSPEND_MODE_RAM } GuestSuspendMode; -static void check_suspend_mode(GuestSuspendMode mode, Error **err) +static void check_suspend_mode(GuestSuspendMode mode, Error **errp) { SYSTEM_POWER_CAPABILITIES sys_pwr_caps; Error *local_err = NULL; - if (error_is_set(err)) { - return; - } ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps)); if (!GetPwrCapabilities(&sys_pwr_caps)) { error_set(&local_err, QERR_QGA_COMMAND_FAILED, @@ -291,7 +288,7 @@ static void check_suspend_mode(GuestSuspendMode mode, Error **err) out: if (local_err) { - error_propagate(err, local_err); + error_propagate(errp, local_err); } } @@ -308,42 +305,46 @@ static DWORD WINAPI do_suspend(LPVOID opaque) return ret; } -void qmp_guest_suspend_disk(Error **err) +void qmp_guest_suspend_disk(Error **errp) { + Error *local_err = NULL; GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); *mode = GUEST_SUSPEND_MODE_DISK; - check_suspend_mode(*mode, err); - acquire_privilege(SE_SHUTDOWN_NAME, err); - execute_async(do_suspend, mode, err); + check_suspend_mode(*mode, &local_err); + acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + execute_async(do_suspend, mode, &local_err); - if (error_is_set(err)) { + if (local_err) { + error_propagate(errp, local_err); g_free(mode); } } -void qmp_guest_suspend_ram(Error **err) +void qmp_guest_suspend_ram(Error **errp) { + Error *local_err = NULL; GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); *mode = GUEST_SUSPEND_MODE_RAM; - check_suspend_mode(*mode, err); - acquire_privilege(SE_SHUTDOWN_NAME, err); - execute_async(do_suspend, mode, err); + check_suspend_mode(*mode, &local_err); + acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + execute_async(do_suspend, mode, &local_err); - if (error_is_set(err)) { + if (local_err) { + error_propagate(errp, local_err); g_free(mode); } } -void qmp_guest_suspend_hybrid(Error **err) +void qmp_guest_suspend_hybrid(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); } -GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **err) +GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) { - error_set(err, QERR_UNSUPPORTED); + error_set(errp, QERR_UNSUPPORTED); return NULL; } @@ -372,6 +373,7 @@ int64_t qmp_guest_get_time(Error **errp) void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) { + Error *local_err = NULL; SYSTEMTIME ts; FILETIME tf; LONGLONG time; @@ -403,8 +405,9 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) } } - acquire_privilege(SE_SYSTEMTIME_NAME, errp); - if (error_is_set(errp)) { + acquire_privilege(SE_SYSTEMTIME_NAME, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/qga/commands.c b/qga/commands.c index a0c2de07ec..783496791e 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -40,7 +40,7 @@ int64_t qmp_guest_sync(int64_t id, Error **errp) return id; } -void qmp_guest_ping(Error **err) +void qmp_guest_ping(Error **errp) { slog("guest-ping called"); } @@ -62,7 +62,7 @@ static void qmp_command_info(QmpCommand *cmd, void *opaque) info->supported_commands = cmd_info_list; } -struct GuestAgentInfo *qmp_guest_info(Error **err) +struct GuestAgentInfo *qmp_guest_info(Error **errp) { GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo)); diff --git a/qga/main.c b/qga/main.c index 38219c9d77..8b927c9db7 100644 --- a/qga/main.c +++ b/qga/main.c @@ -910,6 +910,7 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp) if (!write_persistent_state(&s->pstate, s->pstate_filepath)) { error_setg(errp, "failed to commit persistent state to disk"); + return -1; } return handle; diff --git a/qga/vss-win32.c b/qga/vss-win32.c index 24c428842b..0e4095736e 100644 --- a/qga/vss-win32.c +++ b/qga/vss-win32.c @@ -145,19 +145,19 @@ void ga_uninstall_vss_provider(void) } /* Call VSS requester and freeze/thaw filesystems and applications */ -void qga_vss_fsfreeze(int *nr_volume, Error **err, bool freeze) +void qga_vss_fsfreeze(int *nr_volume, Error **errp, bool freeze) { const char *func_name = freeze ? "requester_freeze" : "requester_thaw"; QGAVSSRequesterFunc func; ErrorSet errset = { .error_set = (ErrorSetFunc)error_set_win32, - .errp = (void **)err, + .errp = (void **)errp, .err_class = ERROR_CLASS_GENERIC_ERROR }; func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name); if (!func) { - error_setg_win32(err, GetLastError(), "failed to load %s from %s", + error_setg_win32(errp, GetLastError(), "failed to load %s from %s", func_name, QGA_VSS_DLL); return; } diff --git a/qga/vss-win32.h b/qga/vss-win32.h index db8fbe5208..298927dfa5 100644 --- a/qga/vss-win32.h +++ b/qga/vss-win32.h @@ -22,6 +22,6 @@ bool vss_initialized(void); int ga_install_vss_provider(void); void ga_uninstall_vss_provider(void); -void qga_vss_fsfreeze(int *nr_volume, Error **err, bool freeze); +void qga_vss_fsfreeze(int *nr_volume, Error **errp, bool freeze); #endif diff --git a/qmp-commands.hx b/qmp-commands.hx index f437937e2c..cae890ee5d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1165,19 +1165,19 @@ Example: -> { "execute": "transaction", "arguments": { "actions": [ - { 'type': 'blockdev-snapshot-sync', 'data' : { "device": "ide-hd0", + { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd0", "snapshot-file": "/some/place/my-image", "format": "qcow2" } }, - { 'type': 'blockdev-snapshot-sync', 'data' : { "node-name": "myfile", + { "type": "blockdev-snapshot-sync", "data" : { "node-name": "myfile", "snapshot-file": "/some/place/my-image2", "snapshot-node-name": "node3432", "mode": "existing", "format": "qcow2" } }, - { 'type': 'blockdev-snapshot-sync', 'data' : { "device": "ide-hd1", + { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd1", "snapshot-file": "/some/place/my-image2", "mode": "existing", "format": "qcow2" } }, - { 'type': 'blockdev-snapshot-internal-sync', 'data' : { + { "type": "blockdev-snapshot-internal-sync", "data" : { "device": "ide-hd2", "name": "snapshot0" } } ] } } <- { "return": {} } @@ -41,7 +41,7 @@ NameInfo *qmp_query_name(Error **errp) return info; } -VersionInfo *qmp_query_version(Error **err) +VersionInfo *qmp_query_version(Error **errp) { VersionInfo *info = g_malloc0(sizeof(*info)); const char *version = QEMU_VERSION; @@ -82,7 +82,7 @@ UuidInfo *qmp_query_uuid(Error **errp) return info; } -void qmp_quit(Error **err) +void qmp_quit(Error **errp) { no_shutdown = 0; qemu_system_shutdown_request(); @@ -146,24 +146,9 @@ SpiceInfo *qmp_query_spice(Error **errp) }; #endif -static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs) -{ - bdrv_iostatus_reset(bs); -} - -static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) -{ - Error **err = opaque; - - if (!error_is_set(err) && bdrv_key_required(bs)) { - error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs), - bdrv_get_encrypted_filename(bs)); - } -} - void qmp_cont(Error **errp) { - Error *local_err = NULL; + BlockDriverState *bs; if (runstate_needs_reset()) { error_setg(errp, "Resetting the Virtual Machine is required"); @@ -172,11 +157,16 @@ void qmp_cont(Error **errp) return; } - bdrv_iterate(iostatus_bdrv_it, NULL); - bdrv_iterate(encrypted_bdrv_it, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { + bdrv_iostatus_reset(bs); + } + for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { + if (bdrv_key_required(bs)) { + error_set(errp, QERR_DEVICE_ENCRYPTED, + bdrv_get_device_name(bs), + bdrv_get_encrypted_filename(bs)); + return; + } } if (runstate_check(RUN_STATE_INMIGRATE)) { @@ -405,12 +395,12 @@ static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, #endif /* !CONFIG_VNC */ void qmp_change(const char *device, const char *target, - bool has_arg, const char *arg, Error **err) + bool has_arg, const char *arg, Error **errp) { if (strcmp(device, "vnc") == 0) { - qmp_change_vnc(target, has_arg, arg, err); + qmp_change_vnc(target, has_arg, arg, errp); } else { - qmp_change_blockdev(device, target, arg, err); + qmp_change_blockdev(device, target, arg, errp); } } diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 9734ab0a53..8d9096f65c 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -369,9 +369,10 @@ def gen_command_def_prologue(prefix="", proxy=False): try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m", + opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:i:o:m", ["source", "header", "prefix=", - "output-dir=", "type=", "middle"]) + "input-file=", "output-dir=", + "type=", "middle"]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -389,6 +390,8 @@ do_h = False for o, a in opts: if o in ("-p", "--prefix"): prefix = a + elif o in ("-i", "--input-file"): + input_file = a elif o in ("-o", "--output-dir"): output_dir = a + "/" elif o in ("-t", "--type"): @@ -420,7 +423,7 @@ except os.error, e: if e.errno != errno.EEXIST: raise -exprs = parse_schema(sys.stdin) +exprs = parse_schema(input_file) commands = filter(lambda expr: expr.has_key('command'), exprs) commands = filter(lambda expr: not expr.has_key('gen'), commands) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 10864efc58..b4632324a7 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -279,14 +279,15 @@ void qapi_free_%(type)s(%(c_type)s obj) try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:", + opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", ["source", "header", "builtins", - "prefix=", "output-dir="]) + "prefix=", "input-file=", "output-dir="]) except getopt.GetoptError, err: print str(err) sys.exit(1) output_dir = "" +input_file = "" prefix = "" c_file = 'qapi-types.c' h_file = 'qapi-types.h' @@ -298,6 +299,8 @@ do_builtins = False for o, a in opts: if o in ("-p", "--prefix"): prefix = a + elif o in ("-i", "--input-file"): + input_file = a elif o in ("-o", "--output-dir"): output_dir = a + "/" elif o in ("-c", "--source"): @@ -378,7 +381,7 @@ fdecl.write(mcgen(''' ''', guard=guardname(h_file))) -exprs = parse_schema(sys.stdin) +exprs = parse_schema(input_file) exprs = filter(lambda expr: not expr.has_key('gen'), exprs) fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL")) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 45ce3a957a..c6579beed5 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -397,13 +397,14 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e name=name) try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:", + opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", ["source", "header", "builtins", "prefix=", - "output-dir="]) + "input-file=", "output-dir="]) except getopt.GetoptError, err: print str(err) sys.exit(1) +input_file = "" output_dir = "" prefix = "" c_file = 'qapi-visit.c' @@ -416,6 +417,8 @@ do_builtins = False for o, a in opts: if o in ("-p", "--prefix"): prefix = a + elif o in ("-i", "--input-file"): + input_file = a elif o in ("-o", "--output-dir"): output_dir = a + "/" elif o in ("-c", "--source"): @@ -494,7 +497,7 @@ fdecl.write(mcgen(''' ''', prefix=prefix, guard=guardname(h_file))) -exprs = parse_schema(sys.stdin) +exprs = parse_schema(input_file) # to avoid header dependency hell, we always generate declarations # for built-in types in our header files and simply guard them diff --git a/scripts/qapi.py b/scripts/qapi.py index b474c39558..ec806aabeb 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -11,7 +11,9 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. +import re from ordereddict import OrderedDict +import os import sys builtin_types = [ @@ -35,9 +37,17 @@ builtin_type_qtypes = { 'uint64': 'QTYPE_QINT', } +def error_path(parent): + res = "" + while parent: + res = ("In file included from %s:%d:\n" % (parent['file'], + parent['line'])) + res + parent = parent['parent'] + return res + class QAPISchemaError(Exception): def __init__(self, schema, msg): - self.fp = schema.fp + self.input_file = schema.input_file self.msg = msg self.col = 1 self.line = schema.line @@ -46,23 +56,31 @@ class QAPISchemaError(Exception): self.col = (self.col + 7) % 8 + 1 else: self.col += 1 + self.info = schema.parent_info def __str__(self): - return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg) + return error_path(self.info) + \ + "%s:%d:%d: %s" % (self.input_file, self.line, self.col, self.msg) class QAPIExprError(Exception): def __init__(self, expr_info, msg): - self.fp = expr_info['fp'] - self.line = expr_info['line'] + self.info = expr_info self.msg = msg def __str__(self): - return "%s:%s: %s" % (self.fp.name, self.line, self.msg) + return error_path(self.info['parent']) + \ + "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg) class QAPISchema: - def __init__(self, fp): - self.fp = fp + def __init__(self, fp, input_relname=None, include_hist=[], parent_info=None): + input_fname = os.path.abspath(fp.name) + if input_relname is None: + input_relname = fp.name + self.input_dir = os.path.dirname(input_fname) + self.input_file = input_relname + self.include_hist = include_hist + [(input_relname, input_fname)] + self.parent_info = parent_info self.src = fp.read() if self.src == '' or self.src[-1] != '\n': self.src += '\n' @@ -73,10 +91,33 @@ class QAPISchema: self.accept() while self.tok != None: - expr_info = {'fp': fp, 'line': self.line} - expr_elem = {'expr': self.get_expr(False), - 'info': expr_info} - self.exprs.append(expr_elem) + expr_info = {'file': input_relname, 'line': self.line, 'parent': self.parent_info} + expr = self.get_expr(False) + if isinstance(expr, dict) and "include" in expr: + if len(expr) != 1: + raise QAPIExprError(expr_info, "Invalid 'include' directive") + include = expr["include"] + if not isinstance(include, str): + raise QAPIExprError(expr_info, + 'Expected a file name (string), got: %s' + % include) + include_path = os.path.join(self.input_dir, include) + if any(include_path == elem[1] + for elem in self.include_hist): + raise QAPIExprError(expr_info, "Inclusion loop for %s" + % include) + try: + fobj = open(include_path, 'r') + except IOError as e: + raise QAPIExprError(expr_info, + '%s: %s' % (e.strerror, include)) + exprs_include = QAPISchema(fobj, include, + self.include_hist, expr_info) + self.exprs.extend(exprs_include.exprs) + else: + expr_elem = {'expr': expr, + 'info': expr_info} + self.exprs.append(expr_elem) def accept(self): while True: @@ -263,10 +304,10 @@ def check_exprs(schema): if expr.has_key('union'): check_union(expr, expr_elem['info']) -def parse_schema(fp): +def parse_schema(input_file): try: - schema = QAPISchema(fp) - except QAPISchemaError, e: + schema = QAPISchema(open(input_file, "r")) + except (QAPISchemaError, QAPIExprError), e: print >>sys.stderr, e exit(1) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 8bbcb42cc4..800835a9d3 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -65,13 +65,13 @@ def read_trace_file(edict, fobj): header[0] != header_event_id or \ header[1] != header_magic: raise ValueError('Not a valid trace file!') - if header[2] != 0 and \ - header[2] != 2: - raise ValueError('Unknown version of tracelog format!') log_version = header[2] - if log_version == 0: - raise ValueError('Older log format, not supported with this QEMU release!') + if log_version not in [0, 2, 3]: + raise ValueError('Unknown version of tracelog format!') + if log_version != 3: + raise ValueError('Log format %d not supported with this QEMU release!' + % log_version) while True: rec = read_record(edict, fobj) @@ -109,14 +109,10 @@ def process(events, log, analyzer): if isinstance(log, str): log = open(log, 'rb') - enabled_events = [] dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)") edict = {dropped_event_id: dropped_event} - for e in events: - if 'disable' not in e.properties: - enabled_events.append(e) - for num, event in enumerate(enabled_events): + for num, event in enumerate(events): edict[num] = event def build_fn(analyzer, event): diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index 175df08005..eccf5524f3 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -6,7 +6,7 @@ Machinery for generating tracing-related intermediate files. """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -52,6 +52,10 @@ class Arguments: """ self._args = args + def copy(self): + """Create a new copy.""" + return Arguments(list(self._args)) + @staticmethod def build(arg_str): """Build and Arguments instance from an argument string. @@ -144,7 +148,13 @@ class Event(object): unknown_props = set(self.properties) - self._VALID_PROPS if len(unknown_props) > 0: - raise ValueError("Unknown properties: %s" % ", ".join(unknown_props)) + raise ValueError("Unknown properties: %s" + % ", ".join(unknown_props)) + + def copy(self): + """Create a new copy.""" + return Event(self.name, list(self.properties), self.fmt, + self.args.copy(), self) @staticmethod def build(line_str): @@ -173,6 +183,14 @@ class Event(object): self.args, self.fmt) + QEMU_TRACE = "trace_%(name)s" + + def api(self, fmt=None): + if fmt is None: + fmt = Event.QEMU_TRACE + return fmt % {"name": self.name} + + def _read_events(fobj): res = [] for line in fobj: @@ -189,7 +207,7 @@ class TracetoolError (Exception): pass -def try_import(mod_name, attr_name = None, attr_default = None): +def try_import(mod_name, attr_name=None, attr_default=None): """Try to import a module and get an attribute from it. Parameters @@ -216,7 +234,7 @@ def try_import(mod_name, attr_name = None, attr_default = None): def generate(fevents, format, backend, - binary = None, probe_prefix = None): + binary=None, probe_prefix=None): """Generate the output for the given (format, backend) pair. Parameters @@ -238,20 +256,17 @@ def generate(fevents, format, backend, format = str(format) if len(format) is 0: raise TracetoolError("format not set") - mformat = format.replace("-", "_") - if not tracetool.format.exists(mformat): + if not tracetool.format.exists(format): raise TracetoolError("unknown format: %s" % format) + format = format.replace("-", "_") backend = str(backend) if len(backend) is 0: raise TracetoolError("backend not set") - mbackend = backend.replace("-", "_") - if not tracetool.backend.exists(mbackend): + if not tracetool.backend.exists(backend): raise TracetoolError("unknown backend: %s" % backend) - - if not tracetool.backend.compatible(mbackend, mformat): - raise TracetoolError("backend '%s' not compatible with format '%s'" % - (backend, format)) + backend = backend.replace("-", "_") + backend = tracetool.backend.Wrapper(backend, format) import tracetool.backend.dtrace tracetool.backend.dtrace.BINARY = binary @@ -259,16 +274,4 @@ def generate(fevents, format, backend, events = _read_events(fevents) - if backend == "nop": - ( e.properies.add("disable") for e in events ) - - tracetool.format.generate_begin(mformat, events) - tracetool.backend.generate("nop", format, - [ e - for e in events - if "disable" in e.properties ]) - tracetool.backend.generate(backend, format, - [ e - for e in events - if "disable" not in e.properties ]) - tracetool.format.generate_end(mformat, events) + tracetool.format.generate(events, format, backend) diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py index f0314ee376..5e36f0415d 100644 --- a/scripts/tracetool/backend/__init__.py +++ b/scripts/tracetool/backend/__init__.py @@ -30,17 +30,24 @@ PUBLIC If exists and is set to 'True', the backend is considered "public". Backend functions ----------------- -======== ======================================================================= -Function Description -======== ======================================================================= -<format> Called to generate the format- and backend-specific code for each of - the specified events. If the function does not exist, the backend is - considered not compatible with the given format. -======== ======================================================================= +All the following functions are optional, and no output will be generated if +they do not exist. + +=============================== ============================================== +Function Description +=============================== ============================================== +generate_<format>_begin(events) Generate backend- and format-specific file + header contents. +generate_<format>_end(events) Generate backend- and format-specific file + footer contents. +generate_<format>(event) Generate backend- and format-specific contents + for the given event. +=============================== ============================================== + """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -59,7 +66,7 @@ def get_list(only_public = False): for filename in os.listdir(tracetool.backend.__path__[0]): if filename.endswith('.py') and filename != '__init__.py': modnames.append(filename.rsplit('.', 1)[0]) - for modname in modnames: + for modname in sorted(modnames): module = tracetool.try_import("tracetool.backend." + modname) # just in case; should never fail unless non-module files are put there @@ -91,39 +98,24 @@ def exists(name): return tracetool.try_import("tracetool.backend." + name)[1] -def compatible(backend, format): - """Whether a backend is compatible with the given format.""" - if not exists(backend): - raise ValueError("unknown backend: %s" % backend) - - backend = backend.replace("-", "_") - format = format.replace("-", "_") - - if backend == "nop": - return True - else: - func = tracetool.try_import("tracetool.backend." + backend, - format, None)[1] - return func is not None - - -def _empty(events): - pass +class Wrapper: + def __init__(self, backend, format): + self._backend = backend.replace("-", "_") + self._format = format.replace("-", "_") + assert exists(self._backend) + assert tracetool.format.exists(self._format) -def generate(backend, format, events): - """Generate the per-event output for the given (backend, format) pair.""" - if not compatible(backend, format): - raise ValueError("backend '%s' not compatible with format '%s'" % - (backend, format)) + def _run_function(self, name, *args, **kwargs): + func = tracetool.try_import("tracetool.backend." + self._backend, + name % self._format, None)[1] + if func is not None: + func(*args, **kwargs) - backend = backend.replace("-", "_") - format = format.replace("-", "_") + def generate_begin(self, events): + self._run_function("generate_%s_begin", events) - if backend == "nop": - func = tracetool.try_import("tracetool.format." + format, - "nop", _empty)[1] - else: - func = tracetool.try_import("tracetool.backend." + backend, - format, None)[1] + def generate(self, event): + self._run_function("generate_%s", event) - func(events) + def generate_end(self, events): + self._run_function("generate_%s_end", events) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index e31bc799f8..fabfe99881 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -6,7 +6,7 @@ DTrace/SystemTAP backend. """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -21,7 +21,7 @@ PUBLIC = True PROBEPREFIX = None -def _probeprefix(): +def probeprefix(): if PROBEPREFIX is None: raise ValueError("you must set PROBEPREFIX") return PROBEPREFIX @@ -29,81 +29,18 @@ def _probeprefix(): BINARY = None -def _binary(): +def binary(): if BINARY is None: raise ValueError("you must set BINARY") return BINARY -def c(events): - pass - - -def h(events): +def generate_h_begin(events): out('#include "trace/generated-tracers-dtrace.h"', '') - for e in events: - out('static inline void trace_%(name)s(%(args)s) {', - ' QEMU_%(uppername)s(%(argnames)s);', - '}', - name = e.name, - args = e.args, - uppername = e.name.upper(), - argnames = ", ".join(e.args.names()), - ) - - -def d(events): - out('provider qemu {') - - for e in events: - args = str(e.args) - - # DTrace provider syntax expects foo() for empty - # params, not foo(void) - if args == 'void': - args = '' - - # Define prototype for probe arguments - out('', - 'probe %(name)s(%(args)s);', - name = e.name, - args = args, - ) - - out('', - '};') - - -# Technically 'self' is not used by systemtap yet, but -# they recommended we keep it in the reserved list anyway -RESERVED_WORDS = ( - 'break', 'catch', 'continue', 'delete', 'else', 'for', - 'foreach', 'function', 'global', 'if', 'in', 'limit', - 'long', 'next', 'probe', 'return', 'self', 'string', - 'try', 'while' - ) - -def stap(events): - for e in events: - # Define prototype for probe arguments - out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")', - '{', - probeprefix = _probeprefix(), - name = e.name, - binary = _binary(), - ) - - i = 1 - if len(e.args) > 0: - for name in e.args.names(): - # Append underscore to reserved keywords - if name in RESERVED_WORDS: - name += '_' - out(' %s = $arg%d;' % (name, i)) - i += 1 - - out('}') - - out() + +def generate_h(event): + out(' QEMU_%(uppername)s(%(argnames)s);', + uppername=event.name.upper(), + argnames=", ".join(event.args.names())) diff --git a/scripts/tracetool/backend/events.py b/scripts/tracetool/backend/events.py deleted file mode 100644 index 5afce3e8da..0000000000 --- a/scripts/tracetool/backend/events.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generic event description. - -This is a dummy backend to establish appropriate frontend/backend compatibility -checks. -""" - -__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -def events_h(events): - pass - -def events_c(events): - pass diff --git a/scripts/tracetool/backend/ftrace.py b/scripts/tracetool/backend/ftrace.py index 888c361aec..d798c71347 100644 --- a/scripts/tracetool/backend/ftrace.py +++ b/scripts/tracetool/backend/ftrace.py @@ -19,36 +19,30 @@ from tracetool import out PUBLIC = True -def c(events): - pass - -def h(events): +def generate_h_begin(events): out('#include "trace/ftrace.h"', '#include "trace/control.h"', - '', - ) - - for e in events: - argnames = ", ".join(e.args.names()) - if len(e.args) > 0: - argnames = ", " + argnames - - out('static inline void trace_%(name)s(%(args)s)', - '{', - ' char ftrace_buf[MAX_TRACE_STRLEN];', - ' int unused __attribute__ ((unused));', - ' int trlen;', - ' bool _state = trace_event_get_state(%(event_id)s);', - ' if (_state) {', - ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,', - ' "%(name)s " %(fmt)s "\\n" %(argnames)s);', - ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);', - ' unused = write(trace_marker_fd, ftrace_buf, trlen);', - ' }', - '}', - name = e.name, - args = e.args, - event_id = "TRACE_" + e.name.upper(), - fmt = e.fmt.rstrip("\n"), - argnames = argnames, - ) + '') + + +def generate_h(event): + argnames = ", ".join(event.args.names()) + if len(event.args) > 0: + argnames = ", " + argnames + + out(' {', + ' char ftrace_buf[MAX_TRACE_STRLEN];', + ' int unused __attribute__ ((unused));', + ' int trlen;', + ' if (trace_event_get_state(%(event_id)s)) {', + ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,', + ' "%(name)s " %(fmt)s "\\n" %(argnames)s);', + ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);', + ' unused = write(trace_marker_fd, ftrace_buf, trlen);', + ' }', + ' }', + name=event.name, + args=event.args, + event_id="TRACE_" + event.name.upper(), + fmt=event.fmt.rstrip("\n"), + argnames=argnames) diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index 3dde372e46..e8c2cd57e9 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -6,7 +6,7 @@ Simple built-in backend. """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -26,76 +26,74 @@ def is_string(arg): else: return False -def c(events): + +def generate_h_begin(events): + for event in events: + out('void _simple_%(api)s(%(args)s);', + api=event.api(), + args=event.args) + out('') + + +def generate_h(event): + out(' _simple_%(api)s(%(args)s);', + api=event.api(), + args=", ".join(event.args.names())) + + +def generate_c_begin(events): out('#include "trace.h"', '#include "trace/control.h"', '#include "trace/simple.h"', + '') + + +def generate_c(event): + out('void _simple_%(api)s(%(args)s)', + '{', + ' TraceBufferRecord rec;', + api=event.api(), + args=event.args) + sizes = [] + for type_, name in event.args: + if is_string(type_): + out(' size_t arg%(name)s_len = %(name)s ? MIN(strlen(%(name)s), MAX_TRACE_STRLEN) : 0;', + name=name) + strsizeinfo = "4 + arg%s_len" % name + sizes.append(strsizeinfo) + else: + sizes.append("8") + sizestr = " + ".join(sizes) + if len(event.args) == 0: + sizestr = '0' + + + out('', + ' if (!trace_event_get_state(%(event_id)s)) {', + ' return;', + ' }', '', - ) - - for num, event in enumerate(events): - out('void trace_%(name)s(%(args)s)', - '{', - ' TraceBufferRecord rec;', - name = event.name, - args = event.args, - ) - sizes = [] + ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', + ' return; /* Trace Buffer Full, Event Dropped ! */', + ' }', + event_id='TRACE_' + event.name.upper(), + size_str=sizestr) + + if len(event.args) > 0: for type_, name in event.args: + # string if is_string(type_): - out(' size_t arg%(name)s_len = %(name)s ? MIN(strlen(%(name)s), MAX_TRACE_STRLEN) : 0;', - name = name, - ) - strsizeinfo = "4 + arg%s_len" % name - sizes.append(strsizeinfo) + out(' trace_record_write_str(&rec, %(name)s, arg%(name)s_len);', + name=name) + # pointer var (not string) + elif type_.endswith('*'): + out(' trace_record_write_u64(&rec, (uintptr_t)(uint64_t *)%(name)s);', + name=name) + # primitive data type else: - sizes.append("8") - sizestr = " + ".join(sizes) - if len(event.args) == 0: - sizestr = '0' - - - out('', - ' TraceEvent *eventp = trace_event_id(%(event_enum)s);', - ' bool _state = trace_event_get_state_dynamic(eventp);', - ' if (!_state) {', - ' return;', - ' }', - '', - ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', - ' return; /* Trace Buffer Full, Event Dropped ! */', - ' }', - event_enum = 'TRACE_' + event.name.upper(), - event_id = num, - size_str = sizestr, - ) - - if len(event.args) > 0: - for type_, name in event.args: - # string - if is_string(type_): - out(' trace_record_write_str(&rec, %(name)s, arg%(name)s_len);', - name = name, - ) - # pointer var (not string) - elif type_.endswith('*'): - out(' trace_record_write_u64(&rec, (uintptr_t)(uint64_t *)%(name)s);', - name = name, - ) - # primitive data type - else: - out(' trace_record_write_u64(&rec, (uint64_t)%(name)s);', - name = name, - ) - - out(' trace_record_finish(&rec);', - '}', - '') - - -def h(events): - for event in events: - out('void trace_%(name)s(%(args)s);', - name = event.name, - args = event.args, - ) + out(' trace_record_write_u64(&rec, (uint64_t)%(name)s);', + name=name) + + out(' trace_record_finish(&rec);', + '}', + '') diff --git a/scripts/tracetool/backend/stderr.py b/scripts/tracetool/backend/stderr.py index 6f93dbd1ae..2a1e9064c3 100644 --- a/scripts/tracetool/backend/stderr.py +++ b/scripts/tracetool/backend/stderr.py @@ -6,7 +6,7 @@ Stderr built-in backend. """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -19,30 +19,21 @@ from tracetool import out PUBLIC = True -def c(events): - pass - -def h(events): +def generate_h_begin(events): out('#include <stdio.h>', '#include "trace/control.h"', - '', - ) - - for e in events: - argnames = ", ".join(e.args.names()) - if len(e.args) > 0: - argnames = ", " + argnames - - out('static inline void trace_%(name)s(%(args)s)', - '{', - ' bool _state = trace_event_get_state(%(event_id)s);', - ' if (_state) {', - ' fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);', - ' }', - '}', - name = e.name, - args = e.args, - event_id = "TRACE_" + e.name.upper(), - fmt = e.fmt.rstrip("\n"), - argnames = argnames, - ) + '') + + +def generate_h(event): + argnames = ", ".join(event.args.names()) + if len(event.args) > 0: + argnames = ", " + argnames + + out(' if (trace_event_get_state(%(event_id)s)) {', + ' fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);', + ' }', + event_id="TRACE_" + event.name.upper(), + name=event.name, + fmt=event.fmt.rstrip("\n"), + argnames=argnames) diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py index 41c1c75b7c..2f8f44abde 100644 --- a/scripts/tracetool/backend/ust.py +++ b/scripts/tracetool/backend/ust.py @@ -6,7 +6,7 @@ LTTng User Space Tracing backend. """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -18,65 +18,18 @@ from tracetool import out PUBLIC = True -def c(events): - pass - -def h(events): +def generate_h_begin(events): out('#include <lttng/tracepoint.h>', '#include "trace/generated-ust-provider.h"', '') - for e in events: - argnames = ", ".join(e.args.names()) - if len(e.args) > 0: - argnames = ", " + argnames - - out('static inline void trace_%(name)s(%(args)s)', - '{', - ' tracepoint(qemu, %(name)s%(tp_args)s);', - '}', - '', - name = e.name, - args = e.args, - tp_args = argnames, - ) - -def ust_events_c(events): - pass - -def ust_events_h(events): - for e in events: - if len(e.args) > 0: - out('TRACEPOINT_EVENT(', - ' qemu,', - ' %(name)s,', - ' TP_ARGS(%(args)s),', - ' TP_FIELDS(', - name = e.name, - args = ", ".join(", ".join(i) for i in e.args), - ) - for t,n in e.args: - if ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t): - out(' ctf_integer(' + t + ', ' + n + ', ' + n + ')') - elif ('double' in t) or ('float' in t): - out(' ctf_float(' + t + ', ' + n + ', ' + n + ')') - elif ('char *' in t) or ('char*' in t): - out(' ctf_string(' + n + ', ' + n + ')') - elif ('void *' in t) or ('void*' in t): - out(' ctf_integer_hex(unsigned long, ' + n + ', ' + n + ')') - out(' )', - ')', - '') +def generate_h(event): + argnames = ", ".join(event.args.names()) + if len(event.args) > 0: + argnames = ", " + argnames - else: - out('TRACEPOINT_EVENT(', - ' qemu,', - ' %(name)s,', - ' TP_ARGS(void),', - ' TP_FIELDS()', - ')', - '', - name = e.name, - )
\ No newline at end of file + out(' tracepoint(qemu, %(name)s%(tp_args)s);', + name=event.name, + tp_args=argnames) diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py index 3c2a0d89e0..812570ff6f 100644 --- a/scripts/tracetool/format/__init__.py +++ b/scripts/tracetool/format/__init__.py @@ -20,21 +20,16 @@ All formats must generate their contents through the 'tracetool.out' routine. Format functions ---------------- -All the following functions are optional, and no output will be generated if -they do not exist. - -======== ======================================================================= +======== ================================================================== Function Description -======== ======================================================================= -begin Called to generate the format-specific file header. -end Called to generate the format-specific file footer. -nop Called to generate the per-event contents when the event is disabled or - the selected backend is 'nop'. -======== ======================================================================= +======== ================================================================== +generate Called to generate a format-specific file. +======== ================================================================== + """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -53,7 +48,7 @@ def get_list(): for filename in os.listdir(tracetool.format.__path__[0]): if filename.endswith('.py') and filename != '__init__.py': modnames.append(filename.rsplit('.', 1)[0]) - for modname in modnames: + for modname in sorted(modnames): module = tracetool.try_import("tracetool.format." + modname) # just in case; should never fail unless non-module files are put there @@ -79,25 +74,12 @@ def exists(name): return tracetool.try_import("tracetool.format." + name)[1] -def _empty(events): - pass - -def generate_begin(name, events): - """Generate the header of the format-specific file.""" - if not exists(name): - raise ValueError("unknown format: %s" % name) - - name = name.replace("-", "_") - func = tracetool.try_import("tracetool.format." + name, - "begin", _empty)[1] - func(events) - -def generate_end(name, events): - """Generate the footer of the format-specific file.""" - if not exists(name): - raise ValueError("unknown format: %s" % name) - - name = name.replace("-", "_") - func = tracetool.try_import("tracetool.format." + name, - "end", _empty)[1] - func(events) +def generate(events, format, backend): + if not exists(format): + raise ValueError("unknown format: %s" % format) + format = format.replace("-", "_") + func = tracetool.try_import("tracetool.format." + format, + "generate")[1] + if func is None: + raise AttributeError("format has no 'generate': %s" % format) + func(events, backend) diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py index 35555aee1f..699598fb02 100644 --- a/scripts/tracetool/format/c.py +++ b/scripts/tracetool/format/c.py @@ -2,11 +2,11 @@ # -*- coding: utf-8 -*- """ -Generate .c file. +trace/generated-tracers.c """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -16,5 +16,13 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out -def begin(events): - out('/* This file is autogenerated by tracetool, do not edit. */') +def generate(events, backend): + events = [e for e in events + if "disable" not in e.properties] + + out('/* This file is autogenerated by tracetool, do not edit. */', + '') + backend.generate_begin(events) + for event in events: + backend.generate(event) + backend.generate_end(events) diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py index a2d594773c..46eebb128b 100644 --- a/scripts/tracetool/format/d.py +++ b/scripts/tracetool/format/d.py @@ -2,11 +2,11 @@ # -*- coding: utf-8 -*- """ -Generate .d file (DTrace only). +trace/generated-tracers.dtrace (DTrace only). """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -16,5 +16,27 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out -def begin(events): - out('/* This file is autogenerated by tracetool, do not edit. */') +def generate(events, backend): + events = [e for e in events + if "disable" not in e.properties] + + out('/* This file is autogenerated by tracetool, do not edit. */' + '', + 'provider qemu {') + + for e in events: + args = str(e.args) + + # DTrace provider syntax expects foo() for empty + # params, not foo(void) + if args == 'void': + args = '' + + # Define prototype for probe arguments + out('', + 'probe %(name)s(%(args)s);', + name=e.name, + args=args) + + out('', + '};') diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index d670ec83d5..2d97fa310a 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -2,11 +2,11 @@ # -*- coding: utf-8 -*- """ -Generate .c for event description. +trace/generated-events.c """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -16,14 +16,13 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out -def begin(events): +def generate(events, backend): out('/* This file is autogenerated by tracetool, do not edit. */', '', '#include "trace.h"', '#include "trace/generated-events.h"', '#include "trace/control.h"', - '', - ) + '') out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {') @@ -31,9 +30,7 @@ def begin(events): out(' { .id = %(id)s, .name = \"%(name)s\", .sstate = %(sstate)s, .dstate = 0 },', id = "TRACE_" + e.name.upper(), name = e.name, - sstate = "TRACE_%s_ENABLED" % e.name.upper(), - ) + sstate = "TRACE_%s_ENABLED" % e.name.upper()) out('};', - '', - ) + '') diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index d30ccea8a1..25d913bb25 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -2,11 +2,11 @@ # -*- coding: utf-8 -*- """ -Generate .h for event description. +trace/generated-events.h """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -16,15 +16,14 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out -def begin(events): +def generate(events, backend): out('/* This file is autogenerated by tracetool, do not edit. */', '', '#ifndef TRACE__GENERATED_EVENTS_H', '#define TRACE__GENERATED_EVENTS_H', '', '#include <stdbool.h>', - '' - ) + '') # event identifiers out('typedef enum {') @@ -33,8 +32,7 @@ def begin(events): out(' TRACE_%s,' % e.name.upper()) out(' TRACE_EVENT_COUNT', - '} TraceEventID;', - ) + '} TraceEventID;') # static state for e in events: @@ -46,5 +44,4 @@ def begin(events): out('#include "trace/event-internal.h"', '', - '#endif /* TRACE__GENERATED_EVENTS_H */', - ) + '#endif /* TRACE__GENERATED_EVENTS_H */') diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 93132fceaf..9b3943002c 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -2,11 +2,11 @@ # -*- coding: utf-8 -*- """ -Generate .h file. +trace/generated-tracers.h """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -16,23 +16,29 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out -def begin(events): +def generate(events, backend): out('/* This file is autogenerated by tracetool, do not edit. */', '', '#ifndef TRACE__GENERATED_TRACERS_H', '#define TRACE__GENERATED_TRACERS_H', '', - '#include "qemu-common.h"') + '#include "qemu-common.h"', + '') -def end(events): - out('#endif /* TRACE__GENERATED_TRACERS_H */') + backend.generate_begin(events) -def nop(events): for e in events: out('', - 'static inline void trace_%(name)s(%(args)s)', + 'static inline void %(api)s(%(args)s)', '{', - '}', - name = e.name, - args = e.args, - ) + api=e.api(), + args=e.args) + + if "disable" not in e.properties: + backend.generate(e) + + out('}') + + backend.generate_end(events) + + out('#endif /* TRACE__GENERATED_TRACERS_H */') diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py index 50a4c69954..e24abf7f11 100644 --- a/scripts/tracetool/format/stap.py +++ b/scripts/tracetool/format/stap.py @@ -6,7 +6,7 @@ Generate .stp file (DTrace with SystemTAP only). """ __author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012-2014, LluÃs Vilanova <vilanova@ac.upc.edu>" __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -14,7 +14,43 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out +from tracetool.backend.dtrace import binary, probeprefix -def begin(events): - out('/* This file is autogenerated by tracetool, do not edit. */') +# Technically 'self' is not used by systemtap yet, but +# they recommended we keep it in the reserved list anyway +RESERVED_WORDS = ( + 'break', 'catch', 'continue', 'delete', 'else', 'for', + 'foreach', 'function', 'global', 'if', 'in', 'limit', + 'long', 'next', 'probe', 'return', 'self', 'string', + 'try', 'while' + ) + + +def generate(events, backend): + events = [e for e in events + if "disable" not in e.properties] + + out('/* This file is autogenerated by tracetool, do not edit. */', + '') + + for e in events: + # Define prototype for probe arguments + out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")', + '{', + probeprefix=probeprefix(), + name=e.name, + binary=binary()) + + i = 1 + if len(e.args) > 0: + for name in e.args.names(): + # Append underscore to reserved keywords + if name in RESERVED_WORDS: + name += '_' + out(' %s = $arg%d;' % (name, i)) + i += 1 + + out('}') + + out() diff --git a/scripts/tracetool/format/ust_events_c.py b/scripts/tracetool/format/ust_events_c.py index 116e713225..bc970936be 100644 --- a/scripts/tracetool/format/ust_events_c.py +++ b/scripts/tracetool/format/ust_events_c.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ -Generate .c for LTTng ust event description. +trace/generated-ust.c """ __author__ = "Mohamad Gebai <mohamad.gebai@polymtl.ca>" @@ -16,7 +16,10 @@ __email__ = "stefanha@redhat.com" from tracetool import out -def begin(events): +def generate(events, backend): + events = [e for e in events + if "disabled" not in e.properties] + out('/* This file is autogenerated by tracetool, do not edit. */', '', '#define TRACEPOINT_DEFINE', diff --git a/scripts/tracetool/format/ust_events_h.py b/scripts/tracetool/format/ust_events_h.py index f206eca6ec..5102565470 100644 --- a/scripts/tracetool/format/ust_events_h.py +++ b/scripts/tracetool/format/ust_events_h.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ -Generate .h for LTTng ust event description. +trace/generated-ust-provider.h """ __author__ = "Mohamad Gebai <mohamad.gebai@polymtl.ca>" @@ -16,7 +16,10 @@ __email__ = "stefanha@redhat.com" from tracetool import out -def begin(events): +def generate(events, backend): + events = [e for e in events + if "disabled" not in e.properties] + out('/* This file is autogenerated by tracetool, do not edit. */', '', '#undef TRACEPOINT_PROVIDER', @@ -50,7 +53,40 @@ def begin(events): '#endif', '') -def end(events): + for e in events: + if len(e.args) > 0: + out('TRACEPOINT_EVENT(', + ' qemu,', + ' %(name)s,', + ' TP_ARGS(%(args)s),', + ' TP_FIELDS(', + name=e.name, + args=", ".join(", ".join(i) for i in e.args)) + + for t, n in e.args: + if ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t): + out(' ctf_integer(' + t + ', ' + n + ', ' + n + ')') + elif ('double' in t) or ('float' in t): + out(' ctf_float(' + t + ', ' + n + ', ' + n + ')') + elif ('char *' in t) or ('char*' in t): + out(' ctf_string(' + n + ', ' + n + ')') + elif ('void *' in t) or ('void*' in t): + out(' ctf_integer_hex(unsigned long, ' + n + ', ' + n + ')') + + out(' )', + ')', + '') + + else: + out('TRACEPOINT_EVENT(', + ' qemu,', + ' %(name)s,', + ' TP_ARGS(void),', + ' TP_FIELDS()', + ')', + '', + name=e.name) + out('#endif /* TRACE__GENERATED_UST_H */', '', '/* This part must be outside ifdef protection */', diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 8e0481186a..0379f2be2c 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -96,6 +96,8 @@ static void mb_cpu_reset(CPUState *s) env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17); + env->sregs[SR_PC] = cpu->base_vectors; + #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM; diff --git a/tests/Makefile b/tests/Makefile index 14ecf05b5d..6b8b6f273a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -190,7 +190,10 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ 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) + 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) GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h @@ -242,13 +245,19 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a @@ -400,9 +409,14 @@ check-tests/test-qapi.py: tests/test-qapi.py .PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json - $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py <$^ >$*.test.out 2>$*.test.err; echo $$? >$*.test.exit, " TEST $*.out") + $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \ + $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \ + $^ >$*.test.out 2>$*.test.err; \ + echo $$? >$*.test.exit, \ + " TEST $*.out") @diff -q $(SRC_PATH)/$*.out $*.test.out - @diff -q $(SRC_PATH)/$*.err $*.test.err + @# Sanitize error messages (make them independent of build directory) + @perl -p -e 's|\Q$(SRC_PATH)\E/||g' $*.test.err | diff -q $(SRC_PATH)/$*.err - @diff -q $(SRC_PATH)/$*.exit $*.test.exit # Consolidated targets diff --git a/tests/qapi-schema/duplicate-key.err b/tests/qapi-schema/duplicate-key.err index 0801c6a9bb..768b276f80 100644 --- a/tests/qapi-schema/duplicate-key.err +++ b/tests/qapi-schema/duplicate-key.err @@ -1 +1 @@ -<stdin>:2:10: Duplicate key "key" +tests/qapi-schema/duplicate-key.json:2:10: Duplicate key "key" diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err index 1125caf5db..ccf72d2dfe 100644 --- a/tests/qapi-schema/flat-union-invalid-branch-key.err +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err @@ -1 +1 @@ -<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' +tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err index cad9dbf225..790b6759b8 100644 --- a/tests/qapi-schema/flat-union-invalid-discriminator.err +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err @@ -1 +1 @@ -<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase' +tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase' diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err index e2d7443a3b..a59749eb84 100644 --- a/tests/qapi-schema/flat-union-no-base.err +++ b/tests/qapi-schema/flat-union-no-base.err @@ -1 +1 @@ -<stdin>:7: Flat union 'TestUnion' must have a base field +tests/qapi-schema/flat-union-no-base.json:7: Flat union 'TestUnion' must have a base field diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err index 87482704ec..200016bd5c 100644 --- a/tests/qapi-schema/flat-union-string-discriminator.err +++ b/tests/qapi-schema/flat-union-string-discriminator.err @@ -1 +1 @@ -<stdin>:13: Discriminator 'kind' must be of enumeration type +tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err index d3dd293faf..bfc890cd9f 100644 --- a/tests/qapi-schema/funny-char.err +++ b/tests/qapi-schema/funny-char.err @@ -1 +1 @@ -<stdin>:2:36: Stray ";" +tests/qapi-schema/funny-char.json:2:36: Stray ";" diff --git a/tests/qapi-schema/include-before-err.err b/tests/qapi-schema/include-before-err.err new file mode 100644 index 0000000000..55652751e1 --- /dev/null +++ b/tests/qapi-schema/include-before-err.err @@ -0,0 +1 @@ +tests/qapi-schema/include-before-err.json:2:13: Expected ":" diff --git a/tests/qapi-schema/include-before-err.exit b/tests/qapi-schema/include-before-err.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-before-err.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-before-err.json b/tests/qapi-schema/include-before-err.json new file mode 100644 index 0000000000..afb6cb63c4 --- /dev/null +++ b/tests/qapi-schema/include-before-err.json @@ -0,0 +1,2 @@ +{ 'include': 'include-simple-sub.json' } +{ 'command' 'missing-colon' } diff --git a/tests/qapi-schema/include-before-err.out b/tests/qapi-schema/include-before-err.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-before-err.out diff --git a/tests/qapi-schema/include-cycle-b.json b/tests/qapi-schema/include-cycle-b.json new file mode 100644 index 0000000000..4fa985dcd5 --- /dev/null +++ b/tests/qapi-schema/include-cycle-b.json @@ -0,0 +1 @@ +{ 'include': 'include-cycle-c.json' } diff --git a/tests/qapi-schema/include-cycle-c.json b/tests/qapi-schema/include-cycle-c.json new file mode 100644 index 0000000000..d12b5924a3 --- /dev/null +++ b/tests/qapi-schema/include-cycle-c.json @@ -0,0 +1 @@ +{ 'include': 'include-cycle.json' } diff --git a/tests/qapi-schema/include-cycle.err b/tests/qapi-schema/include-cycle.err new file mode 100644 index 0000000000..602cf62329 --- /dev/null +++ b/tests/qapi-schema/include-cycle.err @@ -0,0 +1,3 @@ +In file included from tests/qapi-schema/include-cycle.json:1: +In file included from include-cycle-b.json:1: +include-cycle-c.json:1: Inclusion loop for include-cycle.json diff --git a/tests/qapi-schema/include-cycle.exit b/tests/qapi-schema/include-cycle.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-cycle.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-cycle.json b/tests/qapi-schema/include-cycle.json new file mode 100644 index 0000000000..6fcf1ebaac --- /dev/null +++ b/tests/qapi-schema/include-cycle.json @@ -0,0 +1 @@ +{ 'include': 'include-cycle-b.json' } diff --git a/tests/qapi-schema/include-cycle.out b/tests/qapi-schema/include-cycle.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-cycle.out diff --git a/tests/qapi-schema/include-format-err.err b/tests/qapi-schema/include-format-err.err new file mode 100644 index 0000000000..721ff4eccc --- /dev/null +++ b/tests/qapi-schema/include-format-err.err @@ -0,0 +1 @@ +tests/qapi-schema/include-format-err.json:1: Invalid 'include' directive diff --git a/tests/qapi-schema/include-format-err.exit b/tests/qapi-schema/include-format-err.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-format-err.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-format-err.json b/tests/qapi-schema/include-format-err.json new file mode 100644 index 0000000000..44980f026f --- /dev/null +++ b/tests/qapi-schema/include-format-err.json @@ -0,0 +1,2 @@ +{ 'include': 'include-simple-sub.json', + 'foo': 'bar' } diff --git a/tests/qapi-schema/include-format-err.out b/tests/qapi-schema/include-format-err.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-format-err.out diff --git a/tests/qapi-schema/include-nested-err.err b/tests/qapi-schema/include-nested-err.err new file mode 100644 index 0000000000..1dacbda3be --- /dev/null +++ b/tests/qapi-schema/include-nested-err.err @@ -0,0 +1,2 @@ +In file included from tests/qapi-schema/include-nested-err.json:1: +missing-colon.json:1:10: Expected ":" diff --git a/tests/qapi-schema/include-nested-err.exit b/tests/qapi-schema/include-nested-err.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-nested-err.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-nested-err.json b/tests/qapi-schema/include-nested-err.json new file mode 100644 index 0000000000..5631e56ea0 --- /dev/null +++ b/tests/qapi-schema/include-nested-err.json @@ -0,0 +1 @@ +{ 'include': 'missing-colon.json' } diff --git a/tests/qapi-schema/include-nested-err.out b/tests/qapi-schema/include-nested-err.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-nested-err.out diff --git a/tests/qapi-schema/include-no-file.err b/tests/qapi-schema/include-no-file.err new file mode 100644 index 0000000000..d5b9b22d85 --- /dev/null +++ b/tests/qapi-schema/include-no-file.err @@ -0,0 +1 @@ +tests/qapi-schema/include-no-file.json:1: No such file or directory: include-no-file-sub.json diff --git a/tests/qapi-schema/include-no-file.exit b/tests/qapi-schema/include-no-file.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-no-file.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-no-file.json b/tests/qapi-schema/include-no-file.json new file mode 100644 index 0000000000..9249ebd50c --- /dev/null +++ b/tests/qapi-schema/include-no-file.json @@ -0,0 +1 @@ +{ 'include': 'include-no-file-sub.json' } diff --git a/tests/qapi-schema/include-no-file.out b/tests/qapi-schema/include-no-file.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-no-file.out diff --git a/tests/qapi-schema/include-non-file.err b/tests/qapi-schema/include-non-file.err new file mode 100644 index 0000000000..9658c78801 --- /dev/null +++ b/tests/qapi-schema/include-non-file.err @@ -0,0 +1 @@ +tests/qapi-schema/include-non-file.json:1: Expected a file name (string), got: ['foo', 'bar'] diff --git a/tests/qapi-schema/include-non-file.exit b/tests/qapi-schema/include-non-file.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-non-file.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-non-file.json b/tests/qapi-schema/include-non-file.json new file mode 100644 index 0000000000..cd43c3f9db --- /dev/null +++ b/tests/qapi-schema/include-non-file.json @@ -0,0 +1 @@ +{ 'include': [ 'foo', 'bar' ] } diff --git a/tests/qapi-schema/include-non-file.out b/tests/qapi-schema/include-non-file.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-non-file.out diff --git a/tests/qapi-schema/include-relpath-sub.json b/tests/qapi-schema/include-relpath-sub.json new file mode 100644 index 0000000000..4bd4af4162 --- /dev/null +++ b/tests/qapi-schema/include-relpath-sub.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/include-relpath.err b/tests/qapi-schema/include-relpath.err new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-relpath.err diff --git a/tests/qapi-schema/include-relpath.exit b/tests/qapi-schema/include-relpath.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/include-relpath.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/include-relpath.json b/tests/qapi-schema/include-relpath.json new file mode 100644 index 0000000000..05018f3908 --- /dev/null +++ b/tests/qapi-schema/include-relpath.json @@ -0,0 +1 @@ +{ 'include': 'include/relpath.json' } diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out new file mode 100644 index 0000000000..4ce3dcf12f --- /dev/null +++ b/tests/qapi-schema/include-relpath.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] +[] diff --git a/tests/qapi-schema/include-self-cycle.err b/tests/qapi-schema/include-self-cycle.err new file mode 100644 index 0000000000..981742ae5f --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.err @@ -0,0 +1 @@ +tests/qapi-schema/include-self-cycle.json:1: Inclusion loop for include-self-cycle.json diff --git a/tests/qapi-schema/include-self-cycle.exit b/tests/qapi-schema/include-self-cycle.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-self-cycle.json b/tests/qapi-schema/include-self-cycle.json new file mode 100644 index 0000000000..55fb1b596f --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.json @@ -0,0 +1 @@ +{ 'include': 'include-self-cycle.json' } diff --git a/tests/qapi-schema/include-self-cycle.out b/tests/qapi-schema/include-self-cycle.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.out diff --git a/tests/qapi-schema/include-simple-sub.json b/tests/qapi-schema/include-simple-sub.json new file mode 100644 index 0000000000..4bd4af4162 --- /dev/null +++ b/tests/qapi-schema/include-simple-sub.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/include-simple.err b/tests/qapi-schema/include-simple.err new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/include-simple.err diff --git a/tests/qapi-schema/include-simple.exit b/tests/qapi-schema/include-simple.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/include-simple.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/include-simple.json b/tests/qapi-schema/include-simple.json new file mode 100644 index 0000000000..1dd391a592 --- /dev/null +++ b/tests/qapi-schema/include-simple.json @@ -0,0 +1 @@ +{ 'include': 'include-simple-sub.json' } diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out new file mode 100644 index 0000000000..4ce3dcf12f --- /dev/null +++ b/tests/qapi-schema/include-simple.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] +[] diff --git a/tests/qapi-schema/include/relpath.json b/tests/qapi-schema/include/relpath.json new file mode 100644 index 0000000000..45dee24704 --- /dev/null +++ b/tests/qapi-schema/include/relpath.json @@ -0,0 +1 @@ +{ 'include': '../include-relpath-sub.json' } diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err index 9f2a35515c..d9d66b377a 100644 --- a/tests/qapi-schema/missing-colon.err +++ b/tests/qapi-schema/missing-colon.err @@ -1 +1 @@ -<stdin>:1:10: Expected ":" +tests/qapi-schema/missing-colon.json:1:10: Expected ":" diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err index 4fe0700195..e73d2770d6 100644 --- a/tests/qapi-schema/missing-comma-list.err +++ b/tests/qapi-schema/missing-comma-list.err @@ -1 +1 @@ -<stdin>:2:20: Expected "," or "]" +tests/qapi-schema/missing-comma-list.json:2:20: Expected "," or "]" diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err index b0121b5f3a..52b3a8a1ec 100644 --- a/tests/qapi-schema/missing-comma-object.err +++ b/tests/qapi-schema/missing-comma-object.err @@ -1 +1 @@ -<stdin>:2:3: Expected "," or "}" +tests/qapi-schema/missing-comma-object.json:2:3: Expected "," or "}" diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err index a6c2dc26a6..334f0c91ae 100644 --- a/tests/qapi-schema/non-objects.err +++ b/tests/qapi-schema/non-objects.err @@ -1 +1 @@ -<stdin>:1:1: Expected "{" +tests/qapi-schema/non-objects.json:1:1: Expected "{" diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err index a6c2dc26a6..9b183841dd 100644 --- a/tests/qapi-schema/quoted-structural-chars.err +++ b/tests/qapi-schema/quoted-structural-chars.err @@ -1 +1 @@ -<stdin>:1:1: Expected "{" +tests/qapi-schema/quoted-structural-chars.json:1:1: Expected "{" diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index b3d1e1dbce..634ef2d00a 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -12,15 +12,13 @@ from qapi import * from pprint import pprint +import os import sys try: - exprs = parse_schema(sys.stdin) + exprs = parse_schema(sys.argv[1]) except SystemExit: raise -except: - print >>sys.stderr, "Crashed:", sys.exc_info()[0] - exit(1) pprint(exprs) pprint(enum_types) diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err index ff839a34e9..24c24b0108 100644 --- a/tests/qapi-schema/trailing-comma-list.err +++ b/tests/qapi-schema/trailing-comma-list.err @@ -1 +1 @@ -<stdin>:2:36: Expected "{", "[" or string +tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[" or string diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err index f5409627da..30bce5e194 100644 --- a/tests/qapi-schema/trailing-comma-object.err +++ b/tests/qapi-schema/trailing-comma-object.err @@ -1 +1 @@ -<stdin>:2:38: Expected string +tests/qapi-schema/trailing-comma-object.json:2:38: Expected string diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err index 0e837a7fad..fb41a86abd 100644 --- a/tests/qapi-schema/unclosed-list.err +++ b/tests/qapi-schema/unclosed-list.err @@ -1 +1 @@ -<stdin>:1:20: Expected "," or "]" +tests/qapi-schema/unclosed-list.json:1:20: Expected "," or "]" diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err index e6dc9501dc..db3deedd63 100644 --- a/tests/qapi-schema/unclosed-object.err +++ b/tests/qapi-schema/unclosed-object.err @@ -1 +1 @@ -<stdin>:1:21: Expected "," or "}" +tests/qapi-schema/unclosed-object.json:1:21: Expected "," or "}" diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err index 948d88339d..12b187074e 100644 --- a/tests/qapi-schema/unclosed-string.err +++ b/tests/qapi-schema/unclosed-string.err @@ -1 +1 @@ -<stdin>:1:11: Missing terminating "'" +tests/qapi-schema/unclosed-string.json:1:11: Missing terminating "'" diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err index dd8e3d1b3b..938f96962b 100644 --- a/tests/qapi-schema/union-invalid-base.err +++ b/tests/qapi-schema/union-invalid-base.err @@ -1 +1 @@ -<stdin>:7: Base 'TestBaseWrong' is not a valid type +tests/qapi-schema/union-invalid-base.json:7: Base 'TestBaseWrong' is not a valid type diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031 index 1d920ea87a..5aefb88b60 100755 --- a/tests/qemu-iotests/031 +++ b/tests/qemu-iotests/031 @@ -35,6 +35,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter . ./common.pattern @@ -56,22 +57,22 @@ for IMGOPTS in "compat=0.10" "compat=1.1"; do echo === Create image with unknown header extension === echo _make_test_img 64M - ./qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension" - ./qcow2.py "$TEST_IMG" dump-header + $PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension" + $PYTHON qcow2.py "$TEST_IMG" dump-header _check_test_img echo echo === Rewrite header with no backing file === echo $QEMU_IMG rebase -u -b "" "$TEST_IMG" - ./qcow2.py "$TEST_IMG" dump-header + $PYTHON qcow2.py "$TEST_IMG" dump-header _check_test_img echo echo === Add a backing file and format === echo $QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG" - ./qcow2.py "$TEST_IMG" dump-header + $PYTHON qcow2.py "$TEST_IMG" dump-header done # success, all done diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 index 03b6aa9de7..29c35d1004 100755 --- a/tests/qemu-iotests/036 +++ b/tests/qemu-iotests/036 @@ -38,6 +38,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter . ./common.pattern @@ -53,15 +54,15 @@ IMGOPTS="compat=1.1" echo === Create image with unknown autoclear feature bit === echo _make_test_img 64M -./qcow2.py "$TEST_IMG" set-feature-bit autoclear 63 -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63 +$PYTHON qcow2.py "$TEST_IMG" dump-header echo echo === Repair image === echo _check_test_img -r all -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header # success, all done echo "*** done" diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index b9cbe99560..b7b70300fc 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -38,6 +38,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter @@ -58,7 +59,7 @@ _make_test_img $size $QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img echo @@ -73,7 +74,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io ulimit -c "$old_ulimit" # The dirty bit must be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img echo @@ -82,7 +83,7 @@ echo "== Read-only access must still work ==" $QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "== Repairing the image file must succeed ==" @@ -90,7 +91,7 @@ echo "== Repairing the image file must succeed ==" _check_test_img -r all # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "== Data should still be accessible after repair ==" @@ -109,12 +110,12 @@ $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io ulimit -c "$old_ulimit" # The dirty bit must be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "== Creating an image file with lazy_refcounts=off ==" @@ -128,7 +129,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io ulimit -c "$old_ulimit" # The dirty bit must not be set since lazy_refcounts=off -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img echo @@ -144,8 +145,8 @@ $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG commit "$TEST_IMG" # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features -./qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features _check_test_img TEST_IMG="$TEST_IMG".base _check_test_img diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 073dc7a2d3..c4af131a66 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -233,6 +233,10 @@ echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG", $QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io +echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io + +$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 01b0384472..31e329e893 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -358,4 +358,14 @@ wrote 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054 index c8b7082b4e..a5ebf99450 100755 --- a/tests/qemu-iotests/054 +++ b/tests/qemu-iotests/054 @@ -35,6 +35,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter @@ -49,7 +50,7 @@ _make_test_img $((1024*1024))T echo echo "creating too large image (1 EB) using qcow2.py" _make_test_img 4G -./qcow2.py "$TEST_IMG" set-header size $((1024 ** 6)) +$PYTHON qcow2.py "$TEST_IMG" set-header size $((1024 ** 6)) _check_test_img # success, all done diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index ca5aa16ff7..26a2fd3e0e 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -104,6 +104,13 @@ truncate -s 10M $TEST_IMG _img_info echo +echo "=== Converting to streamOptimized from image with small cluster size===" +TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G +$QEMU_IO -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IO -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1 + +echo echo "=== Testing version 3 ===" _use_sample_img iotest-version3.vmdk.bz2 _img_info diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 3371c867bb..eba0dedda0 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -2046,10 +2046,18 @@ RW 12582912 VMFS "dummy.IMGFMT" 1 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes +=== Converting to streamOptimized from image with small cluster size=== +Formatting 'TEST_DIR/t.vmdk.IMGFMT', fmt=IMGFMT size=1073741824 +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 10240 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + === Testing version 3 === image: TEST_DIR/iotest-version3.IMGFMT file format: IMGFMT virtual size: 1.0G (1073741824 bytes) +cluster_size: 65536 === Testing 4TB monolithicFlat creation and IO === Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index f0116aab1d..5447b27a1a 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -35,6 +35,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter @@ -68,13 +69,13 @@ poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00" _check_test_img # The corrupt bit should not be set anyway -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Try to write something, thereby forcing the corrupt bit to be set $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io # The corrupt bit must now be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Try to open the image R/W (which should fail) $QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \ @@ -99,19 +100,19 @@ poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01" # Redirect new data cluster onto refcount block poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00" _check_test_img -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Try to fix it _check_test_img -r all # The corrupt bit should be cleared -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Look if it's really really fixed $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "=== Testing cluster data reference into inactive L2 table ===" @@ -124,13 +125,13 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \ "\x80\x00\x00\x00\x00\x04\x00\x00" _check_test_img -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img -r all -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Check data $QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index d3a6b388b5..0de789734f 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -35,6 +35,7 @@ _cleanup() trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter @@ -48,9 +49,9 @@ echo "=== Testing version downgrade with zero expansion ===" echo IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M $QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img @@ -59,9 +60,9 @@ echo "=== Testing dirty version downgrade ===" echo IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M $QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img @@ -69,11 +70,11 @@ echo echo "=== Testing version downgrade with unknown compat/autoclear flags ===" echo IMGOPTS="compat=1.1" _make_test_img 64M -./qcow2.py "$TEST_IMG" set-feature-bit compatible 42 -./qcow2.py "$TEST_IMG" set-feature-bit autoclear 42 -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42 +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42 +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header _check_test_img echo @@ -81,9 +82,9 @@ echo "=== Testing version upgrade and resize ===" echo IMGOPTS="compat=0.10" _make_test_img 64M $QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io _check_test_img @@ -92,9 +93,9 @@ echo "=== Testing dirty lazy_refcounts=off ===" echo IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M $QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 index ab5445f62d..e89b61d70b 100755 --- a/tests/qemu-iotests/065 +++ b/tests/qemu-iotests/065 @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # # Test for additional information emitted by qemu-img info on qcow2 # images diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 index f764534782..6a52c96bba 100755 --- a/tests/qemu-iotests/083 +++ b/tests/qemu-iotests/083 @@ -29,6 +29,7 @@ tmp=/tmp/$$ status=1 # failure is the default! # get standard environment, filters and checks +. ./common.env . ./common.rc . ./common.filter @@ -81,7 +82,7 @@ EOF nbd_url="nbd:127.0.0.1:$port:exportname=foo" fi - ./nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & + $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & wait_for_tcp_port "127.0.0.1:$port" $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | filter_nbd diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 index 33c8dc410a..56cd6f89b7 100755 --- a/tests/qemu-iotests/085 +++ b/tests/qemu-iotests/085 @@ -30,10 +30,6 @@ echo "QA output created by $seq" here=`pwd` status=1 # failure is the default! -qemu_pid= - -QMP_IN="${TEST_DIR}/qmp-in-$$" -QMP_OUT="${TEST_DIR}/qmp-out-$$" snapshot_virt0="snapshot-v0.qcow2" snapshot_virt1="snapshot-v1.qcow2" @@ -42,10 +38,7 @@ MAX_SNAPSHOTS=10 _cleanup() { - kill -KILL ${qemu_pid} - wait ${qemu_pid} 2>/dev/null # silent kill - - rm -f "${QMP_IN}" "${QMP_OUT}" + _cleanup_qemu for i in $(seq 1 ${MAX_SNAPSHOTS}) do rm -f "${TEST_DIR}/${i}-${snapshot_virt0}" @@ -59,43 +52,12 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks . ./common.rc . ./common.filter +. ./common.qemu _supported_fmt qcow2 _supported_proto file _supported_os Linux -# Wait for expected QMP response from QEMU. Will time out -# after 10 seconds, which counts as failure. -# -# $1 is the string to expect -# -# If $silent is set to anything but an empty string, then -# response is not echoed out. -function timed_wait_for() -{ - while read -t 10 resp <&5 - do - if [ "${silent}" == "" ]; then - echo "${resp}" | _filter_testdir | _filter_qemu - fi - grep -q "${1}" < <(echo ${resp}) - if [ $? -eq 0 ]; then - return - fi - done - echo "Timeout waiting for ${1}" - exit 1 # Timeout means the test failed -} - -# Sends QMP command to QEMU, and waits for the expected response -# -# ${1}: String of the QMP command to send -# ${2}: String that the QEMU response should contain -function send_qmp_cmd() -{ - echo "${1}" >&6 - timed_wait_for "${2}" -} # ${1}: unique identifier for the snapshot filename function create_single_snapshot() @@ -104,7 +66,7 @@ function create_single_snapshot() 'arguments': { 'device': 'virtio0', 'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"', 'format': 'qcow2' } }" - send_qmp_cmd "${cmd}" "return" + _send_qemu_cmd $h "${cmd}" "return" } # ${1}: unique identifier for the snapshot filename @@ -120,14 +82,11 @@ function create_group_snapshot() 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ] } }" - send_qmp_cmd "${cmd}" "return" + _send_qemu_cmd $h "${cmd}" "return" } size=128M -mkfifo "${QMP_IN}" -mkfifo "${QMP_OUT}" - _make_test_img $size mv "${TEST_IMG}" "${TEST_IMG}.orig" _make_test_img $size @@ -136,23 +95,15 @@ echo echo === Running QEMU === echo -"${QEMU}" -nographic -monitor none -serial none -qmp stdio\ - -drive file="${TEST_IMG}.orig",if=virtio\ - -drive file="${TEST_IMG}",if=virtio 2>&1 >"${QMP_OUT}" <"${QMP_IN}"& -qemu_pid=$! - -# redirect fifos to file descriptors, to keep from blocking -exec 5<"${QMP_OUT}" -exec 6>"${QMP_IN}" - -# Don't print response, since it has version information in it -silent=yes timed_wait_for "capabilities" +qemu_comm_method="qmp" +_launch_qemu -drive file="${TEST_IMG}.orig",if=virtio -drive file="${TEST_IMG}",if=virtio +h=$QEMU_HANDLE echo echo === Sending capabilities === echo -send_qmp_cmd "{ 'execute': 'qmp_capabilities' }" "return" +_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" echo echo === Create a single snapshot on virtio0 === @@ -165,16 +116,16 @@ echo echo === Invalid command - missing device and nodename === echo -send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync', - 'arguments': { 'snapshot-file':'"${TEST_DIR}"/1-${snapshot_virt0}', +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'snapshot-file':'"${TEST_DIR}/1-${snapshot_virt0}"', 'format': 'qcow2' } }" "error" echo echo === Invalid command - missing snapshot-file === echo -send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync', - 'arguments': { 'device': 'virtio0', +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'device': 'virtio0', 'format': 'qcow2' } }" "error" echo echo diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 new file mode 100755 index 0000000000..384b3ace54 --- /dev/null +++ b/tests/qemu-iotests/091 @@ -0,0 +1,105 @@ +#!/bin/bash +# +# Live migration test +# +# Performs a migration from one VM to another via monitor commands +# +# Copyright (C) 2014 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=jcody@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +MIG_FIFO="${TEST_DIR}/migrate" + +_cleanup() +{ + rm -f "${MIG_FIFO}" + _cleanup_qemu + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +size=1G + +_make_test_img $size + +mkfifo "${MIG_FIFO}" + +echo +echo === Starting QEMU VM1 === +echo + +qemu_comm_method="monitor" +_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk +h1=$QEMU_HANDLE + +echo +echo === Starting QEMU VM2 === +echo +_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk \ + -incoming "exec: cat '${MIG_FIFO}'" +h2=$QEMU_HANDLE + +echo +echo === VM 1: Migrate from VM1 to VM2 === +echo + +silent=yes +_send_qemu_cmd $h1 'qemu-io disk "write -P 0x22 0 4M"' "(qemu)" +echo "vm1: qemu-io disk write complete" +_send_qemu_cmd $h1 "migrate \"exec: cat > '${MIG_FIFO}'\"" "(qemu)" +echo "vm1: live migration started" +qemu_cmd_repeat=20 _send_qemu_cmd $h1 "info migrate" "completed" +echo "vm1: live migration completed" + +echo +echo === VM 2: Post-migration, write to disk, verify running === +echo + +_send_qemu_cmd $h2 'qemu-io disk "write 4M 1M"' "(qemu)" +echo "vm2: qemu-io disk write complete" +qemu_cmd_repeat=20 _send_qemu_cmd $h2 "info status" "running" +echo "vm2: qemu process running successfully" + +echo "vm2: flush io, and quit" +_send_qemu_cmd $h2 'qemu-io disk flush' "(qemu)" +_send_qemu_cmd $h2 'quit' "" + +echo "Check image pattern" +${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io + +echo "Running 'qemu-img check -r all \$TEST_IMG'" +"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu + +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/091.out b/tests/qemu-iotests/091.out new file mode 100644 index 0000000000..a2e0122966 --- /dev/null +++ b/tests/qemu-iotests/091.out @@ -0,0 +1,28 @@ +QA output created by 091 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + +=== Starting QEMU VM1 === + + +=== Starting QEMU VM2 === + + +=== VM 1: Migrate from VM1 to VM2 === + +vm1: qemu-io disk write complete +vm1: live migration started +vm1: live migration completed + +=== VM 2: Post-migration, write to disk, verify running === + +vm2: qemu-io disk write complete +vm2: qemu process running successfully +vm2: flush io, and quit +Check image pattern +read 4194304/4194304 bytes at offset 0 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Running 'qemu-img check -r all $TEST_IMG' +No errors were found on the image. +80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters +Image end offset: 5570560 +*** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index e2ed5a95f8..ca2ee43d3b 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -34,6 +34,13 @@ timestamp=${TIMESTAMP:=false} # generic initialization iam=check +# we need common.env +if ! . ./common.env +then + echo "$iam: failed to source common.env" + exit 1 +fi + # we need common.config if ! . ./common.config then @@ -215,9 +222,16 @@ do start=`_wallclock` $timestamp && echo -n " ["`date "+%T"`"]" - [ ! -x $seq ] && chmod u+x $seq # ensure we can run it + + if [ "$(head -n 1 $seq)" == "#!/usr/bin/env python" ]; then + run_command="$PYTHON $seq" + else + [ ! -x $seq ] && chmod u+x $seq # ensure we can run it + run_command="./$seq" + fi + MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \ - ./$seq >$tmp.out 2>&1 + $run_command >$tmp.out 2>&1 sts=$? $timestamp && _timestamp stop=`_wallclock` diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu new file mode 100644 index 0000000000..918af3102c --- /dev/null +++ b/tests/qemu-iotests/common.qemu @@ -0,0 +1,200 @@ +#!/bin/bash +# +# This allows for launching of multiple QEMU instances, with independent +# communication possible to each instance. +# +# Each instance can choose, at launch, to use either the QMP or the +# HMP (monitor) interface. +# +# All instances are cleaned up via _cleanup_qemu, including killing the +# running qemu instance. +# +# Copyright (C) 2014 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/>. +# + +QEMU_COMM_TIMEOUT=10 + +QEMU_FIFO_IN="${TEST_DIR}/qmp-in-$$" +QEMU_FIFO_OUT="${TEST_DIR}/qmp-out-$$" + +QEMU_PID= +_QEMU_HANDLE=0 +QEMU_HANDLE=0 + +# If bash version is >= 4.1, these will be overwritten and dynamic +# file descriptor values assigned. +_out_fd=3 +_in_fd=4 + +# Wait for expected QMP response from QEMU. Will time out +# after 10 seconds, which counts as failure. +# +# Override QEMU_COMM_TIMEOUT for a timeout different than the +# default 10 seconds +# +# $1: The handle to use +# $2+ All remaining arguments comprise the string to search for +# in the response. +# +# If $silent is set to anything but an empty string, then +# response is not echoed out. +function _timed_wait_for() +{ + local h=${1} + shift + + QEMU_STATUS[$h]=0 + while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} + do + if [ -z "${silent}" ]; then + echo "${resp}" | _filter_testdir | _filter_qemu \ + | _filter_qemu_io | _filter_qmp + fi + grep -q "${*}" < <(echo ${resp}) + if [ $? -eq 0 ]; then + return + fi + done + QEMU_STATUS[$h]=-1 + if [ -z "${qemu_error_no_exit}" ]; then + echo "Timeout waiting for ${*} on handle ${h}" + exit 1 # Timeout means the test failed + fi +} + + +# Sends QMP or HMP command to QEMU, and waits for the expected response +# +# $1: QEMU handle to use +# $2: String of the QMP command to send +# ${@: -1} (Last string passed) +# String that the QEMU response should contain. If it is a null +# string, do not wait for a response +# +# Set qemu_cmd_repeat to the number of times to repeat the cmd +# until either timeout, or a response. If it is not set, or <=0, +# then the command is only sent once. +# +# If $qemu_error_no_exit is set, then even if the expected response +# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in +# that case. +function _send_qemu_cmd() +{ + local h=${1} + local count=1 + local cmd= + local use_error=${qemu_error_no_exit} + shift + + if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then + count=${qemu_cmd_repeat} + use_error="no" + fi + # This array element extraction is done to accomodate pathnames with spaces + cmd=${@: 1:${#@}-1} + shift $(($# - 1)) + + while [ ${count} -gt 0 ] + do + echo "${cmd}" >&${QEMU_IN[${h}]} + if [ -n "${1}" ]; then + qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" + if [ ${QEMU_STATUS[$h]} -eq 0 ]; then + return + fi + fi + let count--; + done + if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then + echo "Timeout waiting for ${1} on handle ${h}" + exit 1 #Timeout means the test failed + fi +} + + +# Launch a QEMU process. +# +# Input parameters: +# $qemu_comm_method: set this variable to 'monitor' (case insensitive) +# to use the QEMU HMP monitor for communication. +# Otherwise, the default of QMP is used. +# Returns: +# $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. +# +function _launch_qemu() +{ + local comm= + local fifo_out= + local fifo_in= + + if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) + then + comm="-monitor stdio" + else + local qemu_comm_method="qmp" + comm="-monitor none -qmp stdio" + fi + + fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} + fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} + mkfifo "${fifo_out}" + mkfifo "${fifo_in}" + + "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" 2>&1 \ + >"${fifo_out}" \ + <"${fifo_in}" & + QEMU_PID[${_QEMU_HANDLE}]=$! + + if [[ "${BASH_VERSINFO[0]}" -ge "5" || + ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] + then + # bash >= 4.1 required for automatic fd + exec {_out_fd}<"${fifo_out}" + exec {_in_fd}>"${fifo_in}" + else + let _out_fd++ + let _in_fd++ + eval "exec ${_out_fd}<'${fifo_out}'" + eval "exec ${_in_fd}>'${fifo_in}'" + fi + + QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} + QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} + QEMU_STATUS[${_QEMU_HANDLE}]=0 + + if [ "${qemu_comm_method}" == "qmp" ] + then + # Don't print response, since it has version information in it + silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" + fi + QEMU_HANDLE=${_QEMU_HANDLE} + let _QEMU_HANDLE++ +} + + +# Silenty kills the QEMU process +function _cleanup_qemu() +{ + # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices + for i in "${!QEMU_OUT[@]}" + do + kill -KILL ${QEMU_PID[$i]} 2>/dev/null + wait ${QEMU_PID[$i]} 2>/dev/null # silent kill + rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" + eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors + eval "exec ${QEMU_OUT[$i]}<&-" + done +} diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ae096638b8..cd3e4d2c27 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -96,3 +96,4 @@ 087 rw auto 088 rw auto 090 rw auto quick +091 rw auto diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index f03353b755..449d285e56 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -86,13 +86,13 @@ static void test_validate_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(!errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(!err); g_free(p->string); g_free(p); } @@ -101,13 +101,13 @@ static void test_validate_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefNested *udp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}"); - visit_type_UserDefNested(v, &udp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefNested(v, &udp, NULL, &err); + g_assert(!err); qapi_free_UserDefNested(udp); } @@ -115,13 +115,13 @@ static void test_validate_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *head = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &errp); - g_assert(!errp); + visit_type_UserDefOneList(v, &head, NULL, &err); + g_assert(!err); qapi_free_UserDefOneList(head); } @@ -130,12 +130,12 @@ static void test_validate_union(TestInputVisitorData *data, { UserDefUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "{ 'type': 'b', 'integer': 41, 'data' : { 'integer': 42 } }"); - visit_type_UserDefUnion(v, &tmp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefUnion(v, &tmp, NULL, &err); + g_assert(!err); qapi_free_UserDefUnion(tmp); } @@ -144,7 +144,7 @@ static void test_validate_union_flat(TestInputVisitorData *data, { UserDefFlatUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "{ 'enum1': 'value1', " @@ -152,8 +152,8 @@ static void test_validate_union_flat(TestInputVisitorData *data, "'boolean': true }"); /* TODO when generator bug is fixed, add 'integer': 41 */ - visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); + g_assert(!err); qapi_free_UserDefFlatUnion(tmp); } @@ -162,12 +162,12 @@ static void test_validate_union_anon(TestInputVisitorData *data, { UserDefAnonUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "42"); - visit_type_UserDefAnonUnion(v, &tmp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefAnonUnion(v, &tmp, NULL, &err); + g_assert(!err); qapi_free_UserDefAnonUnion(tmp); } @@ -175,13 +175,13 @@ static void test_validate_fail_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(err); if (p) { g_free(p->string); } @@ -192,13 +192,13 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefNested *udp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}"); - visit_type_UserDefNested(v, &udp, NULL, &errp); - g_assert(errp); + visit_type_UserDefNested(v, &udp, NULL, &err); + g_assert(err); qapi_free_UserDefNested(udp); } @@ -206,13 +206,13 @@ static void test_validate_fail_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *head = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]"); - visit_type_UserDefOneList(v, &head, NULL, &errp); - g_assert(errp); + visit_type_UserDefOneList(v, &head, NULL, &err); + g_assert(err); qapi_free_UserDefOneList(head); } @@ -220,13 +220,13 @@ static void test_validate_fail_union(TestInputVisitorData *data, const void *unused) { UserDefUnion *tmp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }"); - visit_type_UserDefUnion(v, &tmp, NULL, &errp); - g_assert(errp); + visit_type_UserDefUnion(v, &tmp, NULL, &err); + g_assert(err); qapi_free_UserDefUnion(tmp); } @@ -234,13 +234,13 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data, const void *unused) { UserDefFlatUnion *tmp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }"); - visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp); - g_assert(errp); + visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); + g_assert(err); qapi_free_UserDefFlatUnion(tmp); } @@ -249,12 +249,12 @@ static void test_validate_fail_union_anon(TestInputVisitorData *data, { UserDefAnonUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "3.14"); - visit_type_UserDefAnonUnion(v, &tmp, NULL, &errp); - g_assert(errp); + visit_type_UserDefAnonUnion(v, &tmp, NULL, &err); + g_assert(err); qapi_free_UserDefAnonUnion(tmp); } diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index 1729667a6f..a58a3e6fdb 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -90,13 +90,13 @@ static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { int64_t res = 0, value = -42; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%" PRId64, value); - visit_type_int(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_int(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, value); } @@ -104,7 +104,7 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, const void *unused) { int64_t res = 0; - Error *errp = NULL; + Error *err = NULL; Visitor *v; /* this will overflow a Qint/int64, so should be deserialized into @@ -113,22 +113,22 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, */ v = visitor_input_test_init(data, "%f", DBL_MAX); - visit_type_int(v, &res, NULL, &errp); - g_assert(errp); - error_free(errp); + visit_type_int(v, &res, NULL, &err); + g_assert(err); + error_free(err); } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); } @@ -136,13 +136,13 @@ static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { double res = 0, value = 3.14; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%f", value); - visit_type_number(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_number(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpfloat(res, ==, value); } @@ -150,13 +150,13 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%s", value); - visit_type_str(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_str(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpstr(res, ==, value); g_free(res); @@ -165,7 +165,7 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; Visitor *v; EnumOne i; @@ -174,8 +174,8 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_EnumOne(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(i, ==, res); visitor_input_teardown(data, NULL); @@ -196,34 +196,33 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { Error *err = NULL; - if (!error_is_set(errp)) { - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (!err) { - visit_type_int(v, &(*obj)->integer, "integer", &err); - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - visit_type_str(v, &(*obj)->string, "string", &err); - - /* Always call end_struct if start_struct succeeded. */ - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); - } + + visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), + &err); + if (!err) { + visit_type_int(v, &(*obj)->integer, "integer", &err); + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + visit_type_str(v, &(*obj)->string, "string", &err); + + /* Always call end_struct if start_struct succeeded. */ error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); } + error_propagate(errp, err); } static void test_visitor_in_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(!errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(!err); g_assert_cmpint(p->integer, ==, -42); g_assert(p->boolean == true); g_assert_cmpstr(p->string, ==, "foo"); @@ -242,13 +241,13 @@ static void test_visitor_in_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefNested *udp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}"); - visit_type_UserDefNested(v, &udp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefNested(v, &udp, NULL, &err); + g_assert(!err); check_and_free_str(udp->string0, "string0"); check_and_free_str(udp->dict1.string1, "string1"); @@ -265,14 +264,14 @@ static void test_visitor_in_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *item, *head = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; int i; v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &errp); - g_assert(!errp); + visit_type_UserDefOneList(v, &head, NULL, &err); + g_assert(!err); g_assert(head != NULL); for (i = 0, item = head; item; item = item->next, i++) { @@ -634,16 +633,16 @@ static void test_visitor_in_errors(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(err); g_assert(p->string == NULL); - error_free(errp); + error_free(err); g_free(p->string); g_free(p); } diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index da279713f2..2580f3debf 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -45,11 +45,11 @@ static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { int64_t value = -42; - Error *errp = NULL; + Error *err = NULL; QObject *obj; - visit_type_int(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_int(data->ov, &value, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -62,12 +62,12 @@ static void test_visitor_out_int(TestOutputVisitorData *data, static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool value = true; QObject *obj; - visit_type_bool(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_bool(data->ov, &value, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -81,11 +81,11 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *errp = NULL; + Error *err = NULL; QObject *obj; - visit_type_number(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_number(data->ov, &value, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -99,11 +99,11 @@ static void test_visitor_out_string(TestOutputVisitorData *data, const void *unused) { char *string = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; QObject *obj; - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -117,12 +117,12 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, const void *unused) { char *string = NULL; - Error *errp = NULL; + Error *err = NULL; QObject *obj; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -135,13 +135,13 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, static void test_visitor_out_enum(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; QObject *obj; EnumOne i; for (i = 0; i < ENUM_ONE_MAX; i++) { - visit_type_EnumOne(data->ov, &i, "unused", &errp); - g_assert(!errp); + visit_type_EnumOne(data->ov, &i, "unused", &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -156,13 +156,13 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data, const void *unused) { EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; - Error *errp; + Error *err; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - errp = NULL; - visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp); - g_assert(errp); - error_free(errp); + err = NULL; + visit_type_EnumOne(data->ov, &bad_values[i], "unused", &err); + g_assert(err); + error_free(err); } } @@ -193,12 +193,12 @@ static void test_visitor_out_struct(TestOutputVisitorData *data, .boolean = false, .string = (char *) "foo"}; TestStruct *p = &test_struct; - Error *errp = NULL; + Error *err = NULL; QObject *obj; QDict *qdict; - visit_type_TestStruct(data->ov, &p, NULL, &errp); - g_assert(!errp); + visit_type_TestStruct(data->ov, &p, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -217,7 +217,7 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, const void *unused) { int64_t value = 42; - Error *errp = NULL; + Error *err = NULL; UserDefNested *ud2; QObject *obj; QDict *qdict, *dict1, *dict2, *dict3, *userdef; @@ -242,8 +242,8 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, ud2->dict1.dict3.userdef2->base->integer = value; ud2->dict1.dict3.string3 = g_strdup(strings[3]); - visit_type_UserDefNested(data->ov, &ud2, "unused", &errp); - g_assert(!errp); + visit_type_UserDefNested(data->ov, &ud2, "unused", &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -283,16 +283,16 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data, EnumOne bad_values[] = { ENUM_ONE_MAX, -1 }; UserDefZero b; UserDefOne u = { .base = &b }, *pu = &u; - Error *errp; + Error *err; int i; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - errp = NULL; + err = NULL; u.has_enum1 = true; u.enum1 = bad_values[i]; - visit_type_UserDefOne(data->ov, &pu, "unused", &errp); - g_assert(errp); - error_free(errp); + visit_type_UserDefOne(data->ov, &pu, "unused", &err); + g_assert(err); + error_free(err); } } @@ -328,7 +328,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, const int max_items = 10; bool value_bool = true; int value_int = 10; - Error *errp = NULL; + Error *err = NULL; QListEntry *entry; QObject *obj; QList *qlist; @@ -345,8 +345,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data, head = p; } - visit_type_TestStructList(data->ov, &head, NULL, &errp); - g_assert(!errp); + visit_type_TestStructList(data->ov, &head, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index d406263aee..877e737714 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -54,62 +54,62 @@ static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { int64_t res = 0, value = -42; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "-42"); - visit_type_int(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_int(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, value); } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "yes"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "on"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "false"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, false); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "no"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, false); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "off"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, false); } @@ -117,13 +117,13 @@ static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { double res = 0, value = 3.14; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "3.14"); - visit_type_number(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_number(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpfloat(res, ==, value); } @@ -131,13 +131,13 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, value); - visit_type_str(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_str(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpstr(res, ==, value); g_free(res); @@ -146,7 +146,7 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; Visitor *v; EnumOne i; @@ -155,8 +155,8 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_EnumOne(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(i, ==, res); visitor_input_teardown(data, NULL); diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 22363d100f..2af5a21ab5 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -45,11 +45,11 @@ static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { int64_t value = -42; - Error *errp = NULL; + Error *err = NULL; char *str; - visit_type_int(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_int(data->ov, &value, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -60,12 +60,12 @@ static void test_visitor_out_int(TestOutputVisitorData *data, static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool value = true; char *str; - visit_type_bool(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_bool(data->ov, &value, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -77,11 +77,11 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *errp = NULL; + Error *err = NULL; char *str; - visit_type_number(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_number(data->ov, &value, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -93,11 +93,11 @@ static void test_visitor_out_string(TestOutputVisitorData *data, const void *unused) { char *string = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; char *str; - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -109,12 +109,12 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, const void *unused) { char *string = NULL; - Error *errp = NULL; + Error *err = NULL; char *str; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -125,13 +125,13 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, static void test_visitor_out_enum(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; char *str; EnumOne i; for (i = 0; i < ENUM_ONE_MAX; i++) { - visit_type_EnumOne(data->ov, &i, "unused", &errp); - g_assert(!errp); + visit_type_EnumOne(data->ov, &i, "unused", &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -144,13 +144,13 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data, const void *unused) { EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; - Error *errp; + Error *err; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - errp = NULL; - visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp); - g_assert(errp); - error_free(errp); + err = NULL; + visit_type_EnumOne(data->ov, &bad_values[i], "unused", &err); + g_assert(err); + error_free(err); } } diff --git a/trace/Makefile.objs b/trace/Makefile.objs index d321946d38..6a30467096 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -31,7 +31,7 @@ $(obj)/generated-events.h: $(obj)/generated-events.h-timestamp $(obj)/generated-events.h-timestamp: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=events-h \ - --backend=events \ + --backend=$(TRACE_BACKEND) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) @@ -39,7 +39,7 @@ $(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/conf $(obj)/generated-events.c-timestamp: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=events-c \ - --backend=events \ + --backend=$(TRACE_BACKEND) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) diff --git a/trace/simple.c b/trace/simple.c index aaa010ee2b..bb0b52ce02 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -28,7 +28,7 @@ #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL /** Trace file version number, bump if format changes */ -#define HEADER_VERSION 2 +#define HEADER_VERSION 3 /** Records were dropped event ID */ #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) diff --git a/util/cutils.c b/util/cutils.c index b337293239..dbe7412bd8 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -24,6 +24,8 @@ #include "qemu-common.h" #include "qemu/host-utils.h" #include <math.h> +#include <limits.h> +#include <errno.h> #include "qemu/sockets.h" #include "qemu/iov.h" @@ -457,11 +459,16 @@ int parse_uint_full(const char *s, unsigned long long *value, int base) int qemu_parse_fd(const char *param) { - int fd; - char *endptr = NULL; + long fd; + char *endptr; + errno = 0; fd = strtol(param, &endptr, 10); - if (*endptr || (fd == 0 && param == endptr)) { + if (param == endptr /* no conversion performed */ || + errno != 0 /* not representable as long; possibly others */ || + *endptr != '\0' /* final string not empty */ || + fd < 0 /* invalid as file descriptor */ || + fd > INT_MAX /* not representable as int */) { return -1; } return fd; diff --git a/util/error.c b/util/error.c index 2bb42e1c4b..66245ccd1f 100644 --- a/util/error.c +++ b/util/error.c @@ -165,13 +165,13 @@ void error_free(Error *err) } } -void error_propagate(Error **dst_err, Error *local_err) +void error_propagate(Error **dst_errp, Error *local_err) { - if (local_err && dst_err == &error_abort) { + if (local_err && dst_errp == &error_abort) { error_report("%s", error_get_pretty(local_err)); abort(); - } else if (dst_err && !*dst_err) { - *dst_err = local_err; + } else if (dst_errp && !*dst_errp) { + *dst_errp = local_err; } else if (local_err) { error_free(local_err); } diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 93f7d351d3..69552f7ec3 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -238,3 +238,115 @@ char *qemu_get_exec_dir(void) { return g_strdup(exec_dir); } + +/* + * g_poll has a problem on Windows when using + * timeouts < 10ms, in glib/gpoll.c: + * + * // If not, and we have a significant timeout, poll again with + * // timeout then. Note that this will return indication for only + * // one event, or only for messages. We ignore timeouts less than + * // ten milliseconds as they are mostly pointless on Windows, the + * // MsgWaitForMultipleObjectsEx() call will timeout right away + * // anyway. + * + * if (retval == 0 && (timeout == INFINITE || timeout >= 10)) + * retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); + * + * So whenever g_poll is called with timeout < 10ms it does + * a quick poll instead of wait, this causes significant performance + * degradation of QEMU, thus we should use WaitForMultipleObjectsEx + * directly + */ +gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout) +{ + guint i; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + gint nhandles = 0; + int num_completed = 0; + + for (i = 0; i < nfds; i++) { + gint j; + + if (fds[i].fd <= 0) { + continue; + } + + /* don't add same handle several times + */ + for (j = 0; j < nhandles; j++) { + if (handles[j] == (HANDLE)fds[i].fd) { + break; + } + } + + if (j == nhandles) { + if (nhandles == MAXIMUM_WAIT_OBJECTS) { + fprintf(stderr, "Too many handles to wait for!\n"); + break; + } else { + handles[nhandles++] = (HANDLE)fds[i].fd; + } + } + } + + for (i = 0; i < nfds; ++i) { + fds[i].revents = 0; + } + + if (timeout == -1) { + timeout = INFINITE; + } + + if (nhandles == 0) { + if (timeout == INFINITE) { + return -1; + } else { + SleepEx(timeout, TRUE); + return 0; + } + } + + while (1) { + DWORD res; + gint j; + + res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, + timeout, TRUE); + + if (res == WAIT_FAILED) { + for (i = 0; i < nfds; ++i) { + fds[i].revents = 0; + } + + return -1; + } else if ((res == WAIT_TIMEOUT) || (res == WAIT_IO_COMPLETION) || + ((int)res < (int)WAIT_OBJECT_0) || + (res >= (WAIT_OBJECT_0 + nhandles))) { + break; + } + + for (i = 0; i < nfds; ++i) { + if (handles[res - WAIT_OBJECT_0] == (HANDLE)fds[i].fd) { + fds[i].revents = fds[i].events; + } + } + + ++num_completed; + + if (nhandles <= 1) { + break; + } + + /* poll the rest of the handles + */ + for (j = res - WAIT_OBJECT_0 + 1; j < nhandles; j++) { + handles[j - 1] = handles[j]; + } + --nhandles; + + timeout = 0; + } + + return num_completed; +} diff --git a/util/qemu-option.c b/util/qemu-option.c index 8bbc3ad4a3..324e4c59f7 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -1036,7 +1036,7 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) const char *value; int n; - if (!strcmp(key, "id") || error_is_set(state->errp)) { + if (!strcmp(key, "id") || *state->errp) { return; } @@ -3024,7 +3024,6 @@ int main(int argc, char **argv, char **envp) runstate_init(); - init_clocks(); rtc_clock = QEMU_CLOCK_HOST; qemu_init_auxval(envp); |