diff options
197 files changed, 4348 insertions, 1749 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 9bd2b8f678..314411332c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -255,6 +255,12 @@ L: xen-devel@lists.xensource.com S: Supported F: xen-* F: */xen* +F: hw/char/xen_console.c +F: hw/display/xenfb.c +F: hw/net/xen_nic.c +F: hw/xen/ +F: hw/xenpv/ +F: include/hw/xen/ Hosts: ------ @@ -286,6 +292,36 @@ F: hw/*/allwinner* F: include/hw/*/allwinner* F: hw/arm/cubieboard.c +ARM PrimeCell +M: Peter Maydell <peter.maydell@linaro.org> +S: Maintained +F: hw/char/pl011.c +F: hw/display/pl110* +F: hw/dma/pl080.c +F: hw/dma/pl330.c +F: hw/gpio/pl061.c +F: hw/input/pl050.c +F: hw/intc/pl190.c +F: hw/sd/pl181.c +F: hw/timer/pl031.c +F: include/hw/arm/primecell.h + +ARM cores +M: Peter Maydell <peter.maydell@linaro.org> +S: Maintained +F: hw/intc/arm* +F: hw/intc/gic_internal.h +F: hw/misc/a9scu.c +F: hw/misc/arm11scu.c +F: hw/timer/a9gtimer* +F: hw/timer/arm_* +F: include/hw/arm/arm.h +F: include/hw/intc/arm* +F: include/hw/misc/a9scu.h +F: include/hw/misc/arm11scu.h +F: include/hw/timer/a9gtimer.h +F: include/hw/timer/arm_mptimer.h + Exynos M: Evgeny Voevodin <e.voevodin@samsung.com> M: Maksim Kozlov <m.kozlov@samsung.com> @@ -322,11 +358,6 @@ M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: hw/arm/integratorcp.c -Mainstone -L: qemu-devel@nongnu.org -S: Orphan -F: hw/arm/mainstone.c - Musicpal M: Jan Kiszka <jan.kiszka@web.de> S: Maintained @@ -346,11 +377,17 @@ Real View M: Peter Maydell <peter.maydell@linaro.org> S: Maintained F: hw/arm/realview* +F: hw/intc/realview_gic.c +F: include/hw/intc/realview_gic.h -Spitz +PXA2XX M: Andrzej Zaborowski <balrogg@gmail.com> S: Maintained +F: hw/arm/mainstone.c F: hw/arm/spitz.c +F: hw/arm/tosa.c +F: hw/arm/z2.c +F: hw/*/pxa2xx* Stellaris M: Peter Maydell <peter.maydell@linaro.org> @@ -726,6 +763,8 @@ M: Scott Wood <scottwood@freescale.com> L: qemu-ppc@nongnu.org S: Supported F: hw/ppc/e500* +F: hw/pci-host/ppce500.c +F: hw/net/fsl_etsec/ Character devices M: Paolo Bonzini <pbonzini@redhat.com> @@ -1154,6 +1193,19 @@ F: crypto/ F: include/crypto/ F: tests/test-crypto-* +Coroutines +M: Stefan Hajnoczi <stefanha@redhat.com> +M: Kevin Wolf <kwolf@redhat.com> +F: util/*coroutine* +F: include/qemu/coroutine* +F: tests/test-coroutine.c + +Buffers +M: Daniel P. Berrange <berrange@redhat.com> +S: Odd fixes +F: util/buffer.c +F: include/qemu/buffer.h + Usermode Emulation ------------------ Overall @@ -298,18 +298,15 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) 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) -# we require QGA_VSS_PROVIDER files to be built alongside qemu-ga -# executable since they are shipped together, but we don't want to actually -# link against them -qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a $(QGA_VSS_PROVIDER) - $(call LINK, $(filter-out $(QGA_VSS_PROVIDER), $^)) +qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a + $(call LINK, $^) ifdef QEMU_GA_MSI_ENABLED QEMU_GA_MSI=qemu-ga-$(ARCH).msi msi: $(QEMU_GA_MSI) -$(QEMU_GA_MSI): qemu-ga.exe +$(QEMU_GA_MSI): qemu-ga.exe $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI): config-host.mak @@ -321,6 +318,11 @@ msi: @echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)" endif +ifneq ($(EXESUF),) +.PHONY: qemu-ga +qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI) +endif + clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h diff --git a/Makefile.objs b/Makefile.objs index bc43e5c1dd..ecfe03c195 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -15,10 +15,6 @@ block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ block-obj-y += qemu-io-cmds.o -block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o -block-obj-y += qemu-coroutine-sleep.o -block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o - block-obj-m = block/ ####################################################################### @@ -1,3 +1,107 @@ -Read the documentation in qemu-doc.html or on http://wiki.qemu-project.org + QEMU README + =========== -- QEMU team +QEMU is a generic and open source machine & userspace emulator and +virtualizer. + +QEMU is capable of emulating a complete machine in software without any +need for hardware virtualization support. By using dynamic translation, +it achieves very good performance. QEMU can also integrate with the Xen +and KVM hypervisors to provide emulated hardware while allowing the +hypervisor to manage the CPU. With hypervisor support, QEMU can achieve +near native performance for CPUs. When QEMU emulates CPUs directly it is +capable of running operating systems made for one machine (e.g. an ARMv7 +board) on a different machine (e.g. an x86_64 PC board). + +QEMU is also capable of providing userspace API virtualization for Linux +and BSD kernel interfaces. This allows binaries compiled against one +architecture ABI (e.g. the Linux PPC64 ABI) to be run on a host using a +different architecture ABI (e.g. the Linux x86_64 ABI). This does not +involve any hardware emulation, simply CPU and syscall emulation. + +QEMU aims to fit into a variety of use cases. It can be invoked directly +by users wishing to have full control over its behaviour and settings. +It also aims to facilitate integration into higher level management +layers, by providing a stable command line interface and monitor API. +It is commonly invoked indirectly via the libvirt library when using +open source applications such as oVirt, OpenStack and virt-manager. + +QEMU as a whole is released under the GNU General Public License, +version 2. For full licensing details, consult the LICENSE file. + + +Building +======== + +QEMU is multi-platform software intended to be buildable on all modern +Linux platforms, OS-X, Win32 (via the Mingw64 toolchain) and a variety +of other UNIX targets. The simple steps to build QEMU are: + + mkdir build + cd build + ../configure + make + +Complete details of the process for building and configuring QEMU for +all supported host platforms can be found in the qemu-tech.html file. +Additional information can also be found online via the QEMU website: + + http://qemu-project.org/Hosts/Linux + http://qemu-project.org/Hosts/W32 + + +Submitting patches +================== + +The QEMU source code is maintained under the GIT version control system. + + git clone git://git.qemu-project.org/qemu.git + +When submitting patches, the preferred approach is to use 'git +format-patch' and/or 'git send-email' to format & send the mail to the +qemu-devel@nongnu.org mailing list. All patches submitted must contain +a 'Signed-off-by' line from the author. Patches should follow the +guidelines set out in the HACKING and CODING_STYLE files. + +Additional information on submitting patches can be found online via +the QEMU website + + http://qemu-project.org/Contribute/SubmitAPatch + http://qemu-project.org/Contribute/TrivialPatches + + +Bug reporting +============= + +The QEMU project uses Launchpad as its primary upstream bug tracker. Bugs +found when running code built from QEMU git or upstream released sources +should be reported via: + + https://bugs.launchpad.net/qemu/ + +If using QEMU via an operating system vendor pre-built binary package, it +is preferable to report bugs to the vendor's own bug tracker first. If +the bug is also known to affect latest upstream code, it can also be +reported via launchpad. + +For additional information on bug reporting consult: + + http://qemu-project.org/Contribute/ReportABug + + +Contact +======= + +The QEMU community can be contacted in a number of ways, with the two +main methods being email and IRC + + - qemu-devel@nongnu.org + http://lists.nongnu.org/mailman/listinfo/qemu-devel + - #qemu on irc.oftc.net + +Information on additional methods of contacting the community can be +found online via the QEMU website: + + http://qemu-project.org/Contribute/StartHere + +-- End diff --git a/backends/baum.c b/backends/baum.c index a17f62541b..723c658ac0 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -561,7 +561,10 @@ static void baum_close(struct CharDriverState *chr) g_free(baum); } -CharDriverState *chr_baum_init(void) +static CharDriverState *chr_baum_init(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { BaumDriverState *baum; CharDriverState *chr; @@ -586,14 +589,16 @@ CharDriverState *chr_baum_init(void) baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); if (baum->brlapi_fd == -1) { - brlapi_perror("baum_init: brlapi_openConnection"); + error_setg(errp, "brlapi__openConnection: %s", + brlapi_strerror(brlapi_error_location())); goto fail_handle; } baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum); if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) { - brlapi_perror("baum_init: brlapi_getDisplaySize"); + error_setg(errp, "brlapi__getDisplaySize: %s", + brlapi_strerror(brlapi_error_location())); goto fail; } @@ -609,7 +614,8 @@ CharDriverState *chr_baum_init(void) tty = BRLAPI_TTY_DEFAULT; if (brlapi__enterTtyMode(handle, tty, NULL) == -1) { - brlapi_perror("baum_init: brlapi_enterTtyMode"); + error_setg(errp, "brlapi__enterTtyMode: %s", + brlapi_strerror(brlapi_error_location())); goto fail; } @@ -629,7 +635,8 @@ fail_handle: static void register_types(void) { - register_char_driver("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL); + register_char_driver("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL, + chr_baum_init); } type_init(register_types); diff --git a/backends/msmouse.c b/backends/msmouse.c index 0119110a40..0126fa0b13 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -63,7 +63,10 @@ static void msmouse_chr_close (struct CharDriverState *chr) g_free (chr); } -CharDriverState *qemu_chr_open_msmouse(void) +static CharDriverState *qemu_chr_open_msmouse(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { CharDriverState *chr; @@ -79,7 +82,8 @@ CharDriverState *qemu_chr_open_msmouse(void) static void register_types(void) { - register_char_driver("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL); + register_char_driver("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL, + qemu_chr_open_msmouse); } type_init(register_types); diff --git a/backends/testdev.c b/backends/testdev.c index 1429152d05..26d5c7307a 100644 --- a/backends/testdev.c +++ b/backends/testdev.c @@ -108,7 +108,10 @@ static void testdev_close(struct CharDriverState *chr) g_free(testdev); } -CharDriverState *chr_testdev_init(void) +static CharDriverState *chr_testdev_init(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { TestdevCharState *testdev; CharDriverState *chr; @@ -125,7 +128,8 @@ CharDriverState *chr_testdev_init(void) static void register_types(void) { - register_char_driver("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL); + register_char_driver("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL, + chr_testdev_init); } type_init(register_types); @@ -33,7 +33,7 @@ #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "qemu/notify.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "block/qapi.h" #include "qmp-commands.h" #include "qemu/timer.h" @@ -721,7 +721,7 @@ const BdrvChildRole child_format = { }; /* - * Returns the flags that bs->backing_hd should get, based on the given flags + * Returns the flags that bs->backing should get, based on the given flags * for the parent BDS */ static int bdrv_backing_flags(int flags) @@ -763,12 +763,15 @@ static void bdrv_assign_node_name(BlockDriverState *bs, const char *node_name, Error **errp) { - if (!node_name) { - return; - } + char *gen_node_name = NULL; - /* Check for empty string or invalid characters */ - if (!id_wellformed(node_name)) { + if (!node_name) { + node_name = gen_node_name = id_generate(ID_BLOCK); + } else if (!id_wellformed(node_name)) { + /* + * Check for empty string or invalid characters, but not if it is + * generated (generated names use characters not available to the user) + */ error_setg(errp, "Invalid node name"); return; } @@ -777,18 +780,20 @@ static void bdrv_assign_node_name(BlockDriverState *bs, if (blk_by_name(node_name)) { error_setg(errp, "node-name=%s is conflicting with a device id", node_name); - return; + goto out; } /* takes care of avoiding duplicates node names */ if (bdrv_find_node(node_name)) { error_setg(errp, "Duplicate node name"); - return; + goto out; } /* copy node name into the bs and insert it into the graph list */ pstrcpy(bs->node_name, sizeof(bs->node_name), node_name); QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list); +out: + g_free(gen_node_name); } static QemuOptsList bdrv_runtime_opts = { @@ -809,7 +814,7 @@ static QemuOptsList bdrv_runtime_opts = { * * Removes all processed options from *options. */ -static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, +static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, QDict *options, int flags, BlockDriver *drv, Error **errp) { int ret, open_flags; @@ -823,7 +828,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, assert(options != NULL && bs->options != options); if (file != NULL) { - filename = file->filename; + filename = file->bs->filename; } else { filename = qdict_get_try_str(options, "filename"); } @@ -1090,6 +1095,7 @@ static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, }; QLIST_INSERT_HEAD(&parent_bs->children, child, next); + QLIST_INSERT_HEAD(&child_bs->parents, child, next_parent); return child; } @@ -1097,50 +1103,62 @@ static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, static void bdrv_detach_child(BdrvChild *child) { QLIST_REMOVE(child, next); + QLIST_REMOVE(child, next_parent); g_free(child); } void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) { - BlockDriverState *child_bs = child->bs; + BlockDriverState *child_bs; + + if (child == NULL) { + return; + } if (child->bs->inherits_from == parent) { child->bs->inherits_from = NULL; } + child_bs = child->bs; bdrv_detach_child(child); bdrv_unref(child_bs); } +/* + * Sets the backing file link of a BDS. A new reference is created; callers + * which don't need their own reference any more must call bdrv_unref(). + */ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd) { + if (backing_hd) { + bdrv_ref(backing_hd); + } - if (bs->backing_hd) { + if (bs->backing) { assert(bs->backing_blocker); - bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker); - bdrv_detach_child(bs->backing_child); + bdrv_op_unblock_all(bs->backing->bs, bs->backing_blocker); + bdrv_unref_child(bs, bs->backing); } else if (backing_hd) { error_setg(&bs->backing_blocker, "node is used as backing hd of '%s'", bdrv_get_device_or_node_name(bs)); } - bs->backing_hd = backing_hd; if (!backing_hd) { error_free(bs->backing_blocker); bs->backing_blocker = NULL; - bs->backing_child = NULL; + bs->backing = NULL; goto out; } - bs->backing_child = bdrv_attach_child(bs, backing_hd, &child_backing); + bs->backing = bdrv_attach_child(bs, backing_hd, &child_backing); bs->open_flags &= ~BDRV_O_NO_BACKING; pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_hd->drv ? backing_hd->drv->format_name : ""); - bdrv_op_block_all(bs->backing_hd, bs->backing_blocker); + bdrv_op_block_all(backing_hd, bs->backing_blocker); /* Otherwise we won't be able to commit due to check in bdrv_commit */ - bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET, + bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET, bs->backing_blocker); out: bdrv_refresh_limits(bs, NULL); @@ -1161,7 +1179,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) BlockDriverState *backing_hd; Error *local_err = NULL; - if (bs->backing_hd != NULL) { + if (bs->backing != NULL) { QDECREF(options); goto free_exit; } @@ -1201,7 +1219,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) qdict_put(options, "driver", qstring_from_str(bs->backing_format)); } - assert(bs->backing_hd == NULL); + assert(bs->backing == NULL); ret = bdrv_open_inherit(&backing_hd, *backing_filename ? backing_filename : NULL, NULL, options, 0, bs, &child_backing, &local_err); @@ -1215,7 +1233,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) goto free_exit; } + /* Hook up the backing file link; drop our reference, bs owns the + * backing_hd reference now */ bdrv_set_backing_hd(bs, backing_hd); + bdrv_unref(backing_hd); free_exit: g_free(backing_filename); @@ -1279,40 +1300,6 @@ done: return c; } -/* - * This is a version of bdrv_open_child() that returns 0/-EINVAL instead of - * a BdrvChild object. - * - * If allow_none is true, no image will be opened if filename is false and no - * BlockdevRef is given. *pbs will remain unchanged and 0 will be returned. - * - * To conform with the behavior of bdrv_open(), *pbs has to be NULL. - */ -int bdrv_open_image(BlockDriverState **pbs, const char *filename, - QDict *options, const char *bdref_key, - BlockDriverState* parent, const BdrvChildRole *child_role, - bool allow_none, Error **errp) -{ - Error *local_err = NULL; - BdrvChild *c; - - assert(pbs); - assert(*pbs == NULL); - - c = bdrv_open_child(filename, options, bdref_key, parent, child_role, - allow_none, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return -EINVAL; - } - - if (c != NULL) { - *pbs = c->bs; - } - - return 0; -} - int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) { /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ @@ -1401,7 +1388,8 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, const BdrvChildRole *child_role, Error **errp) { int ret; - BlockDriverState *file = NULL, *bs; + BdrvChild *file = NULL; + BlockDriverState *bs; BlockDriver *drv = NULL; const char *drvname; Error *local_err = NULL; @@ -1485,11 +1473,12 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, flags = bdrv_backing_flags(flags); } - assert(file == NULL); bs->open_flags = flags; - ret = bdrv_open_image(&file, filename, options, "file", - bs, &child_file, true, &local_err); - if (ret < 0) { + + file = bdrv_open_child(filename, options, "file", bs, + &child_file, true, &local_err); + if (local_err) { + ret = -EINVAL; goto fail; } } @@ -1497,7 +1486,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, /* Image format probing */ bs->probed = !drv; if (!drv && file) { - ret = find_image_format(file, filename, &drv, &local_err); + ret = find_image_format(file->bs, filename, &drv, &local_err); if (ret < 0) { goto fail; } @@ -1520,7 +1509,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, } if (file && (bs->file != file)) { - bdrv_unref(file); + bdrv_unref_child(bs, file); file = NULL; } @@ -1537,15 +1526,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, bdrv_refresh_filename(bs); - /* For snapshot=on, create a temporary qcow2 overlay. bs points to the - * temporary snapshot afterwards. */ - if (snapshot_flags) { - ret = bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err); - if (local_err) { - goto close_and_fail; - } - } - /* Check if any unknown options were used */ if (options && (qdict_size(options) != 0)) { const QDictEntry *entry = qdict_first(options); @@ -1577,11 +1557,21 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, QDECREF(options); *pbs = bs; + + /* For snapshot=on, create a temporary qcow2 overlay. bs points to the + * temporary snapshot afterwards. */ + if (snapshot_flags) { + ret = bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err); + if (local_err) { + goto close_and_fail; + } + } + return 0; fail: if (file != NULL) { - bdrv_unref(file); + bdrv_unref_child(bs, file); } QDECREF(bs->options); QDECREF(options); @@ -1922,11 +1912,13 @@ void bdrv_close(BlockDriverState *bs) BdrvChild *child, *next; bs->drv->bdrv_close(bs); + bs->drv = NULL; - if (bs->backing_hd) { - BlockDriverState *backing_hd = bs->backing_hd; - bdrv_set_backing_hd(bs, NULL); - bdrv_unref(backing_hd); + bdrv_set_backing_hd(bs, NULL); + + if (bs->file != NULL) { + bdrv_unref_child(bs, bs->file); + bs->file = NULL; } QLIST_FOREACH_SAFE(child, &bs->children, next, next) { @@ -1940,7 +1932,6 @@ void bdrv_close(BlockDriverState *bs) g_free(bs->opaque); bs->opaque = NULL; - bs->drv = NULL; bs->copy_on_read = 0; bs->backing_file[0] = '\0'; bs->backing_format[0] = '\0'; @@ -1953,11 +1944,6 @@ void bdrv_close(BlockDriverState *bs) bs->options = NULL; QDECREF(bs->full_open_options); bs->full_open_options = NULL; - - if (bs->file != NULL) { - bdrv_unref(bs->file); - bs->file = NULL; - } } if (bs->blk) { @@ -2005,13 +1991,7 @@ void bdrv_make_anon(BlockDriverState *bs) bs->node_name[0] = '\0'; } -static void bdrv_rebind(BlockDriverState *bs) -{ - if (bs->drv && bs->drv->bdrv_rebind) { - bs->drv->bdrv_rebind(bs); - } -} - +/* Fields that need to stay with the top-level BDS */ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, BlockDriverState *bs_src) { @@ -2023,20 +2003,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest->enable_write_cache = bs_src->enable_write_cache; - /* i/o throttled req */ - bs_dest->throttle_state = bs_src->throttle_state, - bs_dest->io_limits_enabled = bs_src->io_limits_enabled; - bs_dest->pending_reqs[0] = bs_src->pending_reqs[0]; - bs_dest->pending_reqs[1] = bs_src->pending_reqs[1]; - bs_dest->throttled_reqs[0] = bs_src->throttled_reqs[0]; - bs_dest->throttled_reqs[1] = bs_src->throttled_reqs[1]; - memcpy(&bs_dest->round_robin, - &bs_src->round_robin, - sizeof(bs_dest->round_robin)); - memcpy(&bs_dest->throttle_timers, - &bs_src->throttle_timers, - sizeof(ThrottleTimers)); - /* r/w error */ bs_dest->on_read_error = bs_src->on_read_error; bs_dest->on_write_error = bs_src->on_write_error; @@ -2047,125 +2013,45 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, /* dirty bitmap */ bs_dest->dirty_bitmaps = bs_src->dirty_bitmaps; - - /* reference count */ - bs_dest->refcnt = bs_src->refcnt; - - /* job */ - bs_dest->job = bs_src->job; - - /* keep the same entry in bdrv_states */ - bs_dest->device_list = bs_src->device_list; - bs_dest->blk = bs_src->blk; - - memcpy(bs_dest->op_blockers, bs_src->op_blockers, - sizeof(bs_dest->op_blockers)); } -/* - * Swap bs contents for two image chains while they are live, - * while keeping required fields on the BlockDriverState that is - * actually attached to a device. - * - * This will modify the BlockDriverState fields, and swap contents - * between bs_new and bs_old. Both bs_new and bs_old are modified. - * - * bs_new must not be attached to a BlockBackend. - * - * This function does not create any image files. - */ -void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) +static void change_parent_backing_link(BlockDriverState *from, + BlockDriverState *to) { - BlockDriverState tmp; - BdrvChild *child; - - bdrv_drain(bs_new); - bdrv_drain(bs_old); + BdrvChild *c, *next; - /* The code needs to swap the node_name but simply swapping node_list won't - * work so first remove the nodes from the graph list, do the swap then - * insert them back if needed. - */ - if (bs_new->node_name[0] != '\0') { - QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list); + QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { + assert(c->role != &child_backing); + c->bs = to; + QLIST_REMOVE(c, next_parent); + QLIST_INSERT_HEAD(&to->parents, c, next_parent); + bdrv_ref(to); + bdrv_unref(from); } - if (bs_old->node_name[0] != '\0') { - QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list); - } - - /* If the BlockDriverState is part of a throttling group acquire - * its lock since we're going to mess with the protected fields. - * Otherwise there's no need to worry since no one else can touch - * them. */ - if (bs_old->throttle_state) { - throttle_group_lock(bs_old); + if (from->blk) { + blk_set_bs(from->blk, to); + if (!to->device_list.tqe_prev) { + QTAILQ_INSERT_BEFORE(from, to, device_list); + } + QTAILQ_REMOVE(&bdrv_states, from, device_list); } +} - /* bs_new must be unattached and shouldn't have anything fancy enabled */ - assert(!bs_new->blk); - assert(QLIST_EMPTY(&bs_new->dirty_bitmaps)); - assert(bs_new->job == NULL); - assert(bs_new->io_limits_enabled == false); - assert(bs_new->throttle_state == NULL); - assert(!throttle_timers_are_initialized(&bs_new->throttle_timers)); - - tmp = *bs_new; - *bs_new = *bs_old; - *bs_old = tmp; +static void swap_feature_fields(BlockDriverState *bs_top, + BlockDriverState *bs_new) +{ + BlockDriverState tmp; - /* there are some fields that should not be swapped, move them back */ - bdrv_move_feature_fields(&tmp, bs_old); - bdrv_move_feature_fields(bs_old, bs_new); + bdrv_move_feature_fields(&tmp, bs_top); + bdrv_move_feature_fields(bs_top, bs_new); bdrv_move_feature_fields(bs_new, &tmp); - /* bs_new must remain unattached */ - assert(!bs_new->blk); - - /* Check a few fields that should remain attached to the device */ - assert(bs_new->job == NULL); - assert(bs_new->io_limits_enabled == false); - assert(bs_new->throttle_state == NULL); - assert(!throttle_timers_are_initialized(&bs_new->throttle_timers)); - - /* Release the ThrottleGroup lock */ - if (bs_old->throttle_state) { - throttle_group_unlock(bs_old); - } - - /* insert the nodes back into the graph node list if needed */ - if (bs_new->node_name[0] != '\0') { - QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list); - } - if (bs_old->node_name[0] != '\0') { - QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list); + assert(!bs_new->throttle_state); + if (bs_top->throttle_state) { + assert(bs_top->io_limits_enabled); + bdrv_io_limits_enable(bs_new, throttle_group_get_name(bs_top)); + bdrv_io_limits_disable(bs_top); } - - /* - * Update lh_first.le_prev for non-empty lists. - * - * The head of the op blocker list doesn't change because it is moved back - * in bdrv_move_feature_fields(). - */ - assert(QLIST_EMPTY(&bs_old->tracked_requests)); - assert(QLIST_EMPTY(&bs_new->tracked_requests)); - - QLIST_FIX_HEAD_PTR(&bs_new->children, next); - QLIST_FIX_HEAD_PTR(&bs_old->children, next); - - /* Update references in bs->opaque and children */ - QLIST_FOREACH(child, &bs_old->children, next) { - if (child->bs->inherits_from == bs_new) { - child->bs->inherits_from = bs_old; - } - } - QLIST_FOREACH(child, &bs_new->children, next) { - if (child->bs->inherits_from == bs_old) { - child->bs->inherits_from = bs_new; - } - } - - bdrv_rebind(bs_new); - bdrv_rebind(bs_old); } /* @@ -2178,14 +2064,59 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) * bs_new must not be attached to a BlockBackend. * * This function does not create any image files. + * + * bdrv_append() takes ownership of a bs_new reference and unrefs it because + * that's what the callers commonly need. bs_new will be referenced by the old + * parents of bs_top after bdrv_append() returns. If the caller needs to keep a + * reference of its own, it must call bdrv_ref(). */ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top) { - bdrv_swap(bs_new, bs_top); + assert(!bdrv_requests_pending(bs_top)); + assert(!bdrv_requests_pending(bs_new)); + + bdrv_ref(bs_top); + change_parent_backing_link(bs_top, bs_new); + + /* Some fields always stay on top of the backing file chain */ + swap_feature_fields(bs_top, bs_new); + + bdrv_set_backing_hd(bs_new, bs_top); + bdrv_unref(bs_top); + + /* bs_new is now referenced by its new parents, we don't need the + * additional reference any more. */ + bdrv_unref(bs_new); +} + +void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new) +{ + assert(!bdrv_requests_pending(old)); + assert(!bdrv_requests_pending(new)); + + bdrv_ref(old); - /* The contents of 'tmp' will become bs_top, as we are - * swapping bs_new and bs_top contents. */ - bdrv_set_backing_hd(bs_top, bs_new); + if (old->blk) { + /* As long as these fields aren't in BlockBackend, but in the top-level + * BlockDriverState, it's not possible for a BDS to have two BBs. + * + * We really want to copy the fields from old to new, but we go for a + * swap instead so that pointers aren't duplicated and cause trouble. + * (Also, bdrv_swap() used to do the same.) */ + assert(!new->blk); + swap_feature_fields(old, new); + } + change_parent_backing_link(old, new); + + /* Change backing files if a previously independent node is added to the + * chain. For active commit, we replace top by its own (indirect) backing + * file and don't do anything here so we don't build a loop. */ + if (new->backing == NULL && !bdrv_chain_contains(backing_bs(old), new)) { + bdrv_set_backing_hd(new, backing_bs(old)); + bdrv_set_backing_hd(old, NULL); + } + + bdrv_unref(old); } static void bdrv_delete(BlockDriverState *bs) @@ -2237,20 +2168,20 @@ int bdrv_commit(BlockDriverState *bs) if (!drv) return -ENOMEDIUM; - if (!bs->backing_hd) { + if (!bs->backing) { return -ENOTSUP; } if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) || - bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) { + bdrv_op_is_blocked(bs->backing->bs, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) { return -EBUSY; } - ro = bs->backing_hd->read_only; - open_flags = bs->backing_hd->open_flags; + ro = bs->backing->bs->read_only; + open_flags = bs->backing->bs->open_flags; if (ro) { - if (bdrv_reopen(bs->backing_hd, open_flags | BDRV_O_RDWR, NULL)) { + if (bdrv_reopen(bs->backing->bs, open_flags | BDRV_O_RDWR, NULL)) { return -EACCES; } } @@ -2261,7 +2192,7 @@ int bdrv_commit(BlockDriverState *bs) goto ro_cleanup; } - backing_length = bdrv_getlength(bs->backing_hd); + backing_length = bdrv_getlength(bs->backing->bs); if (backing_length < 0) { ret = backing_length; goto ro_cleanup; @@ -2271,7 +2202,7 @@ int bdrv_commit(BlockDriverState *bs) * grow the backing file image if possible. If not possible, * we must return an error */ if (length > backing_length) { - ret = bdrv_truncate(bs->backing_hd, length); + ret = bdrv_truncate(bs->backing->bs, length); if (ret < 0) { goto ro_cleanup; } @@ -2280,7 +2211,7 @@ int bdrv_commit(BlockDriverState *bs) total_sectors = length >> BDRV_SECTOR_BITS; /* qemu_try_blockalign() for bs will choose an alignment that works for - * bs->backing_hd as well, so no need to compare the alignment manually. */ + * bs->backing->bs as well, so no need to compare the alignment manually. */ buf = qemu_try_blockalign(bs, COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE); if (buf == NULL) { ret = -ENOMEM; @@ -2298,7 +2229,7 @@ int bdrv_commit(BlockDriverState *bs) goto ro_cleanup; } - ret = bdrv_write(bs->backing_hd, sector, buf, n); + ret = bdrv_write(bs->backing->bs, sector, buf, n); if (ret < 0) { goto ro_cleanup; } @@ -2317,8 +2248,8 @@ int bdrv_commit(BlockDriverState *bs) * Make sure all data we wrote to the backing device is actually * stable on disk. */ - if (bs->backing_hd) { - bdrv_flush(bs->backing_hd); + if (bs->backing) { + bdrv_flush(bs->backing->bs); } ret = 0; @@ -2327,7 +2258,7 @@ ro_cleanup: if (ro) { /* ignoring error return here */ - bdrv_reopen(bs->backing_hd, open_flags & ~BDRV_O_RDWR, NULL); + bdrv_reopen(bs->backing->bs, open_flags & ~BDRV_O_RDWR, NULL); } return ret; @@ -2341,7 +2272,7 @@ int bdrv_commit_all(void) AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - if (bs->drv && bs->backing_hd) { + if (bs->drv && bs->backing) { int ret = bdrv_commit(bs); if (ret < 0) { aio_context_release(aio_context); @@ -2398,8 +2329,8 @@ int bdrv_change_backing_file(BlockDriverState *bs, BlockDriverState *bdrv_find_overlay(BlockDriverState *active, BlockDriverState *bs) { - while (active && bs != active->backing_hd) { - active = active->backing_hd; + while (active && bs != backing_bs(active)) { + active = backing_bs(active); } return active; @@ -2411,12 +2342,6 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs) return bdrv_find_overlay(bs, NULL); } -typedef struct BlkIntermediateStates { - BlockDriverState *bs; - QSIMPLEQ_ENTRY(BlkIntermediateStates) entry; -} BlkIntermediateStates; - - /* * Drops images above 'base' up to and including 'top', and sets the image * above 'top' to have base as its backing file. @@ -2449,15 +2374,9 @@ typedef struct BlkIntermediateStates { int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, BlockDriverState *base, const char *backing_file_str) { - BlockDriverState *intermediate; - BlockDriverState *base_bs = NULL; BlockDriverState *new_top_bs = NULL; - BlkIntermediateStates *intermediate_state, *next; int ret = -EIO; - QSIMPLEQ_HEAD(states_to_delete, BlkIntermediateStates) states_to_delete; - QSIMPLEQ_INIT(&states_to_delete); - if (!top->drv || !base->drv) { goto exit; } @@ -2469,55 +2388,29 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, goto exit; } - /* special case of new_top_bs->backing_hd already pointing to base - nothing + /* special case of new_top_bs->backing->bs already pointing to base - nothing * to do, no intermediate images */ - if (new_top_bs->backing_hd == base) { + if (backing_bs(new_top_bs) == base) { ret = 0; goto exit; } - intermediate = top; - - /* now we will go down through the list, and add each BDS we find - * into our deletion queue, until we hit the 'base' - */ - while (intermediate) { - intermediate_state = g_new0(BlkIntermediateStates, 1); - intermediate_state->bs = intermediate; - QSIMPLEQ_INSERT_TAIL(&states_to_delete, intermediate_state, entry); - - if (intermediate->backing_hd == base) { - base_bs = intermediate->backing_hd; - break; - } - intermediate = intermediate->backing_hd; - } - if (base_bs == NULL) { - /* something went wrong, we did not end at the base. safely - * unravel everything, and exit with error */ + /* Make sure that base is in the backing chain of top */ + if (!bdrv_chain_contains(top, base)) { goto exit; } /* success - we can delete the intermediate states, and link top->base */ - backing_file_str = backing_file_str ? backing_file_str : base_bs->filename; + backing_file_str = backing_file_str ? backing_file_str : base->filename; ret = bdrv_change_backing_file(new_top_bs, backing_file_str, - base_bs->drv ? base_bs->drv->format_name : ""); + base->drv ? base->drv->format_name : ""); if (ret) { goto exit; } - bdrv_set_backing_hd(new_top_bs, base_bs); + bdrv_set_backing_hd(new_top_bs, base); - QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) { - /* so that bdrv_close() does not recursively close the chain */ - bdrv_set_backing_hd(intermediate_state->bs, NULL); - bdrv_unref(intermediate_state->bs); - } ret = 0; - exit: - QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) { - g_free(intermediate_state); - } return ret; } @@ -2560,7 +2453,7 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) return drv->bdrv_get_allocated_file_size(bs); } if (bs->file) { - return bdrv_get_allocated_file_size(bs->file); + return bdrv_get_allocated_file_size(bs->file->bs); } return -ENOTSUP; } @@ -2709,25 +2602,27 @@ void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce) int bdrv_is_encrypted(BlockDriverState *bs) { - if (bs->backing_hd && bs->backing_hd->encrypted) + if (bs->backing && bs->backing->bs->encrypted) { return 1; + } return bs->encrypted; } int bdrv_key_required(BlockDriverState *bs) { - BlockDriverState *backing_hd = bs->backing_hd; + BdrvChild *backing = bs->backing; - if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key) + if (backing && backing->bs->encrypted && !backing->bs->valid_key) { return 1; + } return (bs->encrypted && !bs->valid_key); } int bdrv_set_key(BlockDriverState *bs, const char *key) { int ret; - if (bs->backing_hd && bs->backing_hd->encrypted) { - ret = bdrv_set_key(bs->backing_hd, key); + if (bs->backing && bs->backing->bs->encrypted) { + ret = bdrv_set_key(bs->backing->bs, key); if (ret < 0) return ret; if (!bs->encrypted) @@ -2894,7 +2789,7 @@ BlockDriverState *bdrv_lookup_bs(const char *device, bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base) { while (top && top != base) { - top = top->backing_hd; + top = backing_bs(top); } return top != NULL; @@ -2952,7 +2847,7 @@ int bdrv_has_zero_init(BlockDriverState *bs) /* If BS is a copy on write image, it is initialized to the contents of the base image, which may not be zeroes. */ - if (bs->backing_hd) { + if (bs->backing) { return 0; } if (bs->drv->bdrv_has_zero_init) { @@ -2967,7 +2862,7 @@ bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs) { BlockDriverInfo bdi; - if (bs->backing_hd) { + if (bs->backing) { return false; } @@ -2982,7 +2877,7 @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) { BlockDriverInfo bdi; - if (bs->backing_hd || !(bs->open_flags & BDRV_O_UNMAP)) { + if (bs->backing || !(bs->open_flags & BDRV_O_UNMAP)) { return false; } @@ -2995,7 +2890,7 @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) const char *bdrv_get_encrypted_filename(BlockDriverState *bs) { - if (bs->backing_hd && bs->backing_hd->encrypted) + if (bs->backing && bs->backing->bs->encrypted) return bs->backing_file; else if (bs->encrypted) return bs->filename; @@ -3042,7 +2937,7 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, const char *tag) { while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) { - bs = bs->file; + bs = bs->file ? bs->file->bs : NULL; } if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) { @@ -3055,7 +2950,7 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) { while (bs && bs->drv && !bs->drv->bdrv_debug_remove_breakpoint) { - bs = bs->file; + bs = bs->file ? bs->file->bs : NULL; } if (bs && bs->drv && bs->drv->bdrv_debug_remove_breakpoint) { @@ -3068,7 +2963,7 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) int bdrv_debug_resume(BlockDriverState *bs, const char *tag) { while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) { - bs = bs->file; + bs = bs->file ? bs->file->bs : NULL; } if (bs && bs->drv && bs->drv->bdrv_debug_resume) { @@ -3081,7 +2976,7 @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag) bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) { while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) { - bs = bs->file; + bs = bs->file ? bs->file->bs : NULL; } if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) { @@ -3120,13 +3015,13 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, is_protocol = path_has_protocol(backing_file); - for (curr_bs = bs; curr_bs->backing_hd; curr_bs = curr_bs->backing_hd) { + for (curr_bs = bs; curr_bs->backing; curr_bs = curr_bs->backing->bs) { /* If either of the filename paths is actually a protocol, then * compare unmodified paths; otherwise make paths relative */ if (is_protocol || path_has_protocol(curr_bs->backing_file)) { if (strcmp(backing_file, curr_bs->backing_file) == 0) { - retval = curr_bs->backing_hd; + retval = curr_bs->backing->bs; break; } } else { @@ -3150,7 +3045,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, } if (strcmp(backing_file_full, filename_full) == 0) { - retval = curr_bs->backing_hd; + retval = curr_bs->backing->bs; break; } } @@ -3168,11 +3063,11 @@ int bdrv_get_backing_file_depth(BlockDriverState *bs) return 0; } - if (!bs->backing_hd) { + if (!bs->backing) { return 0; } - return 1 + bdrv_get_backing_file_depth(bs->backing_hd); + return 1 + bdrv_get_backing_file_depth(bs->backing->bs); } void bdrv_init(void) @@ -3203,7 +3098,7 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) if (bs->drv->bdrv_invalidate_cache) { bs->drv->bdrv_invalidate_cache(bs, &local_err); } else if (bs->file) { - bdrv_invalidate_cache(bs->file, &local_err); + bdrv_invalidate_cache(bs->file->bs, &local_err); } if (local_err) { error_propagate(errp, local_err); @@ -3933,10 +3828,10 @@ void bdrv_detach_aio_context(BlockDriverState *bs) bs->drv->bdrv_detach_aio_context(bs); } if (bs->file) { - bdrv_detach_aio_context(bs->file); + bdrv_detach_aio_context(bs->file->bs); } - if (bs->backing_hd) { - bdrv_detach_aio_context(bs->backing_hd); + if (bs->backing) { + bdrv_detach_aio_context(bs->backing->bs); } bs->aio_context = NULL; @@ -3953,11 +3848,11 @@ void bdrv_attach_aio_context(BlockDriverState *bs, bs->aio_context = new_context; - if (bs->backing_hd) { - bdrv_attach_aio_context(bs->backing_hd, new_context); + if (bs->backing) { + bdrv_attach_aio_context(bs->backing->bs, new_context); } if (bs->file) { - bdrv_attach_aio_context(bs->file, new_context); + bdrv_attach_aio_context(bs->file->bs, new_context); } if (bs->drv->bdrv_attach_aio_context) { bs->drv->bdrv_attach_aio_context(bs, new_context); @@ -4169,7 +4064,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) /* This BDS's file name will most probably depend on its file's name, so * refresh that first */ if (bs->file) { - bdrv_refresh_filename(bs->file); + bdrv_refresh_filename(bs->file->bs); } if (drv->bdrv_refresh_filename) { @@ -4197,19 +4092,20 @@ void bdrv_refresh_filename(BlockDriverState *bs) /* If no specific options have been given for this BDS, the filename of * the underlying file should suffice for this one as well */ - if (bs->file->exact_filename[0] && !has_open_options) { - strcpy(bs->exact_filename, bs->file->exact_filename); + if (bs->file->bs->exact_filename[0] && !has_open_options) { + strcpy(bs->exact_filename, bs->file->bs->exact_filename); } /* Reconstructing the full options QDict is simple for most format block * drivers, as long as the full options are known for the underlying * file BDS. The full options QDict of that file BDS should somehow * contain a representation of the filename, therefore the following * suffices without querying the (exact_)filename of this BDS. */ - if (bs->file->full_open_options) { + if (bs->file->bs->full_open_options) { qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str(drv->format_name))); - QINCREF(bs->file->full_open_options); - qdict_put_obj(opts, "file", QOBJECT(bs->file->full_open_options)); + QINCREF(bs->file->bs->full_open_options); + qdict_put_obj(opts, "file", + QOBJECT(bs->file->bs->full_open_options)); bs->full_open_options = opts; } else { diff --git a/block/blkdebug.c b/block/blkdebug.c index bc247f46f5..6860a2ba2f 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -426,11 +426,11 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, /* Set initial state */ s->state = 1; - /* Open the backing file */ - assert(bs->file == NULL); - ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image", - bs, &child_file, false, &local_err); - if (ret < 0) { + /* Open the image file */ + bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", + bs, &child_file, false, &local_err); + if (local_err) { + ret = -EINVAL; error_propagate(errp, local_err); goto out; } @@ -449,7 +449,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, goto out; fail_unref: - bdrv_unref(bs->file); + bdrv_unref_child(bs, bs->file); out: qemu_opts_del(opts); return ret; @@ -510,7 +510,8 @@ static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs, return inject_error(bs, cb, opaque, rule); } - return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); + return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors, + cb, opaque); } static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs, @@ -532,7 +533,8 @@ static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs, return inject_error(bs, cb, opaque, rule); } - return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); + return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors, + cb, opaque); } static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs, @@ -551,7 +553,7 @@ static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs, return inject_error(bs, cb, opaque, rule); } - return bdrv_aio_flush(bs->file, cb, opaque); + return bdrv_aio_flush(bs->file->bs, cb, opaque); } @@ -716,12 +718,12 @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) static int64_t blkdebug_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file); + return bdrv_getlength(bs->file->bs); } static int blkdebug_truncate(BlockDriverState *bs, int64_t offset) { - return bdrv_truncate(bs->file, offset); + return bdrv_truncate(bs->file->bs, offset); } static void blkdebug_refresh_filename(BlockDriverState *bs) @@ -741,24 +743,24 @@ static void blkdebug_refresh_filename(BlockDriverState *bs) } } - if (force_json && !bs->file->full_open_options) { + if (force_json && !bs->file->bs->full_open_options) { /* The config file cannot be recreated, so creating a plain filename * is impossible */ return; } - if (!force_json && bs->file->exact_filename[0]) { + if (!force_json && bs->file->bs->exact_filename[0]) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), "blkdebug:%s:%s", qdict_get_try_str(bs->options, "config") ?: "", - bs->file->exact_filename); + bs->file->bs->exact_filename); } opts = qdict_new(); qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug"))); - QINCREF(bs->file->full_open_options); - qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options)); + QINCREF(bs->file->bs->full_open_options); + qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options)); for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { if (strcmp(qdict_entry_key(e), "x-image") && diff --git a/block/blkverify.c b/block/blkverify.c index d277e63220..c5f8e8dcba 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -14,7 +14,7 @@ #include "qapi/qmp/qstring.h" typedef struct { - BlockDriverState *test_file; + BdrvChild *test_file; } BDRVBlkverifyState; typedef struct BlkverifyAIOCB BlkverifyAIOCB; @@ -123,26 +123,29 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the raw file */ - assert(bs->file == NULL); - ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options, - "raw", bs, &child_file, false, &local_err); - if (ret < 0) { + bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", + bs, &child_file, false, &local_err); + if (local_err) { + ret = -EINVAL; error_propagate(errp, local_err); goto fail; } /* Open the test file */ - assert(s->test_file == NULL); - ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options, - "test", bs, &child_format, false, &local_err); - if (ret < 0) { + s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, + "test", bs, &child_format, false, + &local_err); + if (local_err) { + ret = -EINVAL; error_propagate(errp, local_err); - s->test_file = NULL; goto fail; } ret = 0; fail: + if (ret < 0) { + bdrv_unref_child(bs, bs->file); + } qemu_opts_del(opts); return ret; } @@ -151,7 +154,7 @@ static void blkverify_close(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - bdrv_unref(s->test_file); + bdrv_unref_child(bs, s->test_file); s->test_file = NULL; } @@ -159,7 +162,7 @@ static int64_t blkverify_getlength(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - return bdrv_getlength(s->test_file); + return bdrv_getlength(s->test_file->bs); } static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, @@ -238,13 +241,13 @@ static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs, nb_sectors, cb, opaque); acb->verify = blkverify_verify_readv; - acb->buf = qemu_blockalign(bs->file, qiov->size); + acb->buf = qemu_blockalign(bs->file->bs, qiov->size); qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf); - bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, + bdrv_aio_readv(s->test_file->bs, sector_num, qiov, nb_sectors, blkverify_aio_cb, acb); - bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors, + bdrv_aio_readv(bs->file->bs, sector_num, &acb->raw_qiov, nb_sectors, blkverify_aio_cb, acb); return &acb->common; } @@ -257,9 +260,9 @@ static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs, BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, nb_sectors, cb, opaque); - bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors, + bdrv_aio_writev(s->test_file->bs, sector_num, qiov, nb_sectors, blkverify_aio_cb, acb); - bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, + bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors, blkverify_aio_cb, acb); return &acb->common; } @@ -271,7 +274,7 @@ static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs, BDRVBlkverifyState *s = bs->opaque; /* Only flush test file, the raw file is not important */ - return bdrv_aio_flush(s->test_file, cb, opaque); + return bdrv_aio_flush(s->test_file->bs, cb, opaque); } static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, @@ -279,13 +282,13 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, { BDRVBlkverifyState *s = bs->opaque; - bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate); + bool perm = bdrv_recurse_is_first_non_filter(bs->file->bs, candidate); if (perm) { return true; } - return bdrv_recurse_is_first_non_filter(s->test_file, candidate); + return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate); } /* Propagate AioContext changes to ->test_file */ @@ -293,7 +296,7 @@ static void blkverify_detach_aio_context(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - bdrv_detach_aio_context(s->test_file); + bdrv_detach_aio_context(s->test_file->bs); } static void blkverify_attach_aio_context(BlockDriverState *bs, @@ -301,32 +304,38 @@ static void blkverify_attach_aio_context(BlockDriverState *bs, { BDRVBlkverifyState *s = bs->opaque; - bdrv_attach_aio_context(s->test_file, new_context); + bdrv_attach_aio_context(s->test_file->bs, new_context); } static void blkverify_refresh_filename(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - /* bs->file has already been refreshed */ - bdrv_refresh_filename(s->test_file); + /* bs->file->bs has already been refreshed */ + bdrv_refresh_filename(s->test_file->bs); - if (bs->file->full_open_options && s->test_file->full_open_options) { + if (bs->file->bs->full_open_options + && s->test_file->bs->full_open_options) + { QDict *opts = qdict_new(); qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkverify"))); - QINCREF(bs->file->full_open_options); - qdict_put_obj(opts, "raw", QOBJECT(bs->file->full_open_options)); - QINCREF(s->test_file->full_open_options); - qdict_put_obj(opts, "test", QOBJECT(s->test_file->full_open_options)); + QINCREF(bs->file->bs->full_open_options); + qdict_put_obj(opts, "raw", QOBJECT(bs->file->bs->full_open_options)); + QINCREF(s->test_file->bs->full_open_options); + qdict_put_obj(opts, "test", + QOBJECT(s->test_file->bs->full_open_options)); bs->full_open_options = opts; } - if (bs->file->exact_filename[0] && s->test_file->exact_filename[0]) { + if (bs->file->bs->exact_filename[0] + && s->test_file->bs->exact_filename[0]) + { snprintf(bs->exact_filename, sizeof(bs->exact_filename), "blkverify:%s:%s", - bs->file->exact_filename, s->test_file->exact_filename); + bs->file->bs->exact_filename, + s->test_file->bs->exact_filename); } } diff --git a/block/block-backend.c b/block/block-backend.c index c2e873292a..225655126e 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -239,6 +239,23 @@ BlockDriverState *blk_bs(BlockBackend *blk) } /* + * Changes the BlockDriverState attached to @blk + */ +void blk_set_bs(BlockBackend *blk, BlockDriverState *bs) +{ + bdrv_ref(bs); + + if (blk->bs) { + blk->bs->blk = NULL; + bdrv_unref(blk->bs); + } + assert(bs->blk == NULL); + + blk->bs = bs; + bs->blk = blk; +} + +/* * Return @blk's DriveInfo if any, else null. */ DriveInfo *blk_legacy_dinfo(BlockBackend *blk) diff --git a/block/bochs.c b/block/bochs.c index 199ac2b9af..18949b9d4f 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -103,7 +103,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, bs->read_only = 1; // no write support yet - ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)); + ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs)); if (ret < 0) { return ret; } @@ -137,7 +137,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, return -ENOMEM; } - ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap, + ret = bdrv_pread(bs->file->bs, le32_to_cpu(bochs.header), s->catalog_bitmap, s->catalog_size * 4); if (ret < 0) { goto fail; @@ -206,7 +206,7 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) (s->extent_blocks + s->bitmap_blocks)); /* read in bitmap for current extent */ - ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), + ret = bdrv_pread(bs->file->bs, bitmap_offset + (extent_offset / 8), &bitmap_entry, 1); if (ret < 0) { return ret; @@ -229,7 +229,7 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num, if (block_offset < 0) { return block_offset; } else if (block_offset > 0) { - ret = bdrv_pread(bs->file, block_offset, buf, 512); + ret = bdrv_pread(bs->file->bs, block_offset, buf, 512); if (ret < 0) { return ret; } diff --git a/block/cloop.c b/block/cloop.c index f328be06f8..4190ae06d7 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -66,7 +66,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, bs->read_only = 1; /* read header */ - ret = bdrv_pread(bs->file, 128, &s->block_size, 4); + ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4); if (ret < 0) { return ret; } @@ -92,7 +92,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return -EINVAL; } - ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4); + ret = bdrv_pread(bs->file->bs, 128 + 4, &s->n_blocks, 4); if (ret < 0) { return ret; } @@ -123,7 +123,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return -ENOMEM; } - ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); + ret = bdrv_pread(bs->file->bs, 128 + 4 + 4, s->offsets, offsets_size); if (ret < 0) { goto fail; } @@ -203,8 +203,8 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num) int ret; uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num]; - ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block, - bytes); + ret = bdrv_pread(bs->file->bs, s->offsets[block_num], + s->compressed_block, bytes); if (ret != bytes) { return -1; } diff --git a/block/dmg.c b/block/dmg.c index 9f2528169c..546a6f5330 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -85,7 +85,7 @@ static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result) uint64_t buffer; int ret; - ret = bdrv_pread(bs->file, offset, &buffer, 8); + ret = bdrv_pread(bs->file->bs, offset, &buffer, 8); if (ret < 0) { return ret; } @@ -99,7 +99,7 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result) uint32_t buffer; int ret; - ret = bdrv_pread(bs->file, offset, &buffer, 4); + ret = bdrv_pread(bs->file->bs, offset, &buffer, 4); if (ret < 0) { return ret; } @@ -354,7 +354,7 @@ static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds, offset += 4; buffer = g_realloc(buffer, count); - ret = bdrv_pread(bs->file, offset, buffer, count); + ret = bdrv_pread(bs->file->bs, offset, buffer, count); if (ret < 0) { goto fail; } @@ -391,7 +391,7 @@ static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds, buffer = g_malloc(info_length + 1); buffer[info_length] = '\0'; - ret = bdrv_pread(bs->file, info_begin, buffer, info_length); + ret = bdrv_pread(bs->file->bs, info_begin, buffer, info_length); if (ret != info_length) { ret = -EINVAL; goto fail; @@ -446,7 +446,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, ds.max_sectors_per_chunk = 1; /* locate the UDIF trailer */ - offset = dmg_find_koly_offset(bs->file, errp); + offset = dmg_find_koly_offset(bs->file->bs, errp); if (offset < 0) { ret = offset; goto fail; @@ -514,9 +514,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, } /* initialize zlib engine */ - s->compressed_chunk = qemu_try_blockalign(bs->file, + s->compressed_chunk = qemu_try_blockalign(bs->file->bs, ds.max_compressed_size + 1); - s->uncompressed_chunk = qemu_try_blockalign(bs->file, + s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs, 512 * ds.max_sectors_per_chunk); if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { ret = -ENOMEM; @@ -592,7 +592,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) case 0x80000005: { /* zlib compressed */ /* we need to buffer, because only the chunk as whole can be * inflated. */ - ret = bdrv_pread(bs->file, s->offsets[chunk], + ret = bdrv_pread(bs->file->bs, s->offsets[chunk], s->compressed_chunk, s->lengths[chunk]); if (ret != s->lengths[chunk]) { return -1; @@ -616,7 +616,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) case 0x80000006: /* bzip2 compressed */ /* we need to buffer, because only the chunk as whole can be * inflated. */ - ret = bdrv_pread(bs->file, s->offsets[chunk], + ret = bdrv_pread(bs->file->bs, s->offsets[chunk], s->compressed_chunk, s->lengths[chunk]); if (ret != s->lengths[chunk]) { return -1; @@ -641,7 +641,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) break; #endif /* CONFIG_BZIP2 */ case 1: /* copy */ - ret = bdrv_pread(bs->file, s->offsets[chunk], + ret = bdrv_pread(bs->file->bs, s->offsets[chunk], s->uncompressed_chunk, s->lengths[chunk]); if (ret != s->lengths[chunk]) { return -1; diff --git a/block/io.c b/block/io.c index 17293c3dd3..5311473a1d 100644 --- a/block/io.c +++ b/block/io.c @@ -156,38 +156,38 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) /* Take some limits from the children as a default */ if (bs->file) { - bdrv_refresh_limits(bs->file, &local_err); + bdrv_refresh_limits(bs->file->bs, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - bs->bl.opt_transfer_length = bs->file->bl.opt_transfer_length; - bs->bl.max_transfer_length = bs->file->bl.max_transfer_length; - bs->bl.min_mem_alignment = bs->file->bl.min_mem_alignment; - bs->bl.opt_mem_alignment = bs->file->bl.opt_mem_alignment; + bs->bl.opt_transfer_length = bs->file->bs->bl.opt_transfer_length; + bs->bl.max_transfer_length = bs->file->bs->bl.max_transfer_length; + bs->bl.min_mem_alignment = bs->file->bs->bl.min_mem_alignment; + bs->bl.opt_mem_alignment = bs->file->bs->bl.opt_mem_alignment; } else { bs->bl.min_mem_alignment = 512; bs->bl.opt_mem_alignment = getpagesize(); } - if (bs->backing_hd) { - bdrv_refresh_limits(bs->backing_hd, &local_err); + if (bs->backing) { + bdrv_refresh_limits(bs->backing->bs, &local_err); if (local_err) { error_propagate(errp, local_err); return; } bs->bl.opt_transfer_length = MAX(bs->bl.opt_transfer_length, - bs->backing_hd->bl.opt_transfer_length); + bs->backing->bs->bl.opt_transfer_length); bs->bl.max_transfer_length = MIN_NON_ZERO(bs->bl.max_transfer_length, - bs->backing_hd->bl.max_transfer_length); + bs->backing->bs->bl.max_transfer_length); bs->bl.opt_mem_alignment = MAX(bs->bl.opt_mem_alignment, - bs->backing_hd->bl.opt_mem_alignment); + bs->backing->bs->bl.opt_mem_alignment); bs->bl.min_mem_alignment = MAX(bs->bl.min_mem_alignment, - bs->backing_hd->bl.min_mem_alignment); + bs->backing->bs->bl.min_mem_alignment); } /* Then let the driver override it */ @@ -213,7 +213,7 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) } /* Check if any requests are in-flight (including throttled requests) */ -static bool bdrv_requests_pending(BlockDriverState *bs) +bool bdrv_requests_pending(BlockDriverState *bs) { if (!QLIST_EMPTY(&bs->tracked_requests)) { return true; @@ -224,10 +224,10 @@ static bool bdrv_requests_pending(BlockDriverState *bs) if (!qemu_co_queue_empty(&bs->throttled_reqs[1])) { return true; } - if (bs->file && bdrv_requests_pending(bs->file)) { + if (bs->file && bdrv_requests_pending(bs->file->bs)) { return true; } - if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) { + if (bs->backing && bdrv_requests_pending(bs->backing->bs)) { return true; } return false; @@ -1137,13 +1137,13 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs, if (ret < 0) { /* Do nothing, write notifier decided to fail this request */ } else if (flags & BDRV_REQ_ZERO_WRITE) { - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_ZERO); + bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO); ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags); } else { - BLKDBG_EVENT(bs, BLKDBG_PWRITEV); + bdrv_debug_event(bs, BLKDBG_PWRITEV); ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov); } - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_DONE); + bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE); if (ret == 0 && !bs->enable_write_cache) { ret = bdrv_co_flush(bs); @@ -1192,13 +1192,13 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs, /* RMW the unaligned part before head. */ mark_request_serialising(req, align); wait_serialising_requests(req); - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); ret = bdrv_aligned_preadv(bs, req, offset & ~(align - 1), align, align, &local_qiov, 0); if (ret < 0) { goto fail; } - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); memset(buf + head_padding_bytes, 0, zero_bytes); ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align, @@ -1230,13 +1230,13 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs, /* RMW the unaligned part after tail. */ mark_request_serialising(req, align); wait_serialising_requests(req); - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ret = bdrv_aligned_preadv(bs, req, offset, align, align, &local_qiov, 0); if (ret < 0) { goto fail; } - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); memset(buf, 0, bytes); ret = bdrv_aligned_pwritev(bs, req, offset, align, @@ -1307,13 +1307,13 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, }; qemu_iovec_init_external(&head_qiov, &head_iov, 1); - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); ret = bdrv_aligned_preadv(bs, &req, offset & ~(align - 1), align, align, &head_qiov, 0); if (ret < 0) { goto fail; } - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); qemu_iovec_init(&local_qiov, qiov->niov + 2); qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1)); @@ -1341,13 +1341,13 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, }; qemu_iovec_init_external(&tail_qiov, &tail_iov, 1); - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ret = bdrv_aligned_preadv(bs, &req, (offset + bytes) & ~(align - 1), align, align, &tail_qiov, 0); if (ret < 0) { goto fail; } - BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); + bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); if (!use_local_qiov) { qemu_iovec_init(&local_qiov, qiov->niov + 1); @@ -1496,7 +1496,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, if (ret & BDRV_BLOCK_RAW) { assert(ret & BDRV_BLOCK_OFFSET_VALID); - return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS, + return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS, *pnum, pnum); } @@ -1505,8 +1505,8 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, } else { if (bdrv_unallocated_blocks_are_zero(bs)) { ret |= BDRV_BLOCK_ZERO; - } else if (bs->backing_hd) { - BlockDriverState *bs2 = bs->backing_hd; + } else if (bs->backing) { + BlockDriverState *bs2 = bs->backing->bs; int64_t nb_sectors2 = bdrv_nb_sectors(bs2); if (nb_sectors2 >= 0 && sector_num >= nb_sectors2) { ret |= BDRV_BLOCK_ZERO; @@ -1519,7 +1519,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, (ret & BDRV_BLOCK_OFFSET_VALID)) { int file_pnum; - ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS, + ret2 = bdrv_co_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS, *pnum, &file_pnum); if (ret2 >= 0) { /* Ignore errors. This is just providing extra information, it @@ -1551,7 +1551,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs, int64_t ret = 0; assert(bs != base); - for (p = bs; p != base; p = p->backing_hd) { + for (p = bs; p != base; p = backing_bs(p)) { ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum); if (ret < 0 || ret & BDRV_BLOCK_ALLOCATED) { break; @@ -1614,7 +1614,7 @@ int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { - return bdrv_get_block_status_above(bs, bs->backing_hd, + return bdrv_get_block_status_above(bs, backing_bs(bs), sector_num, nb_sectors, pnum); } @@ -1672,7 +1672,7 @@ int bdrv_is_allocated_above(BlockDriverState *top, n = pnum_inter; } - intermediate = intermediate->backing_hd; + intermediate = backing_bs(intermediate); } *pnum = n; @@ -1723,7 +1723,7 @@ int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) } else if (drv->bdrv_save_vmstate) { return drv->bdrv_save_vmstate(bs, qiov, pos); } else if (bs->file) { - return bdrv_writev_vmstate(bs->file, qiov, pos); + return bdrv_writev_vmstate(bs->file->bs, qiov, pos); } return -ENOTSUP; @@ -1738,7 +1738,7 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, if (drv->bdrv_load_vmstate) return drv->bdrv_load_vmstate(bs, buf, pos, size); if (bs->file) - return bdrv_load_vmstate(bs->file, buf, pos, size); + return bdrv_load_vmstate(bs->file->bs, buf, pos, size); return -ENOTSUP; } @@ -2366,7 +2366,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) * in the case of cache=unsafe, so there are no useless flushes. */ flush_parent: - return bdrv_co_flush(bs->file); + return bs->file ? bdrv_co_flush(bs->file->bs) : 0; } int bdrv_flush(BlockDriverState *bs) @@ -2594,7 +2594,7 @@ void bdrv_io_plug(BlockDriverState *bs) if (drv && drv->bdrv_io_plug) { drv->bdrv_io_plug(bs); } else if (bs->file) { - bdrv_io_plug(bs->file); + bdrv_io_plug(bs->file->bs); } } @@ -2604,7 +2604,7 @@ void bdrv_io_unplug(BlockDriverState *bs) if (drv && drv->bdrv_io_unplug) { drv->bdrv_io_unplug(bs); } else if (bs->file) { - bdrv_io_unplug(bs->file); + bdrv_io_unplug(bs->file->bs); } } @@ -2614,7 +2614,7 @@ void bdrv_flush_io_queue(BlockDriverState *bs) if (drv && drv->bdrv_flush_io_queue) { drv->bdrv_flush_io_queue(bs); } else if (bs->file) { - bdrv_flush_io_queue(bs->file); + bdrv_flush_io_queue(bs->file->bs); } bdrv_start_throttled_reqs(bs); } diff --git a/block/mirror.c b/block/mirror.c index 1ca4aa0da0..7e43511832 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -353,6 +353,11 @@ static void mirror_exit(BlockJob *job, void *opaque) MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); MirrorExitData *data = opaque; AioContext *replace_aio_context = NULL; + BlockDriverState *src = s->common.bs; + + /* Make sure that the source BDS doesn't go away before we called + * block_job_completed(). */ + bdrv_ref(src); if (s->to_replace) { replace_aio_context = bdrv_get_aio_context(s->to_replace); @@ -367,14 +372,7 @@ static void mirror_exit(BlockJob *job, void *opaque) if (bdrv_get_flags(s->target) != bdrv_get_flags(to_replace)) { bdrv_reopen(s->target, bdrv_get_flags(to_replace), NULL); } - bdrv_swap(s->target, to_replace); - if (s->common.driver->job_type == BLOCK_JOB_TYPE_COMMIT) { - /* drop the bs loop chain formed by the swap: break the loop then - * trigger the unref from the top one */ - BlockDriverState *p = s->base->backing_hd; - bdrv_set_backing_hd(s->base, NULL); - bdrv_unref(p); - } + bdrv_replace_in_backing_chain(to_replace, s->target); } if (s->to_replace) { bdrv_op_unblock_all(s->to_replace, s->replace_blocker); @@ -388,6 +386,7 @@ static void mirror_exit(BlockJob *job, void *opaque) bdrv_unref(s->target); block_job_completed(&s->common, data->ret); g_free(data); + bdrv_unref(src); } static void coroutine_fn mirror_run(void *opaque) @@ -431,7 +430,7 @@ static void coroutine_fn mirror_run(void *opaque) */ bdrv_get_backing_filename(s->target, backing_filename, sizeof(backing_filename)); - if (backing_filename[0] && !s->target->backing_hd) { + if (backing_filename[0] && !s->target->backing) { ret = bdrv_get_info(s->target, &bdi); if (ret < 0) { goto immediate_exit; @@ -637,8 +636,7 @@ static void mirror_complete(BlockJob *job, Error **errp) return; } if (!s->synced) { - error_setg(errp, QERR_BLOCK_JOB_NOT_READY, - bdrv_get_device_name(job->bs)); + error_setg(errp, QERR_BLOCK_JOB_NOT_READY, job->id); return; } @@ -766,7 +764,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, return; } is_none_mode = mode == MIRROR_SYNC_MODE_NONE; - base = mode == MIRROR_SYNC_MODE_TOP ? bs->backing_hd : NULL; + base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; mirror_start_job(bs, target, replaces, speed, granularity, buf_size, on_source_error, on_target_error, unmap, cb, opaque, errp, diff --git a/block/parallels.c b/block/parallels.c index 5cd6ec3349..4f79293826 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -202,13 +202,13 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, to_allocate = (sector_num + *pnum + s->tracks - 1) / s->tracks - idx; space = to_allocate * s->tracks; - if (s->data_end + space > bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS) { + if (s->data_end + space > bdrv_getlength(bs->file->bs) >> BDRV_SECTOR_BITS) { int ret; space += s->prealloc_size; if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) { - ret = bdrv_write_zeroes(bs->file, s->data_end, space, 0); + ret = bdrv_write_zeroes(bs->file->bs, s->data_end, space, 0); } else { - ret = bdrv_truncate(bs->file, + ret = bdrv_truncate(bs->file->bs, (s->data_end + space) << BDRV_SECTOR_BITS); } if (ret < 0) { @@ -244,7 +244,8 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs) if (off + to_write > s->header_size) { to_write = s->header_size - off; } - ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off, to_write); + ret = bdrv_pwrite(bs->file->bs, off, (uint8_t *)s->header + off, + to_write); if (ret < 0) { qemu_co_mutex_unlock(&s->lock); return ret; @@ -303,7 +304,7 @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs, qemu_iovec_reset(&hd_qiov); qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes); - ret = bdrv_co_writev(bs->file, position, n, &hd_qiov); + ret = bdrv_co_writev(bs->file->bs, position, n, &hd_qiov); if (ret < 0) { break; } @@ -343,7 +344,7 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs, qemu_iovec_reset(&hd_qiov); qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes); - ret = bdrv_co_readv(bs->file, position, n, &hd_qiov); + ret = bdrv_co_readv(bs->file->bs, position, n, &hd_qiov); if (ret < 0) { break; } @@ -369,7 +370,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res, bool flush_bat = false; int cluster_size = s->tracks << BDRV_SECTOR_BITS; - size = bdrv_getlength(bs->file); + size = bdrv_getlength(bs->file->bs); if (size < 0) { res->check_errors++; return size; @@ -424,7 +425,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res, } if (flush_bat) { - ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size); + ret = bdrv_pwrite_sync(bs->file->bs, 0, s->header, s->header_size); if (ret < 0) { res->check_errors++; return ret; @@ -440,7 +441,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res, size - res->image_end_offset); res->leaks += count; if (fix & BDRV_FIX_LEAKS) { - ret = bdrv_truncate(bs->file, res->image_end_offset); + ret = bdrv_truncate(bs->file->bs, res->image_end_offset); if (ret < 0) { res->check_errors++; return ret; @@ -546,12 +547,13 @@ static int parallels_probe(const uint8_t *buf, int buf_size, static int parallels_update_header(BlockDriverState *bs) { BDRVParallelsState *s = bs->opaque; - unsigned size = MAX(bdrv_opt_mem_align(bs->file), sizeof(ParallelsHeader)); + unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs), + sizeof(ParallelsHeader)); if (size > s->header_size) { size = s->header_size; } - return bdrv_pwrite_sync(bs->file, 0, s->header, size); + return bdrv_pwrite_sync(bs->file->bs, 0, s->header, size); } static int parallels_open(BlockDriverState *bs, QDict *options, int flags, @@ -564,7 +566,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; char *buf; - ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph)); + ret = bdrv_pread(bs->file->bs, 0, &ph, sizeof(ph)); if (ret < 0) { goto fail; } @@ -603,8 +605,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, } size = bat_entry_off(s->bat_size); - s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file)); - s->header = qemu_try_blockalign(bs->file, s->header_size); + s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file->bs)); + s->header = qemu_try_blockalign(bs->file->bs, s->header_size); if (s->header == NULL) { ret = -ENOMEM; goto fail; @@ -619,7 +621,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, s->header_size = size; } - ret = bdrv_pread(bs->file, 0, s->header, s->header_size); + ret = bdrv_pread(bs->file->bs, 0, s->header, s->header_size); if (ret < 0) { goto fail; } @@ -663,8 +665,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, if (local_err != NULL) { goto fail_options; } - if (!bdrv_has_zero_init(bs->file) || - bdrv_truncate(bs->file, bdrv_getlength(bs->file)) != 0) { + if (!bdrv_has_zero_init(bs->file->bs) || + bdrv_truncate(bs->file->bs, bdrv_getlength(bs->file->bs)) != 0) { s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; } @@ -707,7 +709,7 @@ static void parallels_close(BlockDriverState *bs) } if (bs->open_flags & BDRV_O_RDWR) { - bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS); + bdrv_truncate(bs->file->bs, s->data_end << BDRV_SECTOR_BITS); } g_free(s->bat_dirty_bmap); diff --git a/block/qapi.c b/block/qapi.c index 2ce509711d..355ba324f1 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -110,8 +110,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp) qapi_free_BlockDeviceInfo(info); return NULL; } - if (bs0->drv && bs0->backing_hd) { - bs0 = bs0->backing_hd; + if (bs0->drv && bs0->backing) { + bs0 = bs0->backing->bs; (*p_image_info)->has_backing_image = true; p_image_info = &((*p_image_info)->backing_image); } else { @@ -359,12 +359,12 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs, if (bs->file) { s->has_parent = true; - s->parent = bdrv_query_stats(bs->file, query_backing); + s->parent = bdrv_query_stats(bs->file->bs, query_backing); } - if (query_backing && bs->backing_hd) { + if (query_backing && bs->backing) { s->has_backing = true; - s->backing = bdrv_query_stats(bs->backing_hd, query_backing); + s->backing = bdrv_query_stats(bs->backing->bs, query_backing); } return s; diff --git a/block/qcow.c b/block/qcow.c index 6e35db1df8..635085e27b 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -100,7 +100,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, int ret; QCowHeader header; - ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); + ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header)); if (ret < 0) { goto fail; } @@ -193,7 +193,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, + ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)); if (ret < 0) { goto fail; @@ -205,7 +205,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, /* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */ s->l2_cache = - qemu_try_blockalign(bs->file, + qemu_try_blockalign(bs->file->bs, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); if (s->l2_cache == NULL) { error_setg(errp, "Could not allocate L2 table cache"); @@ -224,7 +224,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, ret = -EINVAL; goto fail; } - ret = bdrv_pread(bs->file, header.backing_file_offset, + ret = bdrv_pread(bs->file->bs, header.backing_file_offset, bs->backing_file, len); if (ret < 0) { goto fail; @@ -369,13 +369,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, if (!allocate) return 0; /* allocate a new l2 entry */ - l2_offset = bdrv_getlength(bs->file); + l2_offset = bdrv_getlength(bs->file->bs); /* round to cluster size */ l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* update the L1 entry */ s->l1_table[l1_index] = l2_offset; tmp = cpu_to_be64(l2_offset); - if (bdrv_pwrite_sync(bs->file, + if (bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset + l1_index * sizeof(tmp), &tmp, sizeof(tmp)) < 0) return 0; @@ -405,11 +405,12 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, l2_table = s->l2_cache + (min_index << s->l2_bits); if (new_l2_table) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table, + if (bdrv_pwrite_sync(bs->file->bs, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) < 0) return 0; } else { - if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + if (bdrv_pread(bs->file->bs, l2_offset, l2_table, + s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; } @@ -430,20 +431,21 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, overwritten */ if (decompress_cluster(bs, cluster_offset) < 0) return 0; - cluster_offset = bdrv_getlength(bs->file); + cluster_offset = bdrv_getlength(bs->file->bs); cluster_offset = (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* write the cluster content */ - if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) != + if (bdrv_pwrite(bs->file->bs, cluster_offset, s->cluster_cache, + s->cluster_size) != s->cluster_size) return -1; } else { - cluster_offset = bdrv_getlength(bs->file); + cluster_offset = bdrv_getlength(bs->file->bs); if (allocate == 1) { /* round to cluster size */ cluster_offset = (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); - bdrv_truncate(bs->file, cluster_offset + s->cluster_size); + bdrv_truncate(bs->file->bs, cluster_offset + s->cluster_size); /* if encrypted, we must initialize the cluster content which won't be written */ if (bs->encrypted && @@ -463,7 +465,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, errno = EIO; return -1; } - if (bdrv_pwrite(bs->file, cluster_offset + i * 512, + if (bdrv_pwrite(bs->file->bs, + cluster_offset + i * 512, s->cluster_data, 512) != 512) return -1; } @@ -477,7 +480,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* update L2 table */ tmp = cpu_to_be64(cluster_offset); l2_table[l2_index] = tmp; - if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp), + if (bdrv_pwrite_sync(bs->file->bs, l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) < 0) return 0; } @@ -546,7 +549,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) if (s->cluster_cache_offset != coffset) { csize = cluster_offset >> (63 - s->cluster_bits); csize &= (s->cluster_size - 1); - ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize); + ret = bdrv_pread(bs->file->bs, coffset, s->cluster_data, csize); if (ret != csize) return -1; if (decompress_buffer(s->cluster_cache, s->cluster_size, @@ -594,13 +597,13 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, } if (!cluster_offset) { - if (bs->backing_hd) { + if (bs->backing) { /* read from the base image */ hd_iov.iov_base = (void *)buf; hd_iov.iov_len = n * 512; qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_readv(bs->backing_hd, sector_num, + ret = bdrv_co_readv(bs->backing->bs, sector_num, n, &hd_qiov); qemu_co_mutex_lock(&s->lock); if (ret < 0) { @@ -625,7 +628,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, hd_iov.iov_len = n * 512; qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_readv(bs->file, + ret = bdrv_co_readv(bs->file->bs, (cluster_offset >> 9) + index_in_cluster, n, &hd_qiov); qemu_co_mutex_lock(&s->lock); @@ -727,7 +730,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, hd_iov.iov_len = n * 512; qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_writev(bs->file, + ret = bdrv_co_writev(bs->file->bs, (cluster_offset >> 9) + index_in_cluster, n, &hd_qiov); qemu_co_mutex_lock(&s->lock); @@ -879,10 +882,10 @@ static int qcow_make_empty(BlockDriverState *bs) int ret; memset(s->l1_table, 0, l1_length); - if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table, + if (bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, s->l1_table, l1_length) < 0) return -1; - ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length); + ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length); if (ret < 0) return ret; @@ -962,7 +965,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, } cluster_offset &= s->cluster_offset_mask; - ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len); + ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len); if (ret < 0) { goto fail; } diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 7b14c5c5a5..86dd7f2bd9 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -127,7 +127,7 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables) c = g_new0(Qcow2Cache, 1); c->size = num_tables; c->entries = g_try_new0(Qcow2CachedTable, num_tables); - c->table_array = qemu_try_blockalign(bs->file, + c->table_array = qemu_try_blockalign(bs->file->bs, (size_t) num_tables * s->cluster_size); if (!c->entries || !c->table_array) { @@ -185,7 +185,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) if (c->depends) { ret = qcow2_cache_flush_dependency(bs, c); } else if (c->depends_on_flush) { - ret = bdrv_flush(bs->file); + ret = bdrv_flush(bs->file->bs); if (ret >= 0) { c->depends_on_flush = false; } @@ -216,7 +216,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); } - ret = bdrv_pwrite(bs->file, c->entries[i].offset, + ret = bdrv_pwrite(bs->file->bs, c->entries[i].offset, qcow2_cache_get_table_addr(bs, c, i), s->cluster_size); if (ret < 0) { return ret; @@ -244,7 +244,7 @@ int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c) } if (result == 0) { - ret = bdrv_flush(bs->file); + ret = bdrv_flush(bs->file->bs); if (ret < 0) { result = ret; } @@ -356,7 +356,8 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD); } - ret = bdrv_pread(bs->file, offset, qcow2_cache_get_table_addr(bs, c, i), + ret = bdrv_pread(bs->file->bs, offset, + qcow2_cache_get_table_addr(bs, c, i), s->cluster_size); if (ret < 0) { return ret; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 6ede629efb..67be0ce2c9 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -72,7 +72,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, #endif new_l1_size2 = sizeof(uint64_t) * new_l1_size; - new_l1_table = qemu_try_blockalign(bs->file, + new_l1_table = qemu_try_blockalign(bs->file->bs, align_offset(new_l1_size2, 512)); if (new_l1_table == NULL) { return -ENOMEM; @@ -105,7 +105,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE); for(i = 0; i < s->l1_size; i++) new_l1_table[i] = cpu_to_be64(new_l1_table[i]); - ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2); + ret = bdrv_pwrite_sync(bs->file->bs, new_l1_table_offset, + new_l1_table, new_l1_size2); if (ret < 0) goto fail; for(i = 0; i < s->l1_size; i++) @@ -115,7 +116,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE); cpu_to_be32w((uint32_t*)data, new_l1_size); stq_be_p(data + 4, new_l1_table_offset); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data)); + ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_size), + data, sizeof(data)); if (ret < 0) { goto fail; } @@ -182,8 +184,9 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) } BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE); - ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index, - buf, sizeof(buf)); + ret = bdrv_pwrite_sync(bs->file->bs, + s->l1_table_offset + 8 * l1_start_index, + buf, sizeof(buf)); if (ret < 0) { return ret; } @@ -440,7 +443,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs, } BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); - ret = bdrv_co_writev(bs->file, (cluster_offset >> 9) + n_start, n, &qiov); + ret = bdrv_co_writev(bs->file->bs, (cluster_offset >> 9) + n_start, n, + &qiov); if (ret < 0) { goto out; } @@ -817,7 +821,6 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) /* * If this was a COW, we need to decrease the refcount of the old cluster. - * Also flush bs->file to get the right order for L2 and refcount update. * * Don't discard clusters that reach a refcount of 0 (e.g. compressed * clusters), the next write will reuse them anyway. @@ -1412,7 +1415,8 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) sector_offset = coffset & 511; csize = nb_csectors * 512 - sector_offset; BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED); - ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors); + ret = bdrv_read(bs->file->bs, coffset >> 9, s->cluster_data, + nb_csectors); if (ret < 0) { return ret; } @@ -1469,7 +1473,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset, */ switch (qcow2_get_cluster_type(old_l2_entry)) { case QCOW2_CLUSTER_UNALLOCATED: - if (full_discard || !bs->backing_hd) { + if (full_discard || !bs->backing) { continue; } break; @@ -1645,7 +1649,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, if (!is_active_l1) { /* inactive L2 tables require a buffer to be stored in when loading * them from disk */ - l2_table = qemu_try_blockalign(bs->file, s->cluster_size); + l2_table = qemu_try_blockalign(bs->file->bs, s->cluster_size); if (l2_table == NULL) { return -ENOMEM; } @@ -1679,8 +1683,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, (void **)&l2_table); } else { /* load inactive L2 tables from disk */ - ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE, - (void *)l2_table, s->cluster_sectors); + ret = bdrv_read(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE, + (void *)l2_table, s->cluster_sectors); } if (ret < 0) { goto fail; @@ -1703,7 +1707,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, } if (!preallocated) { - if (!bs->backing_hd) { + if (!bs->backing) { /* not backed; therefore we can simply deallocate the * cluster */ l2_table[j] = 0; @@ -1754,7 +1758,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, goto fail; } - ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE, + ret = bdrv_write_zeroes(bs->file->bs, offset / BDRV_SECTOR_SIZE, s->cluster_sectors, 0); if (ret < 0) { if (!preallocated) { @@ -1787,8 +1791,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, goto fail; } - ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE, - (void *)l2_table, s->cluster_sectors); + ret = bdrv_write(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE, + (void *)l2_table, s->cluster_sectors); if (ret < 0) { goto fail; } @@ -1861,8 +1865,9 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs, l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE); - ret = bdrv_read(bs->file, s->snapshots[i].l1_table_offset / - BDRV_SECTOR_SIZE, (void *)l1_table, l1_sectors); + ret = bdrv_read(bs->file->bs, + s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE, + (void *)l1_table, l1_sectors); if (ret < 0) { goto fail; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 2110839da4..4b81c8db61 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -101,7 +101,7 @@ int qcow2_refcount_init(BlockDriverState *bs) goto fail; } BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD); - ret = bdrv_pread(bs->file, s->refcount_table_offset, + ret = bdrv_pread(bs->file->bs, s->refcount_table_offset, s->refcount_table, refcount_table_size2); if (ret < 0) { goto fail; @@ -431,7 +431,7 @@ static int alloc_refcount_block(BlockDriverState *bs, if (refcount_table_index < s->refcount_table_size) { uint64_t data64 = cpu_to_be64(new_block); BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP); - ret = bdrv_pwrite_sync(bs->file, + ret = bdrv_pwrite_sync(bs->file->bs, s->refcount_table_offset + refcount_table_index * sizeof(uint64_t), &data64, sizeof(data64)); if (ret < 0) { @@ -535,7 +535,7 @@ static int alloc_refcount_block(BlockDriverState *bs, /* Write refcount blocks to disk */ BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS); - ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks, + ret = bdrv_pwrite_sync(bs->file->bs, meta_offset, new_blocks, blocks_clusters * s->cluster_size); g_free(new_blocks); new_blocks = NULL; @@ -549,7 +549,7 @@ static int alloc_refcount_block(BlockDriverState *bs, } BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE); - ret = bdrv_pwrite_sync(bs->file, table_offset, new_table, + ret = bdrv_pwrite_sync(bs->file->bs, table_offset, new_table, table_size * sizeof(uint64_t)); if (ret < 0) { goto fail_table; @@ -564,8 +564,9 @@ static int alloc_refcount_block(BlockDriverState *bs, cpu_to_be64w((uint64_t*)data, table_offset); cpu_to_be32w((uint32_t*)(data + 8), table_clusters); BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset), - data, sizeof(data)); + ret = bdrv_pwrite_sync(bs->file->bs, + offsetof(QCowHeader, refcount_table_offset), + data, sizeof(data)); if (ret < 0) { goto fail_table; } @@ -613,7 +614,7 @@ void qcow2_process_discards(BlockDriverState *bs, int ret) /* Discard is optional, ignore the return value */ if (ret >= 0) { - bdrv_discard(bs->file, + bdrv_discard(bs->file->bs, d->offset >> BDRV_SECTOR_BITS, d->bytes >> BDRV_SECTOR_BITS); } @@ -1068,7 +1069,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } l1_allocated = true; - ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2); + ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2); if (ret < 0) { goto fail; } @@ -1221,7 +1222,8 @@ fail: cpu_to_be64s(&l1_table[i]); } - ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2); + ret = bdrv_pwrite_sync(bs->file->bs, l1_table_offset, + l1_table, l1_size2); for (i = 0; i < l1_size; i++) { be64_to_cpus(&l1_table[i]); @@ -1376,7 +1378,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, l2_size = s->l2_size * sizeof(uint64_t); l2_table = g_malloc(l2_size); - ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size); + ret = bdrv_pread(bs->file->bs, l2_offset, l2_table, l2_size); if (ret < 0) { fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n"); res->check_errors++; @@ -1508,7 +1510,7 @@ static int check_refcounts_l1(BlockDriverState *bs, res->check_errors++; goto fail; } - ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2); + ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2); if (ret < 0) { fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); res->check_errors++; @@ -1606,7 +1608,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, } } - ret = bdrv_pread(bs->file, l2_offset, l2_table, + ret = bdrv_pread(bs->file->bs, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)); if (ret < 0) { fprintf(stderr, "ERROR: Could not read L2 table: %s\n", @@ -1658,7 +1660,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, goto fail; } - ret = bdrv_pwrite(bs->file, l2_offset, l2_table, s->cluster_size); + ret = bdrv_pwrite(bs->file->bs, l2_offset, l2_table, + s->cluster_size); if (ret < 0) { fprintf(stderr, "ERROR: Could not write L2 table: %s\n", strerror(-ret)); @@ -1713,11 +1716,11 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res, goto resize_fail; } - ret = bdrv_truncate(bs->file, offset + s->cluster_size); + ret = bdrv_truncate(bs->file->bs, offset + s->cluster_size); if (ret < 0) { goto resize_fail; } - size = bdrv_getlength(bs->file); + size = bdrv_getlength(bs->file->bs); if (size < 0) { ret = size; goto resize_fail; @@ -2091,7 +2094,7 @@ write_refblocks: on_disk_refblock = (void *)((char *) *refcount_table + refblock_index * s->cluster_size); - ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE, + ret = bdrv_write(bs->file->bs, refblock_offset / BDRV_SECTOR_SIZE, on_disk_refblock, s->cluster_sectors); if (ret < 0) { fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret)); @@ -2140,7 +2143,7 @@ write_refblocks: } assert(reftable_size < INT_MAX / sizeof(uint64_t)); - ret = bdrv_pwrite(bs->file, reftable_offset, on_disk_reftable, + ret = bdrv_pwrite(bs->file->bs, reftable_offset, on_disk_reftable, reftable_size * sizeof(uint64_t)); if (ret < 0) { fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret)); @@ -2152,8 +2155,8 @@ write_refblocks: reftable_offset); cpu_to_be32w(&reftable_offset_and_clusters.reftable_clusters, size_to_clusters(s, reftable_size * sizeof(uint64_t))); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, - refcount_table_offset), + ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, + refcount_table_offset), &reftable_offset_and_clusters, sizeof(reftable_offset_and_clusters)); if (ret < 0) { @@ -2191,7 +2194,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, bool rebuild = false; int ret; - size = bdrv_getlength(bs->file); + size = bdrv_getlength(bs->file->bs); if (size < 0) { res->check_errors++; return size; @@ -2400,7 +2403,7 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, return -ENOMEM; } - ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2); + ret = bdrv_pread(bs->file->bs, l1_ofs, l1, l1_sz2); if (ret < 0) { g_free(l1); return ret; diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 92f4dfc083..def720164d 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -64,7 +64,7 @@ int qcow2_read_snapshots(BlockDriverState *bs) for(i = 0; i < s->nb_snapshots; i++) { /* Read statically sized part of the snapshot header */ offset = align_offset(offset, 8); - ret = bdrv_pread(bs->file, offset, &h, sizeof(h)); + ret = bdrv_pread(bs->file->bs, offset, &h, sizeof(h)); if (ret < 0) { goto fail; } @@ -83,7 +83,7 @@ int qcow2_read_snapshots(BlockDriverState *bs) name_size = be16_to_cpu(h.name_size); /* Read extra data */ - ret = bdrv_pread(bs->file, offset, &extra, + ret = bdrv_pread(bs->file->bs, offset, &extra, MIN(sizeof(extra), extra_data_size)); if (ret < 0) { goto fail; @@ -102,7 +102,7 @@ int qcow2_read_snapshots(BlockDriverState *bs) /* Read snapshot ID */ sn->id_str = g_malloc(id_str_size + 1); - ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size); + ret = bdrv_pread(bs->file->bs, offset, sn->id_str, id_str_size); if (ret < 0) { goto fail; } @@ -111,7 +111,7 @@ int qcow2_read_snapshots(BlockDriverState *bs) /* Read snapshot name */ sn->name = g_malloc(name_size + 1); - ret = bdrv_pread(bs->file, offset, sn->name, name_size); + ret = bdrv_pread(bs->file->bs, offset, sn->name, name_size); if (ret < 0) { goto fail; } @@ -214,25 +214,25 @@ static int qcow2_write_snapshots(BlockDriverState *bs) h.name_size = cpu_to_be16(name_size); offset = align_offset(offset, 8); - ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h)); + ret = bdrv_pwrite(bs->file->bs, offset, &h, sizeof(h)); if (ret < 0) { goto fail; } offset += sizeof(h); - ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra)); + ret = bdrv_pwrite(bs->file->bs, offset, &extra, sizeof(extra)); if (ret < 0) { goto fail; } offset += sizeof(extra); - ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size); + ret = bdrv_pwrite(bs->file->bs, offset, sn->id_str, id_str_size); if (ret < 0) { goto fail; } offset += id_str_size; - ret = bdrv_pwrite(bs->file, offset, sn->name, name_size); + ret = bdrv_pwrite(bs->file->bs, offset, sn->name, name_size); if (ret < 0) { goto fail; } @@ -254,7 +254,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs) header_data.nb_snapshots = cpu_to_be32(s->nb_snapshots); header_data.snapshots_offset = cpu_to_be64(snapshots_offset); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots), + ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, nb_snapshots), &header_data, sizeof(header_data)); if (ret < 0) { goto fail; @@ -396,7 +396,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) goto fail; } - ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table, + ret = bdrv_pwrite(bs->file->bs, sn->l1_table_offset, l1_table, s->l1_size * sizeof(uint64_t)); if (ret < 0) { goto fail; @@ -509,7 +509,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto fail; } - ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes); + ret = bdrv_pread(bs->file->bs, sn->l1_table_offset, + sn_l1_table, sn_l1_bytes); if (ret < 0) { goto fail; } @@ -526,7 +527,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto fail; } - ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table, + ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table, cur_l1_bytes); if (ret < 0) { goto fail; @@ -706,13 +707,14 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, return -EFBIG; } new_l1_bytes = sn->l1_size * sizeof(uint64_t); - new_l1_table = qemu_try_blockalign(bs->file, + new_l1_table = qemu_try_blockalign(bs->file->bs, align_offset(new_l1_bytes, 512)); if (new_l1_table == NULL) { return -ENOMEM; } - ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes); + ret = bdrv_pread(bs->file->bs, sn->l1_table_offset, + new_l1_table, new_l1_bytes); if (ret < 0) { error_setg(errp, "Failed to read l1 table for snapshot"); qemu_vfree(new_l1_table); diff --git a/block/qcow2.c b/block/qcow2.c index 56ad808f6b..bacc4f2e11 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -104,7 +104,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, printf("attempting to read extended header in offset %lu\n", offset); #endif - ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext)); + ret = bdrv_pread(bs->file->bs, offset, &ext, sizeof(ext)); if (ret < 0) { error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: " "pread fail from offset %" PRIu64, offset); @@ -132,7 +132,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, sizeof(bs->backing_format)); return 2; } - ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len); + ret = bdrv_pread(bs->file->bs, offset, bs->backing_format, ext.len); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_backing_format: " "Could not read format name"); @@ -148,7 +148,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, case QCOW2_EXT_MAGIC_FEATURE_TABLE: if (p_feature_table != NULL) { void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); - ret = bdrv_pread(bs->file, offset , feature_table, ext.len); + ret = bdrv_pread(bs->file->bs, offset , feature_table, ext.len); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_feature_table: " "Could not read table"); @@ -169,7 +169,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, uext->len = ext.len; QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next); - ret = bdrv_pread(bs->file, offset , uext->data, uext->len); + ret = bdrv_pread(bs->file->bs, offset , uext->data, uext->len); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: unknown extension: " "Could not read data"); @@ -260,12 +260,12 @@ int qcow2_mark_dirty(BlockDriverState *bs) } val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY); - ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, incompatible_features), + ret = bdrv_pwrite(bs->file->bs, offsetof(QCowHeader, incompatible_features), &val, sizeof(val)); if (ret < 0) { return ret; } - ret = bdrv_flush(bs->file); + ret = bdrv_flush(bs->file->bs); if (ret < 0) { return ret; } @@ -828,7 +828,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, uint64_t ext_end; uint64_t l1_vm_state_index; - ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); + ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header)); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read qcow2 header"); goto fail; @@ -903,7 +903,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, if (header.header_length > sizeof(header)) { s->unknown_header_fields_size = header.header_length - sizeof(header); s->unknown_header_fields = g_malloc(s->unknown_header_fields_size); - ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields, + ret = bdrv_pread(bs->file->bs, sizeof(header), s->unknown_header_fields, s->unknown_header_fields_size); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read unknown qcow2 header " @@ -1056,14 +1056,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, if (s->l1_size > 0) { - s->l1_table = qemu_try_blockalign(bs->file, + s->l1_table = qemu_try_blockalign(bs->file->bs, align_offset(s->l1_size * sizeof(uint64_t), 512)); if (s->l1_table == NULL) { error_setg(errp, "Could not allocate L1 table"); ret = -ENOMEM; goto fail; } - ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, + ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read L1 table"); @@ -1082,7 +1082,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, s->cluster_cache = g_malloc(s->cluster_size); /* one more sector for decompressed data alignment */ - s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS + s->cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + 512); if (s->cluster_data == NULL) { error_setg(errp, "Could not allocate temporary cluster buffer"); @@ -1119,7 +1119,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, ret = -EINVAL; goto fail; } - ret = bdrv_pread(bs->file, header.backing_file_offset, + ret = bdrv_pread(bs->file->bs, header.backing_file_offset, bs->backing_file, len); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read backing file name"); @@ -1369,9 +1369,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, switch (ret) { case QCOW2_CLUSTER_UNALLOCATED: - if (bs->backing_hd) { + if (bs->backing) { /* read from the base image */ - n1 = qcow2_backing_read1(bs->backing_hd, &hd_qiov, + n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov, sector_num, cur_nr_sectors); if (n1 > 0) { QEMUIOVector local_qiov; @@ -1382,7 +1382,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_readv(bs->backing_hd, sector_num, + ret = bdrv_co_readv(bs->backing->bs, sector_num, n1, &local_qiov); qemu_co_mutex_lock(&s->lock); @@ -1429,8 +1429,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, */ if (!cluster_data) { cluster_data = - qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS - * s->cluster_size); + qemu_try_blockalign(bs->file->bs, + QCOW_MAX_CRYPT_CLUSTERS + * s->cluster_size); if (cluster_data == NULL) { ret = -ENOMEM; goto fail; @@ -1446,7 +1447,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_readv(bs->file, + ret = bdrv_co_readv(bs->file->bs, (cluster_offset >> 9) + index_in_cluster, cur_nr_sectors, &hd_qiov); qemu_co_mutex_lock(&s->lock); @@ -1543,7 +1544,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, Error *err = NULL; assert(s->cipher); if (!cluster_data) { - cluster_data = qemu_try_blockalign(bs->file, + cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); if (cluster_data == NULL) { @@ -1580,7 +1581,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); trace_qcow2_writev_data(qemu_coroutine_self(), (cluster_offset >> 9) + index_in_cluster); - ret = bdrv_co_writev(bs->file, + ret = bdrv_co_writev(bs->file->bs, (cluster_offset >> 9) + index_in_cluster, cur_nr_sectors, &hd_qiov); qemu_co_mutex_lock(&s->lock); @@ -1703,7 +1704,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) qcow2_close(bs); - bdrv_invalidate_cache(bs->file, &local_err); + bdrv_invalidate_cache(bs->file->bs, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1911,7 +1912,7 @@ int qcow2_update_header(BlockDriverState *bs) } /* Write the new header */ - ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size); + ret = bdrv_pwrite(bs->file->bs, 0, header, s->cluster_size); if (ret < 0) { goto fail; } @@ -1991,7 +1992,8 @@ static int preallocate(BlockDriverState *bs) if (host_offset != 0) { uint8_t buf[BDRV_SECTOR_SIZE]; memset(buf, 0, BDRV_SECTOR_SIZE); - ret = bdrv_write(bs->file, (host_offset >> BDRV_SECTOR_BITS) + num - 1, + ret = bdrv_write(bs->file->bs, + (host_offset >> BDRV_SECTOR_BITS) + num - 1, buf, 1); if (ret < 0) { return ret; @@ -2403,7 +2405,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset) /* write updated header.size */ offset = cpu_to_be64(offset); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), + ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, size), &offset, sizeof(uint64_t)); if (ret < 0) { return ret; @@ -2427,8 +2429,8 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, if (nb_sectors == 0) { /* align end of file to a sector boundary to ease reading with sector based I/Os */ - cluster_offset = bdrv_getlength(bs->file); - return bdrv_truncate(bs->file, cluster_offset); + cluster_offset = bdrv_getlength(bs->file->bs); + return bdrv_truncate(bs->file->bs, cluster_offset); } if (nb_sectors != s->cluster_sectors) { @@ -2495,7 +2497,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, } BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); - ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len); + ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len); if (ret < 0) { goto fail; } @@ -2544,7 +2546,7 @@ static int make_completely_empty(BlockDriverState *bs) /* After this call, neither the in-memory nor the on-disk refcount * information accurately describe the actual references */ - ret = bdrv_write_zeroes(bs->file, s->l1_table_offset / BDRV_SECTOR_SIZE, + ret = bdrv_write_zeroes(bs->file->bs, s->l1_table_offset / BDRV_SECTOR_SIZE, l1_clusters * s->cluster_sectors, 0); if (ret < 0) { goto fail_broken_refcounts; @@ -2558,7 +2560,7 @@ static int make_completely_empty(BlockDriverState *bs) * overwrite parts of the existing refcount and L1 table, which is not * an issue because the dirty flag is set, complete data loss is in fact * desired and partial data loss is consequently fine as well */ - ret = bdrv_write_zeroes(bs->file, s->cluster_size / BDRV_SECTOR_SIZE, + ret = bdrv_write_zeroes(bs->file->bs, s->cluster_size / BDRV_SECTOR_SIZE, (2 + l1_clusters) * s->cluster_size / BDRV_SECTOR_SIZE, 0); /* This call (even if it failed overall) may have overwritten on-disk @@ -2578,7 +2580,7 @@ static int make_completely_empty(BlockDriverState *bs) cpu_to_be64w(&l1_ofs_rt_ofs_cls.l1_offset, 3 * s->cluster_size); cpu_to_be64w(&l1_ofs_rt_ofs_cls.reftable_offset, s->cluster_size); cpu_to_be32w(&l1_ofs_rt_ofs_cls.reftable_clusters, 1); - ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_table_offset), + ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_table_offset), &l1_ofs_rt_ofs_cls, sizeof(l1_ofs_rt_ofs_cls)); if (ret < 0) { goto fail_broken_refcounts; @@ -2609,7 +2611,7 @@ static int make_completely_empty(BlockDriverState *bs) /* Enter the first refblock into the reftable */ rt_entry = cpu_to_be64(2 * s->cluster_size); - ret = bdrv_pwrite_sync(bs->file, s->cluster_size, + ret = bdrv_pwrite_sync(bs->file->bs, s->cluster_size, &rt_entry, sizeof(rt_entry)); if (ret < 0) { goto fail_broken_refcounts; @@ -2634,7 +2636,7 @@ static int make_completely_empty(BlockDriverState *bs) goto fail; } - ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size); + ret = bdrv_truncate(bs->file->bs, (3 + l1_clusters) * s->cluster_size); if (ret < 0) { goto fail; } @@ -2769,7 +2771,7 @@ static void dump_refcounts(BlockDriverState *bs) int64_t nb_clusters, k, k1, size; int refcount; - size = bdrv_getlength(bs->file); + size = bdrv_getlength(bs->file->bs); nb_clusters = size_to_clusters(s, size); for(k = 0; k < nb_clusters;) { k1 = k; diff --git a/block/qcow2.h b/block/qcow2.h index d700bf1b62..b8c500b9dc 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -26,7 +26,7 @@ #define BLOCK_QCOW2_H #include "crypto/cipher.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 @@ -295,8 +295,6 @@ typedef struct BDRVQcow2State { char *image_backing_format; } BDRVQcow2State; -struct QCowAIOCB; - typedef struct Qcow2COWRegion { /** * Offset of the COW region in bytes from the start of the first cluster diff --git a/block/qed-table.c b/block/qed-table.c index 513aa872c9..f4219b8acc 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -63,7 +63,7 @@ static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table, read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size, qemu_iovec_init_external(qiov, &read_table_cb->iov, 1); - bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov, + bdrv_aio_readv(s->bs->file->bs, offset / BDRV_SECTOR_SIZE, qiov, qiov->size / BDRV_SECTOR_SIZE, qed_read_table_cb, read_table_cb); } @@ -152,7 +152,7 @@ static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table, /* Adjust for offset into table */ offset += start * sizeof(uint64_t); - bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE, + bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE, &write_table_cb->qiov, write_table_cb->qiov.size / BDRV_SECTOR_SIZE, qed_write_table_cb, write_table_cb); diff --git a/block/qed.c b/block/qed.c index a7ff1d9c41..5ea05d4909 100644 --- a/block/qed.c +++ b/block/qed.c @@ -82,7 +82,7 @@ int qed_write_header_sync(BDRVQEDState *s) int ret; qed_header_cpu_to_le(&s->header, &le); - ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le)); + ret = bdrv_pwrite(s->bs->file->bs, 0, &le, sizeof(le)); if (ret != sizeof(le)) { return ret; } @@ -119,7 +119,7 @@ static void qed_write_header_read_cb(void *opaque, int ret) /* Update header */ qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf); - bdrv_aio_writev(s->bs->file, 0, &write_header_cb->qiov, + bdrv_aio_writev(s->bs->file->bs, 0, &write_header_cb->qiov, write_header_cb->nsectors, qed_write_header_cb, write_header_cb); } @@ -152,7 +152,7 @@ static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb, write_header_cb->iov.iov_len = len; qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1); - bdrv_aio_readv(s->bs->file, 0, &write_header_cb->qiov, nsectors, + bdrv_aio_readv(s->bs->file->bs, 0, &write_header_cb->qiov, nsectors, qed_write_header_read_cb, write_header_cb); } @@ -354,12 +354,6 @@ static void qed_cancel_need_check_timer(BDRVQEDState *s) timer_del(s->need_check_timer); } -static void bdrv_qed_rebind(BlockDriverState *bs) -{ - BDRVQEDState *s = bs->opaque; - s->bs = bs; -} - static void bdrv_qed_detach_aio_context(BlockDriverState *bs) { BDRVQEDState *s = bs->opaque; @@ -392,7 +386,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, s->bs = bs; QSIMPLEQ_INIT(&s->allocating_write_reqs); - ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header)); + ret = bdrv_pread(bs->file->bs, 0, &le_header, sizeof(le_header)); if (ret < 0) { return ret; } @@ -416,7 +410,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, } /* Round down file size to the last cluster */ - file_size = bdrv_getlength(bs->file); + file_size = bdrv_getlength(bs->file->bs); if (file_size < 0) { return file_size; } @@ -452,7 +446,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, return -EINVAL; } - ret = qed_read_string(bs->file, s->header.backing_filename_offset, + ret = qed_read_string(bs->file->bs, s->header.backing_filename_offset, s->header.backing_filename_size, bs->backing_file, sizeof(bs->backing_file)); if (ret < 0) { @@ -471,7 +465,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, * feature is no longer valid. */ if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 && - !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) { + !bdrv_is_read_only(bs->file->bs) && !(flags & BDRV_O_INCOMING)) { s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK; ret = qed_write_header_sync(s); @@ -480,7 +474,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, } /* From here on only known autoclear feature bits are valid */ - bdrv_flush(bs->file); + bdrv_flush(bs->file->bs); } s->l1_table = qed_alloc_table(s); @@ -498,7 +492,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, * potentially inconsistent images to be opened read-only. This can * aid data recovery from an otherwise inconsistent image. */ - if (!bdrv_is_read_only(bs->file) && + if (!bdrv_is_read_only(bs->file->bs) && !(flags & BDRV_O_INCOMING)) { BdrvCheckResult result = {0}; @@ -541,7 +535,7 @@ static void bdrv_qed_close(BlockDriverState *bs) bdrv_qed_detach_aio_context(bs); /* Ensure writes reach stable storage */ - bdrv_flush(bs->file); + bdrv_flush(bs->file->bs); /* Clean shutdown, no check required on next open */ if (s->header.features & QED_F_NEED_CHECK) { @@ -772,8 +766,8 @@ static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos, /* If there is a backing file, get its length. Treat the absence of a * backing file like a zero length backing file. */ - if (s->bs->backing_hd) { - int64_t l = bdrv_getlength(s->bs->backing_hd); + if (s->bs->backing) { + int64_t l = bdrv_getlength(s->bs->backing->bs); if (l < 0) { cb(opaque, l); return; @@ -802,7 +796,7 @@ static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos, qemu_iovec_concat(*backing_qiov, qiov, 0, size); BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO); - bdrv_aio_readv(s->bs->backing_hd, pos / BDRV_SECTOR_SIZE, + bdrv_aio_readv(s->bs->backing->bs, pos / BDRV_SECTOR_SIZE, *backing_qiov, size / BDRV_SECTOR_SIZE, cb, opaque); } @@ -839,7 +833,7 @@ static void qed_copy_from_backing_file_write(void *opaque, int ret) } BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE); - bdrv_aio_writev(s->bs->file, copy_cb->offset / BDRV_SECTOR_SIZE, + bdrv_aio_writev(s->bs->file->bs, copy_cb->offset / BDRV_SECTOR_SIZE, ©_cb->qiov, copy_cb->qiov.size / BDRV_SECTOR_SIZE, qed_copy_from_backing_file_cb, copy_cb); } @@ -1055,7 +1049,7 @@ static void qed_aio_write_flush_before_l2_update(void *opaque, int ret) QEDAIOCB *acb = opaque; BDRVQEDState *s = acb_to_s(acb); - if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update_cb, opaque)) { + if (!bdrv_aio_flush(s->bs->file->bs, qed_aio_write_l2_update_cb, opaque)) { qed_aio_complete(acb, -EIO); } } @@ -1081,7 +1075,7 @@ static void qed_aio_write_main(void *opaque, int ret) if (acb->find_cluster_ret == QED_CLUSTER_FOUND) { next_fn = qed_aio_next_io; } else { - if (s->bs->backing_hd) { + if (s->bs->backing) { next_fn = qed_aio_write_flush_before_l2_update; } else { next_fn = qed_aio_write_l2_update_cb; @@ -1089,7 +1083,7 @@ static void qed_aio_write_main(void *opaque, int ret) } BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO); - bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE, + bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE, &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE, next_fn, acb); } @@ -1139,7 +1133,7 @@ static void qed_aio_write_prefill(void *opaque, int ret) static bool qed_should_set_need_check(BDRVQEDState *s) { /* The flush before L2 update path ensures consistency */ - if (s->bs->backing_hd) { + if (s->bs->backing) { return false; } @@ -1321,7 +1315,7 @@ static void qed_aio_read_data(void *opaque, int ret, } BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); - bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE, + bdrv_aio_readv(bs->file->bs, offset / BDRV_SECTOR_SIZE, &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE, qed_aio_next_io, acb); return; @@ -1443,7 +1437,7 @@ static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs, struct iovec iov; /* Refuse if there are untouched backing file sectors */ - if (bs->backing_hd) { + if (bs->backing) { if (qed_offset_into_cluster(s, sector_num * BDRV_SECTOR_SIZE) != 0) { return -ENOTSUP; } @@ -1580,7 +1574,7 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs, } /* Write new header */ - ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len); + ret = bdrv_pwrite_sync(bs->file->bs, 0, buffer, buffer_len); g_free(buffer); if (ret == 0) { memcpy(&s->header, &new_header, sizeof(new_header)); @@ -1596,7 +1590,7 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp) bdrv_qed_close(bs); - bdrv_invalidate_cache(bs->file, &local_err); + bdrv_invalidate_cache(bs->file->bs, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1664,7 +1658,6 @@ static BlockDriver bdrv_qed = { .supports_backing = true, .bdrv_probe = bdrv_qed_probe, - .bdrv_rebind = bdrv_qed_rebind, .bdrv_open = bdrv_qed_open, .bdrv_close = bdrv_qed_close, .bdrv_reopen_prepare = bdrv_qed_reopen_prepare, diff --git a/block/quorum.c b/block/quorum.c index 8fe53b4272..b9ba028d46 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -64,7 +64,7 @@ typedef struct QuorumVotes { /* the following structure holds the state of one quorum instance */ typedef struct BDRVQuorumState { - BlockDriverState **bs; /* children BlockDriverStates */ + BdrvChild **children; /* children BlockDriverStates */ int num_children; /* children count */ int threshold; /* if less than threshold children reads gave the * same result a quorum error occurs. @@ -336,7 +336,7 @@ static void quorum_report_bad_versions(BDRVQuorumState *s, continue; } QLIST_FOREACH(item, &version->items, next) { - quorum_report_bad(acb, s->bs[item->index]->node_name, 0); + quorum_report_bad(acb, s->children[item->index]->bs->node_name, 0); } } } @@ -369,8 +369,9 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb, continue; } QLIST_FOREACH(item, &version->items, next) { - bdrv_aio_writev(s->bs[item->index], acb->sector_num, acb->qiov, - acb->nb_sectors, quorum_rewrite_aio_cb, acb); + bdrv_aio_writev(s->children[item->index]->bs, acb->sector_num, + acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb, + acb); } } @@ -639,13 +640,13 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb) int i; for (i = 0; i < s->num_children; i++) { - acb->qcrs[i].buf = qemu_blockalign(s->bs[i], acb->qiov->size); + acb->qcrs[i].buf = qemu_blockalign(s->children[i]->bs, acb->qiov->size); qemu_iovec_init(&acb->qcrs[i].qiov, acb->qiov->niov); qemu_iovec_clone(&acb->qcrs[i].qiov, acb->qiov, acb->qcrs[i].buf); } for (i = 0; i < s->num_children; i++) { - bdrv_aio_readv(s->bs[i], acb->sector_num, &acb->qcrs[i].qiov, + bdrv_aio_readv(s->children[i]->bs, acb->sector_num, &acb->qcrs[i].qiov, acb->nb_sectors, quorum_aio_cb, &acb->qcrs[i]); } @@ -656,12 +657,12 @@ static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb) { BDRVQuorumState *s = acb->common.bs->opaque; - acb->qcrs[acb->child_iter].buf = qemu_blockalign(s->bs[acb->child_iter], - acb->qiov->size); + acb->qcrs[acb->child_iter].buf = + qemu_blockalign(s->children[acb->child_iter]->bs, acb->qiov->size); qemu_iovec_init(&acb->qcrs[acb->child_iter].qiov, acb->qiov->niov); qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov, acb->qcrs[acb->child_iter].buf); - bdrv_aio_readv(s->bs[acb->child_iter], acb->sector_num, + bdrv_aio_readv(s->children[acb->child_iter]->bs, acb->sector_num, &acb->qcrs[acb->child_iter].qiov, acb->nb_sectors, quorum_aio_cb, &acb->qcrs[acb->child_iter]); @@ -702,8 +703,8 @@ static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs, int i; for (i = 0; i < s->num_children; i++) { - acb->qcrs[i].aiocb = bdrv_aio_writev(s->bs[i], sector_num, qiov, - nb_sectors, &quorum_aio_cb, + acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i]->bs, sector_num, + qiov, nb_sectors, &quorum_aio_cb, &acb->qcrs[i]); } @@ -717,12 +718,12 @@ static int64_t quorum_getlength(BlockDriverState *bs) int i; /* check that all file have the same length */ - result = bdrv_getlength(s->bs[0]); + result = bdrv_getlength(s->children[0]->bs); if (result < 0) { return result; } for (i = 1; i < s->num_children; i++) { - int64_t value = bdrv_getlength(s->bs[i]); + int64_t value = bdrv_getlength(s->children[i]->bs); if (value < 0) { return value; } @@ -741,7 +742,7 @@ static void quorum_invalidate_cache(BlockDriverState *bs, Error **errp) int i; for (i = 0; i < s->num_children; i++) { - bdrv_invalidate_cache(s->bs[i], &local_err); + bdrv_invalidate_cache(s->children[i]->bs, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -762,7 +763,7 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs) error_votes.compare = quorum_64bits_compare; for (i = 0; i < s->num_children; i++) { - result = bdrv_co_flush(s->bs[i]); + result = bdrv_co_flush(s->children[i]->bs); result_value.l = result; quorum_count_vote(&error_votes, &result_value, i); } @@ -782,7 +783,7 @@ static bool quorum_recurse_is_first_non_filter(BlockDriverState *bs, int i; for (i = 0; i < s->num_children; i++) { - bool perm = bdrv_recurse_is_first_non_filter(s->bs[i], + bool perm = bdrv_recurse_is_first_non_filter(s->children[i]->bs, candidate); if (perm) { return true; @@ -922,8 +923,8 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, } } - /* allocate the children BlockDriverState array */ - s->bs = g_new0(BlockDriverState *, s->num_children); + /* allocate the children array */ + s->children = g_new0(BdrvChild *, s->num_children); opened = g_new0(bool, s->num_children); for (i = 0; i < s->num_children; i++) { @@ -931,9 +932,10 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, ret = snprintf(indexstr, 32, "children.%d", i); assert(ret < 32); - ret = bdrv_open_image(&s->bs[i], NULL, options, indexstr, bs, - &child_format, false, &local_err); - if (ret < 0) { + s->children[i] = bdrv_open_child(NULL, options, indexstr, bs, + &child_format, false, &local_err); + if (local_err) { + ret = -EINVAL; goto close_exit; } @@ -949,9 +951,9 @@ close_exit: if (!opened[i]) { continue; } - bdrv_unref(s->bs[i]); + bdrv_unref_child(bs, s->children[i]); } - g_free(s->bs); + g_free(s->children); g_free(opened); exit: qemu_opts_del(opts); @@ -968,10 +970,10 @@ static void quorum_close(BlockDriverState *bs) int i; for (i = 0; i < s->num_children; i++) { - bdrv_unref(s->bs[i]); + bdrv_unref_child(bs, s->children[i]); } - g_free(s->bs); + g_free(s->children); } static void quorum_detach_aio_context(BlockDriverState *bs) @@ -980,7 +982,7 @@ static void quorum_detach_aio_context(BlockDriverState *bs) int i; for (i = 0; i < s->num_children; i++) { - bdrv_detach_aio_context(s->bs[i]); + bdrv_detach_aio_context(s->children[i]->bs); } } @@ -991,7 +993,7 @@ static void quorum_attach_aio_context(BlockDriverState *bs, int i; for (i = 0; i < s->num_children; i++) { - bdrv_attach_aio_context(s->bs[i], new_context); + bdrv_attach_aio_context(s->children[i]->bs, new_context); } } @@ -1003,16 +1005,17 @@ static void quorum_refresh_filename(BlockDriverState *bs) int i; for (i = 0; i < s->num_children; i++) { - bdrv_refresh_filename(s->bs[i]); - if (!s->bs[i]->full_open_options) { + bdrv_refresh_filename(s->children[i]->bs); + if (!s->children[i]->bs->full_open_options) { return; } } children = qlist_new(); for (i = 0; i < s->num_children; i++) { - QINCREF(s->bs[i]->full_open_options); - qlist_append_obj(children, QOBJECT(s->bs[i]->full_open_options)); + QINCREF(s->children[i]->bs->full_open_options); + qlist_append_obj(children, + QOBJECT(s->children[i]->bs->full_open_options)); } opts = qdict_new(); diff --git a/block/raw-posix.c b/block/raw-posix.c index cc1b8743ac..3a527f0b6b 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -519,7 +519,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, "future QEMU versions.\n", bs->filename); } -#endif +#else + if (bdrv_flags & BDRV_O_NATIVE_AIO) { + error_printf("WARNING: aio=native was specified for '%s', but " + "is not supported in this build. Falling back to " + "aio=threads.\n" + " This will become an error condition in " + "future QEMU versions.\n", + bs->filename); + } +#endif /* !defined(CONFIG_LINUX_AIO) */ s->has_discard = true; s->has_write_zeroes = true; diff --git a/block/raw_bsd.c b/block/raw_bsd.c index e3d2d04681..63ee91164f 100644 --- a/block/raw_bsd.c +++ b/block/raw_bsd.c @@ -52,7 +52,7 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) { BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); - return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov); + return bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov); } static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num, @@ -75,7 +75,7 @@ static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num, return 0; } - buf = qemu_try_blockalign(bs->file, 512); + buf = qemu_try_blockalign(bs->file->bs, 512); if (!buf) { ret = -ENOMEM; goto fail; @@ -102,7 +102,7 @@ static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num, } BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); - ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov); + ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov); fail: if (qiov == &local_qiov) { @@ -125,58 +125,58 @@ static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) { - return bdrv_co_write_zeroes(bs->file, sector_num, nb_sectors, flags); + return bdrv_co_write_zeroes(bs->file->bs, sector_num, nb_sectors, flags); } static int coroutine_fn raw_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { - return bdrv_co_discard(bs->file, sector_num, nb_sectors); + return bdrv_co_discard(bs->file->bs, sector_num, nb_sectors); } static int64_t raw_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file); + return bdrv_getlength(bs->file->bs); } static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { - return bdrv_get_info(bs->file, bdi); + return bdrv_get_info(bs->file->bs, bdi); } static void raw_refresh_limits(BlockDriverState *bs, Error **errp) { - bs->bl = bs->file->bl; + bs->bl = bs->file->bs->bl; } static int raw_truncate(BlockDriverState *bs, int64_t offset) { - return bdrv_truncate(bs->file, offset); + return bdrv_truncate(bs->file->bs, offset); } static int raw_is_inserted(BlockDriverState *bs) { - return bdrv_is_inserted(bs->file); + return bdrv_is_inserted(bs->file->bs); } static int raw_media_changed(BlockDriverState *bs) { - return bdrv_media_changed(bs->file); + return bdrv_media_changed(bs->file->bs); } static void raw_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file, eject_flag); + bdrv_eject(bs->file->bs, eject_flag); } static void raw_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file, locked); + bdrv_lock_medium(bs->file->bs, locked); } static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) { - return bdrv_ioctl(bs->file, req, buf); + return bdrv_ioctl(bs->file->bs, req, buf); } static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs, @@ -184,12 +184,12 @@ static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque) { - return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque); + return bdrv_aio_ioctl(bs->file->bs, req, buf, cb, opaque); } static int raw_has_zero_init(BlockDriverState *bs) { - return bdrv_has_zero_init(bs->file); + return bdrv_has_zero_init(bs->file->bs); } static int raw_create(const char *filename, QemuOpts *opts, Error **errp) @@ -207,7 +207,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp) static int raw_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->sg = bs->file->sg; + bs->sg = bs->file->bs->sg; if (bs->probed && !bdrv_is_read_only(bs)) { fprintf(stderr, @@ -217,7 +217,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, "raw images, write operations on block 0 will be restricted.\n" " Specify the 'raw' format explicitly to remove the " "restrictions.\n", - bs->file->filename); + bs->file->bs->filename); } return 0; @@ -237,12 +237,12 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz) { - return bdrv_probe_blocksizes(bs->file, bsz); + return bdrv_probe_blocksizes(bs->file->bs, bsz); } static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo) { - return bdrv_probe_geometry(bs->file, geo); + return bdrv_probe_geometry(bs->file->bs, geo); } BlockDriver bdrv_raw = { diff --git a/block/snapshot.c b/block/snapshot.c index 49e143e991..89500f2f18 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -149,7 +149,7 @@ int bdrv_can_snapshot(BlockDriverState *bs) if (!drv->bdrv_snapshot_create) { if (bs->file != NULL) { - return bdrv_can_snapshot(bs->file); + return bdrv_can_snapshot(bs->file->bs); } return 0; } @@ -168,7 +168,7 @@ int bdrv_snapshot_create(BlockDriverState *bs, return drv->bdrv_snapshot_create(bs, sn_info); } if (bs->file) { - return bdrv_snapshot_create(bs->file, sn_info); + return bdrv_snapshot_create(bs->file->bs, sn_info); } return -ENOTSUP; } @@ -188,10 +188,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs, if (bs->file) { drv->bdrv_close(bs); - ret = bdrv_snapshot_goto(bs->file, snapshot_id); + ret = bdrv_snapshot_goto(bs->file->bs, snapshot_id); open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL); if (open_ret < 0) { - bdrv_unref(bs->file); + bdrv_unref(bs->file->bs); bs->drv = NULL; return open_ret; } @@ -245,7 +245,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp); } if (bs->file) { - return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp); + return bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp); } error_setg(errp, "Block format '%s' used by device '%s' " "does not support internal snapshot deletion", @@ -283,7 +283,7 @@ int bdrv_snapshot_list(BlockDriverState *bs, return drv->bdrv_snapshot_list(bs, psn_info); } if (bs->file) { - return bdrv_snapshot_list(bs->file, psn_info); + return bdrv_snapshot_list(bs->file->bs, psn_info); } return -ENOTSUP; } diff --git a/block/stream.c b/block/stream.c index ab0bd057f7..3f64fa2245 100644 --- a/block/stream.c +++ b/block/stream.c @@ -52,34 +52,6 @@ static int coroutine_fn stream_populate(BlockDriverState *bs, return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov); } -static void close_unused_images(BlockDriverState *top, BlockDriverState *base, - const char *base_id) -{ - BlockDriverState *intermediate; - intermediate = top->backing_hd; - - /* Must assign before bdrv_delete() to prevent traversing dangling pointer - * while we delete backing image instances. - */ - bdrv_set_backing_hd(top, base); - - while (intermediate) { - BlockDriverState *unused; - - /* reached base */ - if (intermediate == base) { - break; - } - - unused = intermediate; - intermediate = intermediate->backing_hd; - bdrv_set_backing_hd(unused, NULL); - bdrv_unref(unused); - } - - bdrv_refresh_limits(top, NULL); -} - typedef struct { int ret; bool reached_end; @@ -101,7 +73,7 @@ static void stream_complete(BlockJob *job, void *opaque) } } data->ret = bdrv_change_backing_file(job->bs, base_id, base_fmt); - close_unused_images(job->bs, base, base_id); + bdrv_set_backing_hd(job->bs, base); } g_free(s->backing_file_str); @@ -121,7 +93,7 @@ static void coroutine_fn stream_run(void *opaque) int n = 0; void *buf; - if (!bs->backing_hd) { + if (!bs->backing) { block_job_completed(&s->common, 0); return; } @@ -166,7 +138,7 @@ wait: } else if (ret >= 0) { /* Copy if allocated in the intermediate images. Limit to the * known-unallocated area [sector_num, sector_num+n). */ - ret = bdrv_is_allocated_above(bs->backing_hd, base, + ret = bdrv_is_allocated_above(backing_bs(bs), base, sector_num, n, &n); /* Finish early if end of backing file has been reached */ diff --git a/block/vdi.c b/block/vdi.c index 062a6541f8..17f435fad6 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -53,7 +53,7 @@ #include "block/block_int.h" #include "qemu/module.h" #include "migration/migration.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #if defined(CONFIG_UUID) #include <uuid/uuid.h> @@ -399,7 +399,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, logout("\n"); - ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1); + ret = bdrv_read(bs->file->bs, 0, (uint8_t *)&header, 1); if (ret < 0) { goto fail; } @@ -490,13 +490,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, bmap_size = header.blocks_in_image * sizeof(uint32_t); bmap_size = DIV_ROUND_UP(bmap_size, SECTOR_SIZE); - s->bmap = qemu_try_blockalign(bs->file, bmap_size * SECTOR_SIZE); + s->bmap = qemu_try_blockalign(bs->file->bs, bmap_size * SECTOR_SIZE); if (s->bmap == NULL) { ret = -ENOMEM; goto fail; } - ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size); + ret = bdrv_read(bs->file->bs, s->bmap_sector, (uint8_t *)s->bmap, + bmap_size); if (ret < 0) { goto fail_free_bmap; } @@ -585,7 +586,7 @@ static int vdi_co_read(BlockDriverState *bs, uint64_t offset = s->header.offset_data / SECTOR_SIZE + (uint64_t)bmap_entry * s->block_sectors + sector_in_block; - ret = bdrv_read(bs->file, offset, buf, n_sectors); + ret = bdrv_read(bs->file->bs, offset, buf, n_sectors); } logout("%u sectors read\n", n_sectors); @@ -653,7 +654,7 @@ static int vdi_co_write(BlockDriverState *bs, * acquire the lock and thus the padded cluster is written before * the other coroutines can write to the affected area. */ qemu_co_mutex_lock(&s->write_lock); - ret = bdrv_write(bs->file, offset, block, s->block_sectors); + ret = bdrv_write(bs->file->bs, offset, block, s->block_sectors); qemu_co_mutex_unlock(&s->write_lock); } else { uint64_t offset = s->header.offset_data / SECTOR_SIZE + @@ -669,7 +670,7 @@ static int vdi_co_write(BlockDriverState *bs, * that that write operation has returned (there may be other writes * in flight, but they do not concern this very operation). */ qemu_co_mutex_unlock(&s->write_lock); - ret = bdrv_write(bs->file, offset, buf, n_sectors); + ret = bdrv_write(bs->file->bs, offset, buf, n_sectors); } nb_sectors -= n_sectors; @@ -694,7 +695,7 @@ static int vdi_co_write(BlockDriverState *bs, assert(VDI_IS_ALLOCATED(bmap_first)); *header = s->header; vdi_header_to_le(header); - ret = bdrv_write(bs->file, 0, block, 1); + ret = bdrv_write(bs->file->bs, 0, block, 1); g_free(block); block = NULL; @@ -712,7 +713,7 @@ static int vdi_co_write(BlockDriverState *bs, base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; logout("will write %u block map sectors starting from entry %u\n", n_sectors, bmap_first); - ret = bdrv_write(bs->file, offset, base, n_sectors); + ret = bdrv_write(bs->file->bs, offset, base, n_sectors); } return ret; diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 47fec63c61..47ae4b1351 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -81,7 +81,7 @@ static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log, offset = log->offset + read; - ret = bdrv_pread(bs->file, offset, hdr, sizeof(VHDXLogEntryHeader)); + ret = bdrv_pread(bs->file->bs, offset, hdr, sizeof(VHDXLogEntryHeader)); if (ret < 0) { goto exit; } @@ -141,7 +141,7 @@ static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log, } offset = log->offset + read; - ret = bdrv_pread(bs->file, offset, buffer, VHDX_LOG_SECTOR_SIZE); + ret = bdrv_pread(bs->file->bs, offset, buffer, VHDX_LOG_SECTOR_SIZE); if (ret < 0) { goto exit; } @@ -191,7 +191,8 @@ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log, /* full */ break; } - ret = bdrv_pwrite(bs->file, offset, buffer_tmp, VHDX_LOG_SECTOR_SIZE); + ret = bdrv_pwrite(bs->file->bs, offset, buffer_tmp, + VHDX_LOG_SECTOR_SIZE); if (ret < 0) { goto exit; } @@ -353,7 +354,7 @@ static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s, } desc_sectors = vhdx_compute_desc_sectors(hdr.descriptor_count); - desc_entries = qemu_try_blockalign(bs->file, + desc_entries = qemu_try_blockalign(bs->file->bs, desc_sectors * VHDX_LOG_SECTOR_SIZE); if (desc_entries == NULL) { ret = -ENOMEM; @@ -462,7 +463,7 @@ static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc, /* count is only > 1 if we are writing zeroes */ for (i = 0; i < count; i++) { - ret = bdrv_pwrite_sync(bs->file, file_offset, buffer, + ret = bdrv_pwrite_sync(bs->file->bs, file_offset, buffer, VHDX_LOG_SECTOR_SIZE); if (ret < 0) { goto exit; @@ -509,7 +510,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, /* if the log shows a FlushedFileOffset larger than our current file * size, then that means the file has been truncated / corrupted, and * we must refused to open it / use it */ - if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file)) { + if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file->bs)) { ret = -EINVAL; goto exit; } @@ -539,12 +540,12 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, goto exit; } } - if (bdrv_getlength(bs->file) < desc_entries->hdr.last_file_offset) { + if (bdrv_getlength(bs->file->bs) < desc_entries->hdr.last_file_offset) { new_file_size = desc_entries->hdr.last_file_offset; if (new_file_size % (1024*1024)) { /* round up to nearest 1MB boundary */ new_file_size = ((new_file_size >> 20) + 1) << 20; - bdrv_truncate(bs->file, new_file_size); + bdrv_truncate(bs->file->bs, new_file_size); } } qemu_vfree(desc_entries); @@ -908,8 +909,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s, .sequence_number = s->log.sequence, .descriptor_count = sectors, .reserved = 0, - .flushed_file_offset = bdrv_getlength(bs->file), - .last_file_offset = bdrv_getlength(bs->file), + .flushed_file_offset = bdrv_getlength(bs->file->bs), + .last_file_offset = bdrv_getlength(bs->file->bs), }; new_hdr.log_guid = header->log_guid; @@ -940,7 +941,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s, if (i == 0 && leading_length) { /* partial sector at the front of the buffer */ - ret = bdrv_pread(bs->file, file_offset, merged_sector, + ret = bdrv_pread(bs->file->bs, file_offset, merged_sector, VHDX_LOG_SECTOR_SIZE); if (ret < 0) { goto exit; @@ -950,7 +951,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s, sector_write = merged_sector; } else if (i == sectors - 1 && trailing_length) { /* partial sector at the end of the buffer */ - ret = bdrv_pread(bs->file, + ret = bdrv_pread(bs->file->bs, file_offset, merged_sector + trailing_length, VHDX_LOG_SECTOR_SIZE - trailing_length); diff --git a/block/vhdx.c b/block/vhdx.c index d3bb1bd9d0..2fe9a5e0cf 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -375,7 +375,7 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, inactive_header->log_guid = *log_guid; } - ret = vhdx_write_header(bs->file, inactive_header, header_offset, true); + ret = vhdx_write_header(bs->file->bs, inactive_header, header_offset, true); if (ret < 0) { goto exit; } @@ -427,7 +427,8 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s, /* We have to read the whole VHDX_HEADER_SIZE instead of * sizeof(VHDXHeader), because the checksum is over the whole * region */ - ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer, VHDX_HEADER_SIZE); + ret = bdrv_pread(bs->file->bs, VHDX_HEADER1_OFFSET, buffer, + VHDX_HEADER_SIZE); if (ret < 0) { goto fail; } @@ -443,7 +444,8 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s, } } - ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, VHDX_HEADER_SIZE); + ret = bdrv_pread(bs->file->bs, VHDX_HEADER2_OFFSET, buffer, + VHDX_HEADER_SIZE); if (ret < 0) { goto fail; } @@ -516,7 +518,7 @@ static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s) * whole block */ buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE); - ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, buffer, + ret = bdrv_pread(bs->file->bs, VHDX_REGION_TABLE_OFFSET, buffer, VHDX_HEADER_BLOCK_SIZE); if (ret < 0) { goto fail; @@ -629,7 +631,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE); - ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, buffer, + ret = bdrv_pread(bs->file->bs, s->metadata_rt.file_offset, buffer, VHDX_METADATA_TABLE_MAX_SIZE); if (ret < 0) { goto exit; @@ -732,7 +734,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) goto exit; } - ret = bdrv_pread(bs->file, + ret = bdrv_pread(bs->file->bs, s->metadata_entries.file_parameters_entry.offset + s->metadata_rt.file_offset, &s->params, @@ -767,7 +769,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) /* determine virtual disk size, logical sector size, * and phys sector size */ - ret = bdrv_pread(bs->file, + ret = bdrv_pread(bs->file->bs, s->metadata_entries.virtual_disk_size_entry.offset + s->metadata_rt.file_offset, &s->virtual_disk_size, @@ -775,7 +777,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) if (ret < 0) { goto exit; } - ret = bdrv_pread(bs->file, + ret = bdrv_pread(bs->file->bs, s->metadata_entries.logical_sector_size_entry.offset + s->metadata_rt.file_offset, &s->logical_sector_size, @@ -783,7 +785,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s) if (ret < 0) { goto exit; } - ret = bdrv_pread(bs->file, + ret = bdrv_pread(bs->file->bs, s->metadata_entries.phys_sector_size_entry.offset + s->metadata_rt.file_offset, &s->physical_sector_size, @@ -906,7 +908,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, QLIST_INIT(&s->regions); /* validate the file signature */ - ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t)); + ret = bdrv_pread(bs->file->bs, 0, &signature, sizeof(uint64_t)); if (ret < 0) { goto fail; } @@ -959,13 +961,13 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, } /* s->bat is freed in vhdx_close() */ - s->bat = qemu_try_blockalign(bs->file, s->bat_rt.length); + s->bat = qemu_try_blockalign(bs->file->bs, s->bat_rt.length); if (s->bat == NULL) { ret = -ENOMEM; goto fail; } - ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length); + ret = bdrv_pread(bs->file->bs, s->bat_offset, s->bat, s->bat_rt.length); if (ret < 0) { goto fail; } @@ -1118,7 +1120,7 @@ static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, break; case PAYLOAD_BLOCK_FULLY_PRESENT: qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_readv(bs->file, + ret = bdrv_co_readv(bs->file->bs, sinfo.file_offset >> BDRV_SECTOR_BITS, sinfo.sectors_avail, &hd_qiov); qemu_co_mutex_lock(&s->lock); @@ -1156,12 +1158,12 @@ exit: static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, uint64_t *new_offset) { - *new_offset = bdrv_getlength(bs->file); + *new_offset = bdrv_getlength(bs->file->bs); /* per the spec, the address for a block is in units of 1MB */ *new_offset = ROUND_UP(*new_offset, 1024 * 1024); - return bdrv_truncate(bs->file, *new_offset + s->block_size); + return bdrv_truncate(bs->file->bs, *new_offset + s->block_size); } /* @@ -1260,7 +1262,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, /* Queue another write of zero buffers if the underlying file * does not zero-fill on file extension */ - if (bdrv_has_zero_init(bs->file) == 0) { + if (bdrv_has_zero_init(bs->file->bs) == 0) { use_zero_buffers = true; /* zero fill the front, if any */ @@ -1327,7 +1329,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, } /* block exists, so we can just overwrite it */ qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_writev(bs->file, + ret = bdrv_co_writev(bs->file->bs, sinfo.file_offset >> BDRV_SECTOR_BITS, sectors_to_write, &hd_qiov); qemu_co_mutex_lock(&s->lock); diff --git a/block/vmdk.c b/block/vmdk.c index be0d6401af..0effb7d91c 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -87,7 +87,7 @@ typedef struct { #define L2_CACHE_SIZE 16 typedef struct VmdkExtent { - BlockDriverState *file; + BdrvChild *file; bool flat; bool compressed; bool has_marker; @@ -222,7 +222,7 @@ static void vmdk_free_extents(BlockDriverState *bs) g_free(e->l1_backup_table); g_free(e->type); if (e->file != bs->file) { - bdrv_unref(e->file); + bdrv_unref_child(bs, e->file); } } g_free(s->extents); @@ -248,7 +248,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) BDRVVmdkState *s = bs->opaque; int ret; - ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE); if (ret < 0) { return 0; } @@ -278,7 +278,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) BDRVVmdkState *s = bs->opaque; int ret; - ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE); if (ret < 0) { return ret; } @@ -297,7 +297,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) pstrcat(desc, sizeof(desc), tmp_desc); } - ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pwrite_sync(bs->file->bs, s->desc_offset, desc, DESC_SIZE); if (ret < 0) { return ret; } @@ -308,10 +308,11 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) static int vmdk_is_cid_valid(BlockDriverState *bs) { BDRVVmdkState *s = bs->opaque; - BlockDriverState *p_bs = bs->backing_hd; uint32_t cur_pcid; - if (!s->cid_checked && p_bs) { + if (!s->cid_checked && bs->backing) { + BlockDriverState *p_bs = bs->backing->bs; + cur_pcid = vmdk_read_cid(p_bs, 0); if (s->parent_cid != cur_pcid) { /* CID not valid */ @@ -340,7 +341,7 @@ static int vmdk_parent_open(BlockDriverState *bs) int ret; desc[DESC_SIZE] = '\0'; - ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); + ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE); if (ret < 0) { return ret; } @@ -367,7 +368,7 @@ static int vmdk_parent_open(BlockDriverState *bs) /* Create and append extent to the extent array. Return the added VmdkExtent * address. return NULL if allocation failed. */ static int vmdk_add_extent(BlockDriverState *bs, - BlockDriverState *file, bool flat, int64_t sectors, + BdrvChild *file, bool flat, int64_t sectors, int64_t l1_offset, int64_t l1_backup_offset, uint32_t l1_size, int l2_size, uint64_t cluster_sectors, @@ -392,7 +393,7 @@ static int vmdk_add_extent(BlockDriverState *bs, return -EFBIG; } - nb_sectors = bdrv_nb_sectors(file); + nb_sectors = bdrv_nb_sectors(file->bs); if (nb_sectors < 0) { return nb_sectors; } @@ -439,14 +440,14 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, return -ENOMEM; } - ret = bdrv_pread(extent->file, + ret = bdrv_pread(extent->file->bs, extent->l1_table_offset, extent->l1_table, l1_size); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read l1 table from extent '%s'", - extent->file->filename); + extent->file->bs->filename); goto fail_l1; } for (i = 0; i < extent->l1_size; i++) { @@ -459,14 +460,14 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, ret = -ENOMEM; goto fail_l1; } - ret = bdrv_pread(extent->file, + ret = bdrv_pread(extent->file->bs, extent->l1_backup_table_offset, extent->l1_backup_table, l1_size); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read l1 backup table from extent '%s'", - extent->file->filename); + extent->file->bs->filename); goto fail_l1b; } for (i = 0; i < extent->l1_size; i++) { @@ -485,7 +486,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, } static int vmdk_open_vmfs_sparse(BlockDriverState *bs, - BlockDriverState *file, + BdrvChild *file, int flags, Error **errp) { int ret; @@ -493,11 +494,11 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, VMDK3Header header; VmdkExtent *extent; - ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); + ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header)); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read header from file '%s'", - file->filename); + file->bs->filename); return ret; } ret = vmdk_add_extent(bs, file, false, @@ -559,7 +560,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, } static int vmdk_open_vmdk4(BlockDriverState *bs, - BlockDriverState *file, + BdrvChild *file, int flags, QDict *options, Error **errp) { int ret; @@ -570,17 +571,17 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, BDRVVmdkState *s = bs->opaque; int64_t l1_backup_offset = 0; - ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); + ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header)); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read header from file '%s'", - file->filename); + file->bs->filename); return -EINVAL; } if (header.capacity == 0) { uint64_t desc_offset = le64_to_cpu(header.desc_offset); if (desc_offset) { - char *buf = vmdk_read_desc(file, desc_offset << 9, errp); + char *buf = vmdk_read_desc(file->bs, desc_offset << 9, errp); if (!buf) { return -EINVAL; } @@ -620,8 +621,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, } QEMU_PACKED eos_marker; } QEMU_PACKED footer; - ret = bdrv_pread(file, - bs->file->total_sectors * 512 - 1536, + ret = bdrv_pread(file->bs, + bs->file->bs->total_sectors * 512 - 1536, &footer, sizeof(footer)); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to read footer"); @@ -675,7 +676,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; } - if (bdrv_nb_sectors(file) < le64_to_cpu(header.grain_offset)) { + if (bdrv_nb_sectors(file->bs) < le64_to_cpu(header.grain_offset)) { error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes", (int64_t)(le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE)); @@ -739,8 +740,7 @@ static int vmdk_parse_description(const char *desc, const char *opt_name, } /* Open an extent file and append to bs array */ -static int vmdk_open_sparse(BlockDriverState *bs, - BlockDriverState *file, int flags, +static int vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags, char *buf, QDict *options, Error **errp) { uint32_t magic; @@ -773,10 +773,11 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, int64_t sectors = 0; int64_t flat_offset; char *extent_path; - BlockDriverState *extent_file; + BdrvChild *extent_file; BDRVVmdkState *s = bs->opaque; VmdkExtent *extent; char extent_opt_prefix[32]; + Error *local_err = NULL; while (*p) { /* parse extent line in one of below formats: @@ -819,22 +820,22 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, !desc_file_path[0]) { error_setg(errp, "Cannot use relative extent paths with VMDK " - "descriptor file '%s'", bs->file->filename); + "descriptor file '%s'", bs->file->bs->filename); return -EINVAL; } extent_path = g_malloc0(PATH_MAX); path_combine(extent_path, PATH_MAX, desc_file_path, fname); - extent_file = NULL; ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); assert(ret < 32); - ret = bdrv_open_image(&extent_file, extent_path, options, - extent_opt_prefix, bs, &child_file, false, errp); + extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, + bs, &child_file, false, &local_err); g_free(extent_path); - if (ret) { - return ret; + if (local_err) { + error_propagate(errp, local_err); + return -EINVAL; } /* save to extents array */ @@ -844,13 +845,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, ret = vmdk_add_extent(bs, extent_file, true, sectors, 0, 0, 0, 0, 0, &extent, errp); if (ret < 0) { - bdrv_unref(extent_file); + bdrv_unref_child(bs, extent_file); return ret; } extent->flat_start_offset = flat_offset << 9; } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ - char *buf = vmdk_read_desc(extent_file, 0, errp); + char *buf = vmdk_read_desc(extent_file->bs, 0, errp); if (!buf) { ret = -EINVAL; } else { @@ -859,13 +860,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, } g_free(buf); if (ret) { - bdrv_unref(extent_file); + bdrv_unref_child(bs, extent_file); return ret; } extent = &s->extents[s->num_extents - 1]; } else { error_setg(errp, "Unsupported extent type '%s'", type); - bdrv_unref(extent_file); + bdrv_unref_child(bs, extent_file); return -ENOTSUP; } extent->type = g_strdup(type); @@ -905,7 +906,8 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, } s->create_type = g_strdup(ct); s->desc_offset = 0; - ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, options, errp); + ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options, + errp); exit: return ret; } @@ -918,7 +920,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, BDRVVmdkState *s = bs->opaque; uint32_t magic; - buf = vmdk_read_desc(bs->file, 0, errp); + buf = vmdk_read_desc(bs->file->bs, 0, errp); if (!buf) { return -EINVAL; } @@ -927,7 +929,8 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, switch (magic) { case VMDK3_MAGIC: case VMDK4_MAGIC: - ret = vmdk_open_sparse(bs, bs->file, flags, buf, options, errp); + ret = vmdk_open_sparse(bs, bs->file, flags, buf, options, + errp); s->desc_offset = 0x200; break; default: @@ -1004,7 +1007,7 @@ static int get_whole_cluster(BlockDriverState *bs, cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS; whole_grain = qemu_blockalign(bs, cluster_bytes); - if (!bs->backing_hd) { + if (!bs->backing) { memset(whole_grain, 0, skip_start_sector << BDRV_SECTOR_BITS); memset(whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 0, cluster_bytes - (skip_end_sector << BDRV_SECTOR_BITS)); @@ -1013,22 +1016,22 @@ static int get_whole_cluster(BlockDriverState *bs, assert(skip_end_sector <= extent->cluster_sectors); /* we will be here if it's first write on non-exist grain(cluster). * try to read from parent image, if exist */ - if (bs->backing_hd && !vmdk_is_cid_valid(bs)) { + if (bs->backing && !vmdk_is_cid_valid(bs)) { ret = VMDK_ERROR; goto exit; } /* Read backing data before skip range */ if (skip_start_sector > 0) { - if (bs->backing_hd) { - ret = bdrv_read(bs->backing_hd, sector_num, + if (bs->backing) { + ret = bdrv_read(bs->backing->bs, sector_num, whole_grain, skip_start_sector); if (ret < 0) { ret = VMDK_ERROR; goto exit; } } - ret = bdrv_write(extent->file, cluster_sector_num, whole_grain, + ret = bdrv_write(extent->file->bs, cluster_sector_num, whole_grain, skip_start_sector); if (ret < 0) { ret = VMDK_ERROR; @@ -1037,8 +1040,8 @@ static int get_whole_cluster(BlockDriverState *bs, } /* Read backing data after skip range */ if (skip_end_sector < extent->cluster_sectors) { - if (bs->backing_hd) { - ret = bdrv_read(bs->backing_hd, sector_num + skip_end_sector, + if (bs->backing) { + ret = bdrv_read(bs->backing->bs, sector_num + skip_end_sector, whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), extent->cluster_sectors - skip_end_sector); if (ret < 0) { @@ -1046,7 +1049,7 @@ static int get_whole_cluster(BlockDriverState *bs, goto exit; } } - ret = bdrv_write(extent->file, cluster_sector_num + skip_end_sector, + ret = bdrv_write(extent->file->bs, cluster_sector_num + skip_end_sector, whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), extent->cluster_sectors - skip_end_sector); if (ret < 0) { @@ -1066,7 +1069,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, offset = cpu_to_le32(offset); /* update L2 table */ if (bdrv_pwrite_sync( - extent->file, + extent->file->bs, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(offset)), &offset, sizeof(offset)) < 0) { @@ -1076,7 +1079,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, if (extent->l1_backup_table_offset != 0) { m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; if (bdrv_pwrite_sync( - extent->file, + extent->file->bs, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(offset)), &offset, sizeof(offset)) < 0) { @@ -1166,7 +1169,7 @@ static int get_cluster_offset(BlockDriverState *bs, } l2_table = extent->l2_cache + (min_index * extent->l2_size); if (bdrv_pread( - extent->file, + extent->file->bs, (int64_t)l2_offset * 512, l2_table, extent->l2_size * sizeof(uint32_t) @@ -1320,7 +1323,7 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, write_len = buf_len + sizeof(VmdkGrainMarker); } write_offset = cluster_offset + offset_in_cluster, - ret = bdrv_pwrite(extent->file, write_offset, write_buf, write_len); + ret = bdrv_pwrite(extent->file->bs, write_offset, write_buf, write_len); write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE); @@ -1355,7 +1358,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, if (!extent->compressed) { - ret = bdrv_pread(extent->file, + ret = bdrv_pread(extent->file->bs, cluster_offset + offset_in_cluster, buf, nb_sectors * 512); if (ret == nb_sectors * 512) { @@ -1369,7 +1372,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, buf_bytes = cluster_bytes * 2; cluster_buf = g_malloc(buf_bytes); uncomp_buf = g_malloc(cluster_bytes); - ret = bdrv_pread(extent->file, + ret = bdrv_pread(extent->file->bs, cluster_offset, cluster_buf, buf_bytes); if (ret < 0) { @@ -1431,11 +1434,11 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, } if (ret != VMDK_OK) { /* if not allocated, try to read from parent image, if exist */ - if (bs->backing_hd && ret != VMDK_ZEROED) { + if (bs->backing && ret != VMDK_ZEROED) { if (!vmdk_is_cid_valid(bs)) { return -EINVAL; } - ret = bdrv_read(bs->backing_hd, sector_num, buf, n); + ret = bdrv_read(bs->backing->bs, sector_num, buf, n); if (ret < 0) { return ret; } @@ -2035,7 +2038,7 @@ static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) int ret = 0; for (i = 0; i < s->num_extents; i++) { - err = bdrv_co_flush(s->extents[i].file); + err = bdrv_co_flush(s->extents[i].file->bs); if (err < 0) { ret = err; } @@ -2050,7 +2053,7 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) int64_t r; BDRVVmdkState *s = bs->opaque; - ret = bdrv_get_allocated_file_size(bs->file); + ret = bdrv_get_allocated_file_size(bs->file->bs); if (ret < 0) { return ret; } @@ -2058,7 +2061,7 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) if (s->extents[i].file == bs->file) { continue; } - r = bdrv_get_allocated_file_size(s->extents[i].file); + r = bdrv_get_allocated_file_size(s->extents[i].file->bs); if (r < 0) { return r; } @@ -2076,7 +2079,7 @@ static int vmdk_has_zero_init(BlockDriverState *bs) * return 0. */ for (i = 0; i < s->num_extents; i++) { if (s->extents[i].flat) { - if (!bdrv_has_zero_init(s->extents[i].file)) { + if (!bdrv_has_zero_init(s->extents[i].file->bs)) { return 0; } } @@ -2089,7 +2092,7 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) ImageInfo *info = g_new0(ImageInfo, 1); *info = (ImageInfo){ - .filename = g_strdup(extent->file->filename), + .filename = g_strdup(extent->file->bs->filename), .format = g_strdup(extent->type), .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, .compressed = extent->compressed, @@ -2135,7 +2138,9 @@ static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result, PRId64 "\n", sector_num); break; } - if (ret == VMDK_OK && cluster_offset >= bdrv_getlength(extent->file)) { + if (ret == VMDK_OK && + cluster_offset >= bdrv_getlength(extent->file->bs)) + { fprintf(stderr, "ERROR: cluster offset for sector %" PRId64 " points after EOF\n", sector_num); @@ -2211,7 +2216,7 @@ static void vmdk_detach_aio_context(BlockDriverState *bs) int i; for (i = 0; i < s->num_extents; i++) { - bdrv_detach_aio_context(s->extents[i].file); + bdrv_detach_aio_context(s->extents[i].file->bs); } } @@ -2222,7 +2227,7 @@ static void vmdk_attach_aio_context(BlockDriverState *bs, int i; for (i = 0; i < s->num_extents; i++) { - bdrv_attach_aio_context(s->extents[i].file, new_context); + bdrv_attach_aio_context(s->extents[i].file->bs, new_context); } } diff --git a/block/vpc.c b/block/vpc.c index 2b3b518d1c..299d373092 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -172,14 +172,14 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, int disk_type = VHD_DYNAMIC; int ret; - ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE); + ret = bdrv_pread(bs->file->bs, 0, s->footer_buf, HEADER_SIZE); if (ret < 0) { goto fail; } footer = (VHDFooter *) s->footer_buf; if (strncmp(footer->creator, "conectix", 8)) { - int64_t offset = bdrv_getlength(bs->file); + int64_t offset = bdrv_getlength(bs->file->bs); if (offset < 0) { ret = offset; goto fail; @@ -189,7 +189,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } /* If a fixed disk, the footer is found only at the end of the file */ - ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, + ret = bdrv_pread(bs->file->bs, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE); if (ret < 0) { goto fail; @@ -232,7 +232,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } if (disk_type == VHD_DYNAMIC) { - ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, + ret = bdrv_pread(bs->file->bs, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE); if (ret < 0) { goto fail; @@ -280,7 +280,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, pagetable_size = (uint64_t) s->max_table_entries * 4; - s->pagetable = qemu_try_blockalign(bs->file, pagetable_size); + s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size); if (s->pagetable == NULL) { ret = -ENOMEM; goto fail; @@ -288,7 +288,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, s->bat_offset = be64_to_cpu(dyndisk_header->table_offset); - ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size); + ret = bdrv_pread(bs->file->bs, s->bat_offset, s->pagetable, + pagetable_size); if (ret < 0) { goto fail; } @@ -308,7 +309,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } } - if (s->free_data_block_offset > bdrv_getlength(bs->file)) { + if (s->free_data_block_offset > bdrv_getlength(bs->file->bs)) { error_setg(errp, "block-vpc: free_data_block_offset points after " "the end of file. The image has been truncated."); ret = -EINVAL; @@ -383,7 +384,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs, s->last_bitmap_offset = bitmap_offset; memset(bitmap, 0xff, s->bitmap_size); - bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size); + bdrv_pwrite_sync(bs->file->bs, bitmap_offset, bitmap, s->bitmap_size); } return block_offset; @@ -401,7 +402,7 @@ static int rewrite_footer(BlockDriverState* bs) BDRVVPCState *s = bs->opaque; int64_t offset = s->free_data_block_offset; - ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE); + ret = bdrv_pwrite_sync(bs->file->bs, offset, s->footer_buf, HEADER_SIZE); if (ret < 0) return ret; @@ -436,7 +437,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) // Initialize the block's bitmap memset(bitmap, 0xff, s->bitmap_size); - ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap, + ret = bdrv_pwrite_sync(bs->file->bs, s->free_data_block_offset, bitmap, s->bitmap_size); if (ret < 0) { return ret; @@ -451,7 +452,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) // Write BAT entry to disk bat_offset = s->bat_offset + (4 * index); bat_value = cpu_to_be32(s->pagetable[index]); - ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4); + ret = bdrv_pwrite_sync(bs->file->bs, bat_offset, &bat_value, 4); if (ret < 0) goto fail; @@ -485,7 +486,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num, VHDFooter *footer = (VHDFooter *) s->footer_buf; if (be32_to_cpu(footer->type) == VHD_FIXED) { - return bdrv_read(bs->file, sector_num, buf, nb_sectors); + return bdrv_read(bs->file->bs, sector_num, buf, nb_sectors); } while (nb_sectors > 0) { offset = get_sector_offset(bs, sector_num, 0); @@ -499,7 +500,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num, if (offset == -1) { memset(buf, 0, sectors * BDRV_SECTOR_SIZE); } else { - ret = bdrv_pread(bs->file, offset, buf, + ret = bdrv_pread(bs->file->bs, offset, buf, sectors * BDRV_SECTOR_SIZE); if (ret != sectors * BDRV_SECTOR_SIZE) { return -1; @@ -534,7 +535,7 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, VHDFooter *footer = (VHDFooter *) s->footer_buf; if (be32_to_cpu(footer->type) == VHD_FIXED) { - return bdrv_write(bs->file, sector_num, buf, nb_sectors); + return bdrv_write(bs->file->bs, sector_num, buf, nb_sectors); } while (nb_sectors > 0) { offset = get_sector_offset(bs, sector_num, 1); @@ -551,7 +552,8 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, return -1; } - ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE); + ret = bdrv_pwrite(bs->file->bs, offset, buf, + sectors * BDRV_SECTOR_SIZE); if (ret != sectors * BDRV_SECTOR_SIZE) { return -1; } @@ -878,7 +880,7 @@ static int vpc_has_zero_init(BlockDriverState *bs) VHDFooter *footer = (VHDFooter *) s->footer_buf; if (be32_to_cpu(footer->type) == VHD_FIXED) { - return bdrv_has_zero_init(bs->file); + return bdrv_has_zero_init(bs->file->bs); } else { return 1; } diff --git a/block/vvfat.c b/block/vvfat.c index 7ddc962436..b184eca6fc 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -985,12 +985,6 @@ static BDRVVVFATState *vvv = NULL; static int enable_write_target(BDRVVVFATState *s, Error **errp); static int is_consistent(BDRVVVFATState *s); -static void vvfat_rebind(BlockDriverState *bs) -{ - BDRVVVFATState *s = bs->opaque; - s->bs = bs; -} - static QemuOptsList runtime_opts = { .name = "vvfat", .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), @@ -2923,6 +2917,7 @@ static BlockDriver vvfat_write_target = { static int enable_write_target(BDRVVVFATState *s, Error **errp) { BlockDriver *bdrv_qcow = NULL; + BlockDriverState *backing; QemuOpts *opts = NULL; int ret; int size = sector2cluster(s, s->sector_count); @@ -2971,10 +2966,13 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) unlink(s->qcow_filename); #endif - bdrv_set_backing_hd(s->bs, bdrv_new()); - s->bs->backing_hd->drv = &vvfat_write_target; - s->bs->backing_hd->opaque = g_new(void *, 1); - *(void**)s->bs->backing_hd->opaque = s; + backing = bdrv_new(); + bdrv_set_backing_hd(s->bs, backing); + bdrv_unref(backing); + + s->bs->backing->bs->drv = &vvfat_write_target; + s->bs->backing->bs->opaque = g_new(void *, 1); + *(void**)s->bs->backing->bs->opaque = s; return 0; @@ -3008,7 +3006,6 @@ static BlockDriver bdrv_vvfat = { .bdrv_parse_filename = vvfat_parse_filename, .bdrv_file_open = vvfat_open, .bdrv_close = vvfat_close, - .bdrv_rebind = vvfat_rebind, .bdrv_read = vvfat_co_read, .bdrv_write = vvfat_co_write, diff --git a/block/write-threshold.c b/block/write-threshold.c index a53c1f5e65..0fe38917c5 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -11,7 +11,7 @@ */ #include "block/block_int.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "block/write-threshold.h" #include "qemu/notify.h" #include "qapi-event.h" diff --git a/blockdev.c b/blockdev.c index 32b04b478c..8141b6b3da 100644 --- a/blockdev.c +++ b/blockdev.c @@ -411,7 +411,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, bdrv_flags |= BDRV_O_NO_FLUSH; } -#ifdef CONFIG_LINUX_AIO if ((buf = qemu_opt_get(opts, "aio")) != NULL) { if (!strcmp(buf, "native")) { bdrv_flags |= BDRV_O_NATIVE_AIO; @@ -422,7 +421,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, goto early_err; } } -#endif if ((buf = qemu_opt_get(opts, "format")) != NULL) { if (is_help_option(buf)) { @@ -1546,7 +1544,7 @@ static void external_snapshot_commit(BlkTransactionState *common) /* We don't need (or want) to use the transactional * bdrv_reopen_multiple() across all the entries at once, because we * don't want to abort all of them if one of them fails the reopen */ - bdrv_reopen(state->new_bs, state->new_bs->open_flags & ~BDRV_O_RDWR, + bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR, NULL); aio_context_release(state->aio_context); @@ -2508,7 +2506,7 @@ void qmp_drive_backup(const char *device, const char *target, /* See if we have a backing HD we can use to create our new image * on top of. */ if (sync == MIRROR_SYNC_MODE_TOP) { - source = bs->backing_hd; + source = backing_bs(bs); if (!source) { sync = MIRROR_SYNC_MODE_FULL; } @@ -2716,7 +2714,7 @@ void qmp_drive_mirror(const char *device, const char *target, } flags = bs->open_flags | BDRV_O_RDWR; - source = bs->backing_hd; + source = backing_bs(bs); if (!source && sync == MIRROR_SYNC_MODE_TOP) { sync = MIRROR_SYNC_MODE_FULL; } diff --git a/blockjob.c b/blockjob.c index 62bb906634..1da5491228 100644 --- a/blockjob.c +++ b/blockjob.c @@ -31,7 +31,7 @@ #include "block/block_int.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qmp-commands.h" #include "qemu/timer.h" #include "qapi-event.h" @@ -54,6 +54,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs, bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); job->driver = driver; + job->id = g_strdup(bdrv_get_device_name(bs)); job->bs = bs; job->cb = cb; job->opaque = opaque; @@ -81,6 +82,7 @@ void block_job_release(BlockDriverState *bs) bs->job = NULL; bdrv_op_unblock_all(bs, job->blocker); error_free(job->blocker); + g_free(job->id); g_free(job); } @@ -113,8 +115,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) void block_job_complete(BlockJob *job, Error **errp) { if (job->pause_count || job->cancelled || !job->driver->complete) { - error_setg(errp, QERR_BLOCK_JOB_NOT_READY, - bdrv_get_device_name(job->bs)); + error_setg(errp, QERR_BLOCK_JOB_NOT_READY, job->id); return; } @@ -269,7 +270,7 @@ BlockJobInfo *block_job_query(BlockJob *job) { BlockJobInfo *info = g_new0(BlockJobInfo, 1); info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]); - info->device = g_strdup(bdrv_get_device_name(job->bs)); + info->device = g_strdup(job->id); info->len = job->len; info->busy = job->busy; info->paused = job->pause_count > 0; @@ -291,7 +292,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error) void block_job_event_cancelled(BlockJob *job) { qapi_event_send_block_job_cancelled(job->driver->job_type, - bdrv_get_device_name(job->bs), + job->id, job->len, job->offset, job->speed, @@ -301,7 +302,7 @@ void block_job_event_cancelled(BlockJob *job) void block_job_event_completed(BlockJob *job, const char *msg) { qapi_event_send_block_job_completed(job->driver->job_type, - bdrv_get_device_name(job->bs), + job->id, job->len, job->offset, job->speed, @@ -315,7 +316,7 @@ void block_job_event_ready(BlockJob *job) job->ready = true; qapi_event_send_block_job_ready(job->driver->job_type, - bdrv_get_device_name(job->bs), + job->id, job->len, job->offset, job->speed, &error_abort); @@ -344,7 +345,7 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs, default: abort(); } - qapi_event_send_block_job_error(bdrv_get_device_name(job->bs), + qapi_event_send_block_job_error(job->id, is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE, action, &error_abort); @@ -1166,18 +1166,14 @@ fi # Note that if the Python conditional here evaluates True we will exit # with status 1 which is a shell 'false' value. -if ! $python -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_info >= (3,))'; then - error_exit "Cannot use '$python', Python 2.4 or later is required." \ +if ! $python -c 'import sys; sys.exit(sys.version_info < (2,6) or sys.version_info >= (3,))'; then + error_exit "Cannot use '$python', Python 2.6 or later is required." \ "Note that Python 3 or later is not yet supported." \ "Use --python=/path/to/python to specify a supported Python." fi -# The -B switch was added in Python 2.6. -# If it is supplied, compiled files are not written. -# Use it for Python versions which support it. -if $python -B -c 'import sys; sys.exit(0)' 2>/dev/null; then - python="$python -B" -fi +# Suppress writing compiled files +python="$python -B" case "$cpu" in ppc) @@ -4457,7 +4453,7 @@ fi if [ "$guest_agent" != "no" ]; then if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then - tools="qemu-ga\$(EXESUF) $tools" + tools="qemu-ga $tools" guest_agent=yes elif [ "$guest_agent" != yes ]; then guest_agent=no diff --git a/cpu-exec-common.c b/cpu-exec-common.c index 16d305b911..43edf36777 100644 --- a/cpu-exec-common.c +++ b/cpu-exec-common.c @@ -37,31 +37,32 @@ void cpu_resume_from_signal(CPUState *cpu, void *puc) siglongjmp(cpu->jmp_env, 1); } -void cpu_reload_memory_map(CPUState *cpu) +void cpu_reloading_memory_map(void) { - AddressSpaceDispatch *d; - if (qemu_in_vcpu_thread()) { - /* Do not let the guest prolong the critical section as much as it - * as it desires. + /* The guest can in theory prolong the RCU critical section as long + * as it feels like. The major problem with this is that because it + * can do multiple reconfigurations of the memory map within the + * critical section, we could potentially accumulate an unbounded + * collection of memory data structures awaiting reclamation. + * + * Because the only thing we're currently protecting with RCU is the + * memory data structures, it's sufficient to break the critical section + * in this callback, which we know will get called every time the + * memory map is rearranged. * - * Currently, this is prevented by the I/O thread's periodinc kicking - * of the VCPU thread (iothread_requesting_mutex, qemu_cpu_kick_thread) - * but this will go away once TCG's execution moves out of the global - * mutex. + * (If we add anything else in the system that uses RCU to protect + * its data structures, we will need to implement some other mechanism + * to force TCG CPUs to exit the critical section, at which point this + * part of this callback might become unnecessary.) * * This pair matches cpu_exec's rcu_read_lock()/rcu_read_unlock(), which - * only protects cpu->as->dispatch. Since we reload it below, we can - * split the critical section. + * only protects cpu->as->dispatch. Since we know our caller is about + * to reload it, it's safe to split the critical section. */ rcu_read_unlock(); rcu_read_lock(); } - - /* The CPU and TLB are protected by the iothread lock. */ - d = atomic_rcu_read(&cpu->as->dispatch); - cpu->memory_dispatch = d; - tlb_flush(cpu, 1); } #endif diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index e77cb1ac54..bb71b23ee7 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -3,6 +3,7 @@ include pci.mak include sound.mak include usb.mak +CONFIG_VIRTIO_VGA=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y diff --git a/docs/rcu.txt b/docs/rcu.txt index 21ecb8106c..2f70954e82 100644 --- a/docs/rcu.txt +++ b/docs/rcu.txt @@ -128,7 +128,7 @@ The core RCU API is small: the callback function is g_free, in particular, g_free_rcu can be used. In the above case, one could have written simply: - g_free_rcu(foo_reclaim, rcu); + g_free_rcu(&foo, rcu); typeof(*p) atomic_rcu_read(p); diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt index 74351dd18f..b8c794f546 100644 --- a/docs/specs/fw_cfg.txt +++ b/docs/specs/fw_cfg.txt @@ -76,6 +76,13 @@ increasing address order, similar to memcpy(). Selector Register IOport: 0x510 Data Register IOport: 0x511 +DMA Address IOport: 0x514 + +=== ARM Register Locations === + +Selector Register address: Base + 8 (2 bytes) +Data Register address: Base + 0 (8 bytes) +DMA Address address: Base + 16 (8 bytes) == Firmware Configuration Items == @@ -86,11 +93,15 @@ by selecting the "signature" item using key 0x0000 (FW_CFG_SIGNATURE), and reading four bytes from the data register. If the fw_cfg device is present, the four bytes read will contain the characters "QEMU". -=== Revision (Key 0x0001, FW_CFG_ID) === +If the DMA interface is available, then reading the DMA Address +Register returns 0x51454d5520434647 ("QEMU CFG" in big-endian format). + +=== Revision / feature bitmap (Key 0x0001, FW_CFG_ID) === -A 32-bit little-endian unsigned int, this item is used as an interface -revision number, and is currently set to 1 by QEMU when fw_cfg is -initialized. +A 32-bit little-endian unsigned int, this item is used to check for enabled +features. + - Bit 0: traditional interface. Always set. + - Bit 1: DMA interface. === File Directory (Key 0x0019, FW_CFG_FILE_DIR) === @@ -132,6 +143,55 @@ Selector Reg. Range Usage In practice, the number of allowed firmware configuration items is given by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h). += Guest-side DMA Interface = + +If bit 1 of the feature bitmap is set, the DMA interface is present. This does +not replace the existing fw_cfg interface, it is an add-on. This interface +can be used through the 64-bit wide address register. + +The address register is in big-endian format. The value for the register is 0 +at startup and after an operation. A write to the least significant half (at +offset 4) triggers an operation. This means that operations with 32-bit +addresses can be triggered with just one write, whereas operations with +64-bit addresses can be triggered with one 64-bit write or two 32-bit writes, +starting with the most significant half (at offset 0). + +In this register, the physical address of a FWCfgDmaAccess structure in RAM +should be written. This is the format of the FWCfgDmaAccess structure: + +typedef struct FWCfgDmaAccess { + uint32_t control; + uint32_t length; + uint64_t address; +} FWCfgDmaAccess; + +The fields of the structure are in big endian mode, and the field at the lowest +address is the "control" field. + +The "control" field has the following bits: + - Bit 0: Error + - Bit 1: Read + - Bit 2: Skip + - Bit 3: Select. The upper 16 bits are the selected index. + +When an operation is triggered, if the "control" field has bit 3 set, the +upper 16 bits are interpreted as an index of a firmware configuration item. +This has the same effect as writing the selector register. + +If the "control" field has bit 1 set, a read operation will be performed. +"length" bytes for the current selector and offset will be copied into the +physical RAM address specified by the "address" field. + +If the "control" field has bit 2 set (and not bit 1), a skip operation will be +performed. The offset for the current selector will be advanced "length" bytes. + +To check the result, read the "control" field: + error bit set -> something went wrong. + all bits cleared -> transfer finished successfully. + otherwise -> transfer still in progress (doesn't happen + today due to implementation not being async, + but may in the future). + = Host-side API = The following functions are available to the QEMU programmer for adding @@ -159,6 +219,17 @@ will convert a 16-, 32-, or 64-bit integer to little-endian, then add a dynamically allocated copy of the appropriately sized item to fw_cfg under the given selector key value. +== fw_cfg_modify_iXX() == + +Modify the value of an XX-bit item (where XX may be 16, 32, or 64). +Similarly to the corresponding fw_cfg_add_iXX() function set, convert +a 16-, 32-, or 64-bit integer to little endian, create a dynamically +allocated copy of the required size, and replace the existing item at +the given selector key value with the newly allocated one. The previous +item, assumed to have been allocated during an earlier call to +fw_cfg_add_iXX() or fw_cfg_modify_iXX() (of the same width XX), is freed +before the function returns. + == fw_cfg_add_file() == Given a filename (i.e., fw_cfg item name), starting pointer, and size, @@ -216,6 +287,21 @@ the following syntax: where <item_name> is the fw_cfg item name, and <path> is the location on the host file system of a file containing the data to be inserted. +Small enough items may be provided directly as strings on the command +line, using the syntax: + + -fw_cfg [name=]<item_name>,string=<string> + +The terminating NUL character of the content <string> will NOT be +included as part of the fw_cfg item data, which is consistent with +the absence of a NUL terminator for items inserted via the file option. + +Both <item_name> and, if applicable, the content <string> are passed +through by QEMU without any interpretation, expansion, or further +processing. Any such processing (potentially performed e.g., by the shell) +is outside of QEMU's responsibility; as such, using plain ASCII characters +is recommended. + NOTE: Users *SHOULD* choose item names beginning with the prefix "opt/" when using the "-fw_cfg" command line option, to avoid conflicting with item names used internally by QEMU. For instance: @@ -164,6 +164,21 @@ static void memory_map_init(void); static void tcg_commit(MemoryListener *listener); static MemoryRegion io_mem_watch; + +/** + * CPUAddressSpace: all the information a CPU needs about an AddressSpace + * @cpu: the CPU whose AddressSpace this is + * @as: the AddressSpace itself + * @memory_dispatch: its dispatch pointer (cached, RCU protected) + * @tcg_as_listener: listener for tracking changes to the AddressSpace + */ +struct CPUAddressSpace { + CPUState *cpu; + AddressSpace *as; + struct AddressSpaceDispatch *memory_dispatch; + MemoryListener tcg_as_listener; +}; + #endif #if !defined(CONFIG_USER_ONLY) @@ -434,7 +449,7 @@ address_space_translate_for_iotlb(CPUState *cpu, hwaddr addr, hwaddr *xlat, hwaddr *plen) { MemoryRegionSection *section; - section = address_space_translate_internal(cpu->memory_dispatch, + section = address_space_translate_internal(cpu->cpu_ases[0].memory_dispatch, addr, xlat, plen, false); assert(!section->mr->iommu_ops); @@ -540,13 +555,16 @@ void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as) /* We only support one address space per cpu at the moment. */ assert(cpu->as == as); - if (cpu->tcg_as_listener) { - memory_listener_unregister(cpu->tcg_as_listener); - } else { - cpu->tcg_as_listener = g_new0(MemoryListener, 1); + if (cpu->cpu_ases) { + /* We've already registered the listener for our only AS */ + return; } - cpu->tcg_as_listener->commit = tcg_commit; - memory_listener_register(cpu->tcg_as_listener, as); + + cpu->cpu_ases = g_new0(CPUAddressSpace, 1); + cpu->cpu_ases[0].cpu = cpu; + cpu->cpu_ases[0].as = as; + cpu->cpu_ases[0].tcg_as_listener.commit = tcg_commit; + memory_listener_register(&cpu->cpu_ases[0].tcg_as_listener, as); } #endif @@ -604,7 +622,6 @@ void cpu_exec_init(CPUState *cpu, Error **errp) #ifndef CONFIG_USER_ONLY cpu->as = &address_space_memory; cpu->thread_id = qemu_get_thread_id(); - cpu_reload_memory_map(cpu); #endif #if defined(CONFIG_USER_ONLY) @@ -2192,7 +2209,8 @@ static uint16_t dummy_section(PhysPageMap *map, AddressSpace *as, MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index) { - AddressSpaceDispatch *d = atomic_rcu_read(&cpu->memory_dispatch); + CPUAddressSpace *cpuas = &cpu->cpu_ases[0]; + AddressSpaceDispatch *d = atomic_rcu_read(&cpuas->memory_dispatch); MemoryRegionSection *sections = d->map.sections; return sections[index & ~TARGET_PAGE_MASK].mr; @@ -2251,19 +2269,20 @@ static void mem_commit(MemoryListener *listener) static void tcg_commit(MemoryListener *listener) { - CPUState *cpu; + CPUAddressSpace *cpuas; + AddressSpaceDispatch *d; /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ - /* XXX: slow ! */ - CPU_FOREACH(cpu) { - /* FIXME: Disentangle the cpu.h circular files deps so we can - directly get the right CPU from listener. */ - if (cpu->tcg_as_listener != listener) { - continue; - } - cpu_reload_memory_map(cpu); - } + cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); + cpu_reloading_memory_map(); + /* The CPU and TLB are protected by the iothread lock. + * We reload the dispatch pointer now because cpu_reloading_memory_map() + * may have split the RCU critical section. + */ + d = atomic_rcu_read(&cpuas->as->dispatch); + cpuas->memory_dispatch = d; + tlb_flush(cpuas->cpu, 1); } void address_space_init_dispatch(AddressSpace *as) diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 65ad3298be..ec9cc7fb27 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 2efebf3571..7cb55ee93a 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 42ee614e27..e1953a9aa1 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 18ee08df0f..55c0d231cb 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c index 8185c533c0..5057f8d220 100644 --- a/hw/9pfs/virtio-9p-coth.c +++ b/hw/9pfs/virtio-9p-coth.c @@ -15,7 +15,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" #include "qemu/event_notifier.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" /* v9fs glib thread pool */ diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index 4f51b250d1..0fbe49a946 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -16,7 +16,7 @@ #define _QEMU_VIRTIO_9P_COTH_H #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p.h" #include <glib.h> diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 2e7d488570..d7a4dc1e9a 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -13,7 +13,7 @@ #include "fsdev/file-op-9p.h" #include "fsdev/virtio-9p-marshal.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" enum { P9_TLERROR = 6, diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 4e7160ce96..5d38c47444 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -119,7 +119,7 @@ static const MemMapEntry a15memmap[] = { [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, [VIRT_UART] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 }, - [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, + [VIRT_FW_CFG] = { 0x09020000, 0x00000018 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, @@ -677,13 +677,13 @@ static void create_flash(const VirtBoardInfo *vbi) g_free(nodename); } -static void create_fw_cfg(const VirtBoardInfo *vbi) +static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) { hwaddr base = vbi->memmap[VIRT_FW_CFG].base; hwaddr size = vbi->memmap[VIRT_FW_CFG].size; char *nodename; - fw_cfg_init_mem_wide(base + 8, base, 8); + fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, as); nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); qemu_fdt_add_subnode(vbi->fdt, nodename); @@ -1031,7 +1031,7 @@ static void machvirt_init(MachineState *machine) */ create_virtio_devices(vbi, pic); - create_fw_cfg(vbi); + create_fw_cfg(vbi, &address_space_memory); rom_set_fw(fw_cfg_find()); guest_info->smp_cpus = smp_cpus; diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 656eb3773a..334935f8d9 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -57,11 +57,6 @@ void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); #define SHIFT 1 #endif -#define IO_READ_PROTO(name) \ - uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ - void name (void *opaque, uint32_t nport, uint32_t val) - #define TYPE_ADLIB "adlib" #define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB) @@ -124,7 +119,7 @@ static void adlib_kill_timers (AdlibState *s) } } -static IO_WRITE_PROTO (adlib_write) +static void adlib_write(void *opaque, uint32_t nport, uint32_t val) { AdlibState *s = opaque; int a = nport & 3; @@ -141,7 +136,7 @@ static IO_WRITE_PROTO (adlib_write) #endif } -static IO_READ_PROTO (adlib_read) +static uint32_t adlib_read(void *opaque, uint32_t nport) { AdlibState *s = opaque; uint8_t data; diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 8e7bcf503e..592578b142 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -157,11 +157,6 @@ static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 }; #define DAC2_CHANNEL 1 #define ADC_CHANNEL 2 -#define IO_READ_PROTO(n) \ -static uint32_t n (void *opaque, uint32_t addr) -#define IO_WRITE_PROTO(n) \ -static void n (void *opaque, uint32_t addr, uint32_t val) - static void es1370_dac1_callback (void *opaque, int free); static void es1370_dac2_callback (void *opaque, int free); static void es1370_adc_callback (void *opaque, int avail); @@ -474,7 +469,7 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) return addr; } -IO_WRITE_PROTO (es1370_writeb) +static void es1370_writeb(void *opaque, uint32_t addr, uint32_t val) { ES1370State *s = opaque; uint32_t shift, mask; @@ -512,7 +507,7 @@ IO_WRITE_PROTO (es1370_writeb) } } -IO_WRITE_PROTO (es1370_writew) +static void es1370_writew(void *opaque, uint32_t addr, uint32_t val) { ES1370State *s = opaque; addr = es1370_fixup (s, addr); @@ -549,7 +544,7 @@ IO_WRITE_PROTO (es1370_writew) } } -IO_WRITE_PROTO (es1370_writel) +static void es1370_writel(void *opaque, uint32_t addr, uint32_t val) { ES1370State *s = opaque; struct chan *d = &s->chan[0]; @@ -615,7 +610,7 @@ IO_WRITE_PROTO (es1370_writel) } } -IO_READ_PROTO (es1370_readb) +static uint32_t es1370_readb(void *opaque, uint32_t addr) { ES1370State *s = opaque; uint32_t val; @@ -650,7 +645,7 @@ IO_READ_PROTO (es1370_readb) return val; } -IO_READ_PROTO (es1370_readw) +static uint32_t es1370_readw(void *opaque, uint32_t addr) { ES1370State *s = opaque; struct chan *d = &s->chan[0]; @@ -692,7 +687,7 @@ IO_READ_PROTO (es1370_readw) return val; } -IO_READ_PROTO (es1370_readl) +static uint32_t es1370_readl(void *opaque, uint32_t addr) { ES1370State *s = opaque; uint32_t val; diff --git a/hw/audio/gus.c b/hw/audio/gus.c index 86223a9544..e0c8a4ee1e 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -41,11 +41,6 @@ #define GUS_ENDIANNESS 0 #endif -#define IO_READ_PROTO(name) \ - static uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ - static void name (void *opaque, uint32_t nport, uint32_t val) - #define TYPE_GUS "gus" #define GUS(obj) OBJECT_CHECK (GUSState, (obj), TYPE_GUS) @@ -64,14 +59,14 @@ typedef struct GUSState { qemu_irq pic; } GUSState; -IO_READ_PROTO (gus_readb) +static uint32_t gus_readb(void *opaque, uint32_t nport) { GUSState *s = opaque; return gus_read (&s->emu, nport, 1); } -IO_WRITE_PROTO (gus_writeb) +static void gus_writeb(void *opaque, uint32_t nport, uint32_t val) { GUSState *s = opaque; diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index b052de5f7d..995435f240 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -40,11 +40,6 @@ #define ldebug(...) #endif -#define IO_READ_PROTO(name) \ - uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ - void name (void *opaque, uint32_t nport, uint32_t val) - static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; #define TYPE_SB16 "sb16" @@ -881,7 +876,7 @@ static void reset (SB16State *s) legacy_reset (s); } -static IO_WRITE_PROTO (dsp_write) +static void dsp_write(void *opaque, uint32_t nport, uint32_t val) { SB16State *s = opaque; int iport; @@ -959,7 +954,7 @@ static IO_WRITE_PROTO (dsp_write) } } -static IO_READ_PROTO (dsp_read) +static uint32_t dsp_read(void *opaque, uint32_t nport) { SB16State *s = opaque; int iport, retval, ack = 0; @@ -1058,14 +1053,14 @@ static void reset_mixer (SB16State *s) } } -static IO_WRITE_PROTO (mixer_write_indexb) +static void mixer_write_indexb(void *opaque, uint32_t nport, uint32_t val) { SB16State *s = opaque; (void) nport; s->mixer_nreg = val; } -static IO_WRITE_PROTO (mixer_write_datab) +static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val) { SB16State *s = opaque; @@ -1121,7 +1116,7 @@ static IO_WRITE_PROTO (mixer_write_datab) s->mixer_regs[s->mixer_nreg] = val; } -static IO_READ_PROTO (mixer_read) +static uint32_t mixer_read(void *opaque, uint32_t nport) { SB16State *s = opaque; diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 8e9350981c..9354037852 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -488,10 +488,10 @@ static inline int vmsvga_fill_rect(struct vmsvga_state_s *s, #endif struct vmsvga_cursor_definition_s { - int width; - int height; + uint32_t width; + uint32_t height; int id; - int bpp; + uint32_t bpp; int hot_x; int hot_y; uint32_t mask[1024]; @@ -658,7 +658,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) cursor.bpp = vmsvga_fifo_read(s); args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp); - if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask || + if (cursor.width > 256 || + cursor.height > 256 || + cursor.bpp > 32 || + SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask || SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) { goto badcmd; } diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index 44beee3a05..0fd69230ae 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -979,7 +979,7 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev) MSIMessage msg = msi_get_message(pci_dev, 0); int virq; - virq = kvm_irqchip_add_msi_route(kvm_state, msg); + virq = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev); if (virq < 0) { perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route"); return; @@ -1017,7 +1017,7 @@ static void assigned_dev_update_msi_msg(PCIDevice *pci_dev) } kvm_irqchip_update_msi_route(kvm_state, assigned_dev->msi_virq[0], - msi_get_message(pci_dev, 0)); + msi_get_message(pci_dev, 0), pci_dev); } static bool assigned_dev_msix_masked(MSIXTableEntry *entry) @@ -1083,7 +1083,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32); msg.data = entry->data; - r = kvm_irqchip_add_msi_route(kvm_state, msg); + r = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev); if (r < 0) { return r; } @@ -1483,7 +1483,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) * error bits, leave the rest. */ status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS); status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN); - status |= (pci_bus_num(pci_dev->bus) << 8) | pci_dev->devfn; + status |= pci_requester_id(pci_dev); status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL | PCI_X_STATUS_SPL_ERR); pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status); @@ -1602,7 +1602,8 @@ static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr, msg.data = entry->data; ret = kvm_irqchip_update_msi_route(kvm_state, - adev->msi_virq[i], msg); + adev->msi_virq[i], msg, + pdev); if (ret) { error_report("Error updating irq routing entry (%d)", ret); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 208f5530c8..3d958bae5b 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -752,14 +752,15 @@ static void pc_build_smbios(FWCfgState *fw_cfg) } } -static FWCfgState *bochs_bios_init(void) +static FWCfgState *bochs_bios_init(AddressSpace *as) { FWCfgState *fw_cfg; uint64_t *numa_fw_cfg; int i, j; unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); - fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT); + fw_cfg = fw_cfg_init_io_dma(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 4, as); + /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: * * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug @@ -1392,7 +1393,8 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, option_rom_mr, 1); - fw_cfg = bochs_bios_init(); + fw_cfg = bochs_bios_init(&address_space_memory); + rom_set_fw(fw_cfg); if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0eacde12bb..9d4425a5b9 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -434,6 +434,11 @@ static void pc_xen_hvm_init(MachineState *machine) { PCIBus *bus; + if (!xen_enabled()) { + error_report("xenfv machine requires the xen accelerator"); + exit(1); + } + pc_xen_hvm_init_pci(machine); bus = pci_find_primary_bus(); diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index ee45f038b8..8682c42e46 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -387,6 +387,9 @@ static int xen_platform_initfn(PCIDevice *dev) PCIXenPlatformState *d = XEN_PLATFORM(dev); uint8_t *pci_conf; + /* Device will crash on reset if xen is not initialized */ + assert(xen_enabled()); + pci_conf = dev->config; pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 796be15635..21f76ed86e 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -548,7 +548,7 @@ static void ahci_init_d2h(AHCIDevice *ad) ad->init_d2h_sent = true; /* We're emulating receiving the first Reg H2D Fis from the device; * Update the SIG register, but otherwise proceed as normal. */ - pr->sig = (ide_state->hcyl << 24) | + pr->sig = ((uint32_t)ide_state->hcyl << 24) | (ide_state->lcyl << 16) | (ide_state->sector << 8) | (ide_state->nsector & 0xFF); diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 7b25d27693..1f5a40de35 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -20,6 +20,10 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) unsigned have, need; int i, len; + if (!vinput->active) { + return; + } + /* queue up events ... */ if (vinput->qindex == vinput->qsize) { vinput->qsize++; diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 658f8c4ff1..73b0a813a7 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -23,6 +23,7 @@ */ #include "hw/hw.h" #include "sysemu/sysemu.h" +#include "sysemu/dma.h" #include "hw/isa/isa.h" #include "hw/nvram/fw_cfg.h" #include "hw/sysbus.h" @@ -30,7 +31,7 @@ #include "qemu/error-report.h" #include "qemu/config-file.h" -#define FW_CFG_SIZE 2 +#define FW_CFG_CTL_SIZE 2 #define FW_CFG_NAME "fw_cfg" #define FW_CFG_PATH "/machine/" FW_CFG_NAME @@ -42,6 +43,18 @@ #define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO) #define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM) +/* FW_CFG_VERSION bits */ +#define FW_CFG_VERSION 0x01 +#define FW_CFG_VERSION_DMA 0x02 + +/* FW_CFG_DMA_CONTROL bits */ +#define FW_CFG_DMA_CTL_ERROR 0x01 +#define FW_CFG_DMA_CTL_READ 0x02 +#define FW_CFG_DMA_CTL_SKIP 0x04 +#define FW_CFG_DMA_CTL_SELECT 0x08 + +#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */ + typedef struct FWCfgEntry { uint32_t len; uint8_t *data; @@ -59,6 +72,11 @@ struct FWCfgState { uint16_t cur_entry; uint32_t cur_offset; Notifier machine_ready; + + bool dma_enabled; + dma_addr_t dma_addr; + AddressSpace *dma_as; + MemoryRegion dma_iomem; }; struct FWCfgIoState { @@ -67,7 +85,7 @@ struct FWCfgIoState { /*< public >*/ MemoryRegion comb_iomem; - uint32_t iobase; + uint32_t iobase, dma_iobase; }; struct FWCfgMemState { @@ -292,6 +310,129 @@ static void fw_cfg_data_mem_write(void *opaque, hwaddr addr, } while (i); } +static void fw_cfg_dma_transfer(FWCfgState *s) +{ + dma_addr_t len; + FWCfgDmaAccess dma; + int arch; + FWCfgEntry *e; + int read; + dma_addr_t dma_addr; + + /* Reset the address before the next access */ + dma_addr = s->dma_addr; + s->dma_addr = 0; + + if (dma_memory_read(s->dma_as, dma_addr, &dma, sizeof(dma))) { + stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control), + FW_CFG_DMA_CTL_ERROR); + return; + } + + dma.address = be64_to_cpu(dma.address); + dma.length = be32_to_cpu(dma.length); + dma.control = be32_to_cpu(dma.control); + + if (dma.control & FW_CFG_DMA_CTL_SELECT) { + fw_cfg_select(s, dma.control >> 16); + } + + arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); + e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; + + if (dma.control & FW_CFG_DMA_CTL_READ) { + read = 1; + } else if (dma.control & FW_CFG_DMA_CTL_SKIP) { + read = 0; + } else { + dma.length = 0; + } + + dma.control = 0; + + while (dma.length > 0 && !(dma.control & FW_CFG_DMA_CTL_ERROR)) { + if (s->cur_entry == FW_CFG_INVALID || !e->data || + s->cur_offset >= e->len) { + len = dma.length; + + /* If the access is not a read access, it will be a skip access, + * tested before. + */ + if (read) { + if (dma_memory_set(s->dma_as, dma.address, 0, len)) { + dma.control |= FW_CFG_DMA_CTL_ERROR; + } + } + + } else { + if (dma.length <= (e->len - s->cur_offset)) { + len = dma.length; + } else { + len = (e->len - s->cur_offset); + } + + if (e->read_callback) { + e->read_callback(e->callback_opaque, s->cur_offset); + } + + /* If the access is not a read access, it will be a skip access, + * tested before. + */ + if (read) { + if (dma_memory_write(s->dma_as, dma.address, + &e->data[s->cur_offset], len)) { + dma.control |= FW_CFG_DMA_CTL_ERROR; + } + } + + s->cur_offset += len; + } + + dma.address += len; + dma.length -= len; + + } + + stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control), + dma.control); + + trace_fw_cfg_read(s, 0); +} + +static uint64_t fw_cfg_dma_mem_read(void *opaque, hwaddr addr, + unsigned size) +{ + /* Return a signature value (and handle various read sizes) */ + return extract64(FW_CFG_DMA_SIGNATURE, (8 - addr - size) * 8, size * 8); +} + +static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + FWCfgState *s = opaque; + + if (size == 4) { + if (addr == 0) { + /* FWCfgDmaAccess high address */ + s->dma_addr = value << 32; + } else if (addr == 4) { + /* FWCfgDmaAccess low address */ + s->dma_addr |= value; + fw_cfg_dma_transfer(s); + } + } else if (size == 8 && addr == 0) { + s->dma_addr = value; + fw_cfg_dma_transfer(s); + } +} + +static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + return !is_write || ((size == 4 && (addr == 0 || addr == 4)) || + (size == 8 && addr == 0)); +} + static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr, unsigned size, bool is_write) { @@ -359,6 +500,15 @@ static const MemoryRegionOps fw_cfg_comb_mem_ops = { .valid.accepts = fw_cfg_comb_valid, }; +static const MemoryRegionOps fw_cfg_dma_mem_ops = { + .read = fw_cfg_dma_mem_read, + .write = fw_cfg_dma_mem_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid.accepts = fw_cfg_dma_mem_valid, + .valid.max_access_size = 8, + .impl.max_access_size = 8, +}; + static void fw_cfg_reset(DeviceState *d) { FWCfgState *s = FW_CFG(d); @@ -399,6 +549,22 @@ static bool is_version_1(void *opaque, int version_id) return version_id == 1; } +static bool fw_cfg_dma_enabled(void *opaque) +{ + FWCfgState *s = opaque; + + return s->dma_enabled; +} + +static const VMStateDescription vmstate_fw_cfg_dma = { + .name = "fw_cfg/dma", + .needed = fw_cfg_dma_enabled, + .fields = (VMStateField[]) { + VMSTATE_UINT64(dma_addr, FWCfgState), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_fw_cfg = { .name = "fw_cfg", .version_id = 2, @@ -408,6 +574,10 @@ static const VMStateDescription vmstate_fw_cfg = { VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1), VMSTATE_UINT32_V(cur_offset, FWCfgState, 2), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_fw_cfg_dma, + NULL, } }; @@ -593,7 +763,6 @@ static void fw_cfg_init1(DeviceState *dev) qdev_init_nofail(dev); fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); - fw_cfg_add_i32(s, FW_CFG_ID, 1); fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); @@ -605,25 +774,53 @@ static void fw_cfg_init1(DeviceState *dev) qemu_add_machine_init_done_notifier(&s->machine_ready); } -FWCfgState *fw_cfg_init_io(uint32_t iobase) +FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, + AddressSpace *dma_as) { DeviceState *dev; + FWCfgState *s; + uint32_t version = FW_CFG_VERSION; + bool dma_enabled = dma_iobase && dma_as; dev = qdev_create(NULL, TYPE_FW_CFG_IO); qdev_prop_set_uint32(dev, "iobase", iobase); + qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase); + qdev_prop_set_bit(dev, "dma_enabled", dma_enabled); + fw_cfg_init1(dev); + s = FW_CFG(dev); + + if (dma_enabled) { + /* 64 bits for the address field */ + s->dma_as = dma_as; + s->dma_addr = 0; + + version |= FW_CFG_VERSION_DMA; + } - return FW_CFG(dev); + fw_cfg_add_i32(s, FW_CFG_ID, version); + + return s; +} + +FWCfgState *fw_cfg_init_io(uint32_t iobase) +{ + return fw_cfg_init_io_dma(iobase, 0, NULL); } -FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr, - uint32_t data_width) +FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, + hwaddr data_addr, uint32_t data_width, + hwaddr dma_addr, AddressSpace *dma_as) { DeviceState *dev; SysBusDevice *sbd; + FWCfgState *s; + uint32_t version = FW_CFG_VERSION; + bool dma_enabled = dma_addr && dma_as; dev = qdev_create(NULL, TYPE_FW_CFG_MEM); qdev_prop_set_uint32(dev, "data_width", data_width); + qdev_prop_set_bit(dev, "dma_enabled", dma_enabled); fw_cfg_init1(dev); @@ -631,13 +828,25 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr, sysbus_mmio_map(sbd, 0, ctl_addr); sysbus_mmio_map(sbd, 1, data_addr); - return FW_CFG(dev); + s = FW_CFG(dev); + + if (dma_enabled) { + s->dma_as = dma_as; + s->dma_addr = 0; + sysbus_mmio_map(sbd, 2, dma_addr); + version |= FW_CFG_VERSION_DMA; + } + + fw_cfg_add_i32(s, FW_CFG_ID, version); + + return s; } FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr) { return fw_cfg_init_mem_wide(ctl_addr, data_addr, - fw_cfg_data_mem_ops.valid.max_access_size); + fw_cfg_data_mem_ops.valid.max_access_size, + 0, NULL); } @@ -664,6 +873,9 @@ static const TypeInfo fw_cfg_info = { static Property fw_cfg_io_properties[] = { DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1), + DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1), + DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled, + false), DEFINE_PROP_END_OF_LIST(), }; @@ -673,8 +885,15 @@ static void fw_cfg_io_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, - FW_CFG(s), "fwcfg", FW_CFG_SIZE); + FW_CFG(s), "fwcfg", FW_CFG_CTL_SIZE); sysbus_add_io(sbd, s->iobase, &s->comb_iomem); + + if (FW_CFG(s)->dma_enabled) { + memory_region_init_io(&FW_CFG(s)->dma_iomem, OBJECT(s), + &fw_cfg_dma_mem_ops, FW_CFG(s), "fwcfg.dma", + sizeof(dma_addr_t)); + sysbus_add_io(sbd, s->dma_iobase, &FW_CFG(s)->dma_iomem); + } } static void fw_cfg_io_class_init(ObjectClass *klass, void *data) @@ -695,6 +914,8 @@ static const TypeInfo fw_cfg_io_info = { static Property fw_cfg_mem_properties[] = { DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1), + DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled, + false), DEFINE_PROP_END_OF_LIST(), }; @@ -705,7 +926,7 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp) const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops; memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, - FW_CFG(s), "fwcfg.ctl", FW_CFG_SIZE); + FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE); sysbus_init_mmio(sbd, &s->ctl_iomem); if (s->data_width > data_ops->valid.max_access_size) { @@ -723,6 +944,13 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->data_iomem, OBJECT(s), data_ops, FW_CFG(s), "fwcfg.data", data_ops->valid.max_access_size); sysbus_init_mmio(sbd, &s->data_iomem); + + if (FW_CFG(s)->dma_enabled) { + memory_region_init_io(&FW_CFG(s)->dma_iomem, OBJECT(s), + &fw_cfg_dma_mem_ops, FW_CFG(s), "fwcfg.dma", + sizeof(dma_addr_t)); + sysbus_init_mmio(sbd, &FW_CFG(s)->dma_iomem); + } } static void fw_cfg_mem_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci/msi.c b/hw/pci/msi.c index f9c0484420..c1dd5318c8 100644 --- a/hw/pci/msi.c +++ b/hw/pci/msi.c @@ -294,7 +294,7 @@ void msi_send_message(PCIDevice *dev, MSIMessage msg) { MemTxAttrs attrs = {}; - attrs.stream_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; + attrs.requester_id = pci_requester_id(dev); address_space_stl_le(&dev->bus_master_as, msg.address, msg.data, attrs, NULL); } diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 46e0ad8a93..98d2c183b0 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -979,7 +979,7 @@ static int do_pcie_aer_inject_error(Monitor *mon, } } err.status = error_status; - err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn; + err.source_id = pci_requester_id(dev); err.flags = 0; if (correctable) { diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d1b0e53668..3852ad1967 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1169,6 +1169,7 @@ static int spapr_vga_init(PCIBus *pci_bus) case VGA_DEVICE: return true; case VGA_STD: + case VGA_VIRTIO: return pci_vga_init(pci_bus) != NULL; default: fprintf(stderr, "This vga model is not supported," diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 31473e749e..5f7f34900a 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -95,6 +95,11 @@ static const VMStateDescription vmstate_ipl = { } }; +static S390IPLState *get_ipl_device(void) +{ + return S390_IPL(object_resolve_path_type("", TYPE_S390_IPL, NULL)); +} + static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr) { uint64_t dstaddr = *(uint64_t *) opaque; @@ -218,7 +223,7 @@ static Property s390_ipl_properties[] = { * - -1 if no valid boot device was found * - ccw id of the boot device otherwise */ -static uint64_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl) +static uint64_t s390_update_iplstate(S390IPLState *ipl) { DeviceState *dev_st; @@ -251,25 +256,19 @@ out: return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno); } -int s390_ipl_update_diag308(IplParameterBlock *iplb) +void s390_ipl_update_diag308(IplParameterBlock *iplb) { - S390IPLState *ipl; + S390IPLState *ipl = get_ipl_device(); - ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); - if (ipl) { - ipl->iplb = *iplb; - ipl->iplb_valid = true; - return 0; - } - return -1; + ipl->iplb = *iplb; + ipl->iplb_valid = true; } IplParameterBlock *s390_ipl_get_iplb(void) { - S390IPLState *ipl; + S390IPLState *ipl = get_ipl_device(); - ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); - if (!ipl || !ipl->iplb_valid) { + if (!ipl->iplb_valid) { return NULL; } return &ipl->iplb; @@ -277,33 +276,33 @@ IplParameterBlock *s390_ipl_get_iplb(void) void s390_reipl_request(void) { - S390IPLState *ipl; + S390IPLState *ipl = get_ipl_device(); - ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); ipl->reipl_requested = true; qemu_system_reset_request(); } +void s390_ipl_prepare_cpu(S390CPU *cpu) +{ + S390IPLState *ipl = get_ipl_device(); + + cpu->env.psw.addr = ipl->start_addr; + cpu->env.psw.mask = IPL_PSW_MASK; + + if (!ipl->kernel || ipl->iplb_valid) { + cpu->env.psw.addr = ipl->bios_start_addr; + cpu->env.regs[7] = s390_update_iplstate(ipl); + } +} + static void s390_ipl_reset(DeviceState *dev) { S390IPLState *ipl = S390_IPL(dev); - S390CPU *cpu = S390_CPU(qemu_get_cpu(0)); - CPUS390XState *env = &cpu->env; - - env->psw.addr = ipl->start_addr; - env->psw.mask = IPL_PSW_MASK; if (!ipl->reipl_requested) { ipl->iplb_valid = false; } ipl->reipl_requested = false; - - if (!ipl->kernel || ipl->iplb_valid) { - env->psw.addr = ipl->bios_start_addr; - env->regs[7] = s390_update_iplstate(env, ipl); - } - - s390_cpu_set_state(CPU_STATE_OPERATING, cpu); } static void s390_ipl_class_init(ObjectClass *klass, void *data) diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 70497bc65f..7f2b4033d4 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -12,13 +12,16 @@ #ifndef HW_S390_IPL_H #define HW_S390_IPL_H +#include "cpu.h" + typedef struct IplParameterBlock { uint8_t reserved1[110]; uint16_t devno; uint8_t reserved2[88]; } IplParameterBlock; -int s390_ipl_update_diag308(IplParameterBlock *iplb); +void s390_ipl_update_diag308(IplParameterBlock *iplb); +void s390_ipl_prepare_cpu(S390CPU *cpu); IplParameterBlock *s390_ipl_get_iplb(void); void s390_reipl_request(void); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 6195f132fc..faba773592 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -35,26 +35,23 @@ typedef struct S390CcwMachineState { bool dea_key_wrap; } S390CcwMachineState; +static const char *const reset_dev_types[] = { + "virtual-css-bridge", + "s390-sclp-event-facility", + "s390-flic", + "diag288", +}; + void subsystem_reset(void) { - DeviceState *css, *sclp, *flic, *diag288; + DeviceState *dev; + int i; - css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL)); - if (css) { - qdev_reset_all(css); - } - sclp = DEVICE(object_resolve_path_type("", - "s390-sclp-event-facility", NULL)); - if (sclp) { - qdev_reset_all(sclp); - } - flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL)); - if (flic) { - qdev_reset_all(flic); - } - diag288 = DEVICE(object_resolve_path_type("", "diag288", NULL)); - if (diag288) { - qdev_reset_all(diag288); + for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { + dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); + if (dev) { + qdev_reset_all(dev); + } } } @@ -164,6 +161,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) NMIClass *nc = NMI_CLASS(oc); mc->init = ccw_init; + mc->reset = s390_machine_reset; mc->block_default_type = IF_VIRTIO; mc->no_cdrom = 1; mc->no_floppy = 1; @@ -262,6 +260,18 @@ static const TypeInfo ccw_machine_info = { .driver = "virtio-rng-ccw",\ .property = "max_revision",\ .value = "0",\ + },{\ + .driver = "virtio-net-ccw",\ + .property = "max_revision",\ + .value = "0",\ + },{\ + .driver = "virtio-scsi-ccw",\ + .property = "max_revision",\ + .value = "0",\ + },{\ + .driver = "vhost-scsi-ccw",\ + .property = "max_revision",\ + .value = "0",\ }, static void ccw_machine_2_4_class_init(ObjectClass *oc, void *data) diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index bc013eb3d4..cbde9772e5 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -40,6 +40,7 @@ #include "hw/s390x/s390_flic.h" #include "hw/s390x/s390-virtio.h" #include "hw/s390x/storage-keys.h" +#include "hw/s390x/ipl.h" #include "cpu.h" //#define DEBUG_S390 @@ -314,6 +315,19 @@ void s390_nmi(NMIState *n, int cpu_index, Error **errp) } } +void s390_machine_reset(void) +{ + S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); + + qemu_devices_reset(); + s390_cmma_reset(); + s390_crypto_reset(); + + /* all cpus are stopped - configure and start the ipl cpu only */ + s390_ipl_prepare_cpu(ipl_cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu); +} + static void s390_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -322,6 +336,7 @@ static void s390_machine_class_init(ObjectClass *oc, void *data) mc->alias = "s390"; mc->desc = "VirtIO based S390 machine"; mc->init = s390_init; + mc->reset = s390_machine_reset; mc->block_default_type = IF_VIRTIO; mc->max_cpus = 255; mc->no_serial = 1; diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h index f389aa1a67..eebce8e5e6 100644 --- a/hw/s390x/s390-virtio.h +++ b/hw/s390x/s390-virtio.h @@ -27,5 +27,6 @@ void s390_init_ipl_dev(const char *kernel_filename, bool enforce_bios); void s390_create_virtio_net(BusState *bus, const char *name); void s390_nmi(NMIState *n, int cpu_index, Error **errp); +void s390_machine_reset(void); void s390_memory_init(ram_addr_t mem_size); #endif diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index a04369c5ad..dcd724e6a5 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -431,7 +431,7 @@ static uint64_t megasas_fw_time(void) static uint64_t megasas_get_sata_addr(uint16_t id) { uint64_t addr = (0x1221ULL << 48); - return addr & (id << 24); + return addr | ((uint64_t)id << 24); } /* diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ffac8f4bb6..d373c1b676 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -558,7 +558,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, const int memset_off = offsetof(SCSIRequest, sense) + sizeof(req->sense); - req = g_slice_alloc(reqops->size); + req = g_malloc(reqops->size); memset((uint8_t *)req + memset_off, 0, reqops->size - memset_off); req->refcount = 1; req->bus = bus; @@ -1622,7 +1622,7 @@ void scsi_req_unref(SCSIRequest *req) } object_unref(OBJECT(req->dev)); object_unref(OBJECT(qbus->parent)); - g_slice_free1(req->ops->size, req); + g_free(req); } } diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 5575648a98..1248fd93ee 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -57,7 +57,7 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, return NULL; } - r = g_slice_new(VirtIOSCSIVring); + r = g_new(VirtIOSCSIVring, 1); r->host_notifier = *virtio_queue_get_host_notifier(vq); r->guest_notifier = *virtio_queue_get_guest_notifier(vq); aio_set_event_notifier(s->ctx, &r->host_notifier, handler); @@ -73,7 +73,7 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, fail_vring: aio_set_event_notifier(s->ctx, &r->host_notifier, NULL); k->set_host_notifier(qbus->parent, n, false); - g_slice_free(VirtIOSCSIVring, r); + g_free(r); return NULL; } @@ -182,18 +182,18 @@ static void virtio_scsi_vring_teardown(VirtIOSCSI *s) if (s->ctrl_vring) { vring_teardown(&s->ctrl_vring->vring, vdev, 0); - g_slice_free(VirtIOSCSIVring, s->ctrl_vring); + g_free(s->ctrl_vring); s->ctrl_vring = NULL; } if (s->event_vring) { vring_teardown(&s->event_vring->vring, vdev, 1); - g_slice_free(VirtIOSCSIVring, s->event_vring); + g_free(s->event_vring); s->event_vring = NULL; } if (s->cmd_vrings) { for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) { vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i); - g_slice_free(VirtIOSCSIVring, s->cmd_vrings[i]); + g_free(s->cmd_vrings[i]); s->cmd_vrings[i] = NULL; } free(s->cmd_vrings); diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 1c33f146a7..20885fb7f1 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -47,7 +47,7 @@ VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) const size_t zero_skip = offsetof(VirtIOSCSIReq, elem) + sizeof(VirtQueueElement); - req = g_slice_alloc(sizeof(*req) + vs->cdb_size); + req = g_malloc(sizeof(*req) + vs->cdb_size); req->vq = vq; req->dev = s; qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory); @@ -58,11 +58,9 @@ VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) void virtio_scsi_free_req(VirtIOSCSIReq *req) { - VirtIOSCSICommon *vs = (VirtIOSCSICommon *)req->dev; - qemu_iovec_destroy(&req->resp_iov); qemu_sglist_destroy(&req->qsgl); - g_slice_free1(sizeof(*req) + vs->cdb_size, req); + g_free(req); } static void virtio_scsi_complete_req(VirtIOSCSIReq *req) @@ -250,7 +248,7 @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) if (--n->tmf_req->remaining == 0) { virtio_scsi_complete_req(n->tmf_req); } - g_slice_free(VirtIOSCSICancelNotifier, n); + g_free(n); } /* Return 0 if the request is ready to be completed and return to guest; @@ -301,7 +299,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) VirtIOSCSICancelNotifier *notifier; req->remaining = 1; - notifier = g_slice_new(VirtIOSCSICancelNotifier); + notifier = g_new(VirtIOSCSICancelNotifier, 1); notifier->tmf_req = req; notifier->notifier.notify = virtio_scsi_cancel_notify; scsi_req_cancel_async(r, ¬ifier->notifier); @@ -350,7 +348,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) VirtIOSCSICancelNotifier *notifier; req->remaining++; - notifier = g_slice_new(VirtIOSCSICancelNotifier); + notifier = g_new(VirtIOSCSICancelNotifier, 1); notifier->notifier.notify = virtio_scsi_cancel_notify; notifier->tmf_req = req; scsi_req_cancel_async(r, ¬ifier->notifier); diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 5f39e1e3ac..ee6b43abc6 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -655,9 +655,12 @@ void hmp_info_usb(Monitor *mon, const QDict *qdict) dev = port->dev; if (!dev) continue; - monitor_printf(mon, " Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n", - bus->busnr, dev->addr, port->path, usb_speed(dev->speed), - dev->product_desc); + monitor_printf(mon, " Device %d.%d, Port %s, Speed %s Mb/s, " + "Product %s%s%s\n", + bus->busnr, dev->addr, port->path, + usb_speed(dev->speed), dev->product_desc, + dev->qdev.id ? ", ID: " : "", + dev->qdev.id ?: ""); } } } diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index f092bb8496..02fb1103c6 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -664,7 +664,7 @@ static const VMStateDescription vmstate_usb_audio = { static Property usb_audio_properties[] = { DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0), DEFINE_PROP_UINT32("buffer", USBAudioState, buffer, - 8 * USBAUDIO_PACKET_SIZE), + 32 * USBAUDIO_PACKET_SIZE), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 5e492fda0f..7695a97143 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -451,6 +451,7 @@ static void usb_host_req_complete_iso(struct libusb_transfer *transfer) } if (xfer->ring->ep->pid == USB_TOKEN_IN) { QTAILQ_INSERT_TAIL(&xfer->ring->copy, xfer, next); + usb_wakeup(xfer->ring->ep, 0); } else { QTAILQ_INSERT_TAIL(&xfer->ring->unused, xfer, next); } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index dcabb6d3b3..8fadbcf682 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -424,7 +424,7 @@ static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, return; } - virq = kvm_irqchip_add_msi_route(kvm_state, *msg); + virq = kvm_irqchip_add_msi_route(kvm_state, *msg, &vdev->pdev); if (virq < 0) { event_notifier_cleanup(&vector->kvm_interrupt); return; @@ -449,9 +449,10 @@ static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector) event_notifier_cleanup(&vector->kvm_interrupt); } -static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg) +static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg, + PCIDevice *pdev) { - kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg); + kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg, pdev); } static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, @@ -486,7 +487,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, if (!msg) { vfio_remove_kvm_msi_virq(vector); } else { - vfio_update_kvm_msi_virq(vector, *msg); + vfio_update_kvm_msi_virq(vector, *msg, pdev); } } else { vfio_add_kvm_msi_virq(vdev, vector, msg, true); @@ -760,7 +761,7 @@ static void vfio_update_msi(VFIOPCIDevice *vdev) } msg = msi_get_message(&vdev->pdev, i); - vfio_update_kvm_msi_virq(vector, msg); + vfio_update_kvm_msi_virq(vector, msg, &vdev->pdev); } } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index e5c406d1d2..f55dd2bf8e 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -590,7 +590,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, int ret; if (irqfd->users == 0) { - ret = kvm_irqchip_add_msi_route(kvm_state, msg); + ret = kvm_irqchip_add_msi_route(kvm_state, msg, &proxy->pci_dev); if (ret < 0) { return ret; } @@ -726,7 +726,8 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, if (proxy->vector_irqfd) { irqfd = &proxy->vector_irqfd[vector]; if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) { - ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg); + ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg, + &proxy->pci_dev); if (ret < 0) { return ret; } diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 72350f1418..c1bc5aef53 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -149,6 +149,28 @@ static void lx60_net_init(MemoryRegion *address_space, memory_region_add_subregion(address_space, buffers, ram); } +static pflash_t *xtfpga_flash_init(MemoryRegion *address_space, + const LxBoardDesc *board, + DriveInfo *dinfo, int be) +{ + SysBusDevice *s; + DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); + + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), + &error_abort); + qdev_prop_set_uint32(dev, "num-blocks", + board->flash_size / board->flash_sector_size); + qdev_prop_set_uint64(dev, "sector-length", board->flash_sector_size); + qdev_prop_set_uint8(dev, "width", 4); + qdev_prop_set_bit(dev, "big-endian", be); + qdev_prop_set_string(dev, "name", "lx60.io.flash"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + memory_region_add_subregion(address_space, board->flash_base, + sysbus_mmio_get_region(s, 0)); + return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01"); +} + static uint64_t translate_phys_addr(void *opaque, uint64_t addr) { XtensaCPU *cpu = opaque; @@ -247,16 +269,7 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine) dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { - flash = pflash_cfi01_register(board->flash_base, - NULL, "lx60.io.flash", board->flash_size, - blk_by_legacy_dinfo(dinfo), - board->flash_sector_size, - board->flash_size / board->flash_sector_size, - 4, 0x0000, 0x0000, 0x0000, 0x0000, be); - if (flash == NULL) { - error_report("unable to mount pflash"); - exit(EXIT_FAILURE); - } + flash = xtfpga_flash_init(system_io, board, dinfo, be); } /* Use presence of kernel file name as 'boot from SRAM' switch. */ @@ -386,7 +399,7 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine) static void xtensa_lx60_init(MachineState *machine) { static const LxBoardDesc lx60_board = { - .flash_base = 0xf8000000, + .flash_base = 0x08000000, .flash_size = 0x00400000, .flash_sector_size = 0x10000, .sram_size = 0x20000, @@ -397,7 +410,7 @@ static void xtensa_lx60_init(MachineState *machine) static void xtensa_lx200_init(MachineState *machine) { static const LxBoardDesc lx200_board = { - .flash_base = 0xf8000000, + .flash_base = 0x08000000, .flash_size = 0x01000000, .flash_sector_size = 0x20000, .sram_size = 0x2000000, @@ -408,7 +421,7 @@ static void xtensa_lx200_init(MachineState *machine) static void xtensa_ml605_init(MachineState *machine) { static const LxBoardDesc ml605_board = { - .flash_base = 0xf8000000, + .flash_base = 0x08000000, .flash_size = 0x01000000, .flash_sector_size = 0x20000, .sram_size = 0x2000000, @@ -419,7 +432,7 @@ static void xtensa_ml605_init(MachineState *machine) static void xtensa_kc705_init(MachineState *machine) { static const LxBoardDesc kc705_board = { - .flash_base = 0xf0000000, + .flash_base = 0x00000000, .flash_size = 0x08000000, .flash_boot_base = 0x06000000, .flash_sector_size = 0x20000, diff --git a/include/block/block.h b/include/block/block.h index 2dd66300ed..84f05ad408 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -4,7 +4,7 @@ #include "block/aio.h" #include "qemu-common.h" #include "qemu/option.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "block/accounting.h" #include "qapi/qmp/qobject.h" #include "qapi-types.h" @@ -203,12 +203,11 @@ BlockDriverState *bdrv_new(void); void bdrv_make_anon(BlockDriverState *bs); void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); +void bdrv_replace_in_backing_chain(BlockDriverState *old, + BlockDriverState *new); + int bdrv_parse_cache_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags); -int bdrv_open_image(BlockDriverState **pbs, const char *filename, - QDict *options, const char *bdref_key, - BlockDriverState* parent, const BdrvChildRole *child_role, - bool allow_none, Error **errp); BdrvChild *bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState* parent, @@ -585,7 +584,13 @@ typedef enum { BLKDBG_EVENT_MAX, } BlkDebugEvent; -#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt) +#define BLKDBG_EVENT(child, evt) \ + do { \ + if (child) { \ + bdrv_debug_event(child->bs, evt); \ + } \ + } while (0) + void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event); int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, diff --git a/include/block/block_int.h b/include/block/block_int.h index 14ad4c334b..a480f944cf 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -28,7 +28,7 @@ #include "block/block.h" #include "qemu/option.h" #include "qemu/queue.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qemu/timer.h" #include "qapi-types.h" #include "qemu/hbitmap.h" @@ -122,7 +122,6 @@ struct BlockDriver { int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); void (*bdrv_close)(BlockDriverState *bs); - void (*bdrv_rebind)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); @@ -339,6 +338,7 @@ struct BdrvChild { BlockDriverState *bs; const BdrvChildRole *role; QLIST_ENTRY(BdrvChild) next; + QLIST_ENTRY(BdrvChild) next_parent; }; /* @@ -378,9 +378,8 @@ struct BlockDriverState { QDict *full_open_options; char exact_filename[PATH_MAX]; - BlockDriverState *backing_hd; - BdrvChild *backing_child; - BlockDriverState *file; + BdrvChild *backing; + BdrvChild *file; NotifierList close_notifiers; @@ -446,6 +445,7 @@ struct BlockDriverState { * parent node of this node. */ BlockDriverState *inherits_from; QLIST_HEAD(, BdrvChild) children; + QLIST_HEAD(, BdrvChild) parents; QDict *options; BlockdevDetectZeroesOptions detect_zeroes; @@ -458,6 +458,11 @@ struct BlockDriverState { NotifierWithReturn write_threshold_notifier; }; +static inline BlockDriverState *backing_bs(BlockDriverState *bs) +{ + return bs->backing ? bs->backing->bs : NULL; +} + /* Essential block drivers which must always be statically linked into qemu, and * which therefore can be accessed without using bdrv_find_format() */ @@ -496,7 +501,7 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs, * * May be called from .bdrv_detach_aio_context() to detach children from the * current #AioContext. This is only needed by block drivers that manage their - * own children. Both ->file and ->backing_hd are automatically handled and + * own children. Both ->file and ->backing are automatically handled and * block drivers should not call this function on them explicitly. */ void bdrv_detach_aio_context(BlockDriverState *bs); @@ -506,7 +511,7 @@ void bdrv_detach_aio_context(BlockDriverState *bs); * * May be called from .bdrv_attach_aio_context() to attach children to the new * #AioContext. This is only needed by block drivers that manage their own - * children. Both ->file and ->backing_hd are automatically handled and block + * children. Both ->file and ->backing are automatically handled and block * drivers should not call this function on them explicitly. */ void bdrv_attach_aio_context(BlockDriverState *bs, @@ -655,6 +660,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, BlockCompletionFunc *cb, void *opaque, Error **errp); +void blk_set_bs(BlockBackend *blk, BlockDriverState *bs); + void blk_dev_change_media_cb(BlockBackend *blk, bool load); bool blk_dev_has_removable_media(BlockBackend *blk); void blk_dev_eject_request(BlockBackend *blk, bool force); @@ -663,5 +670,6 @@ bool blk_dev_is_medium_locked(BlockBackend *blk); void blk_dev_resize_cb(BlockBackend *blk); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); +bool bdrv_requests_pending(BlockDriverState *bs); #endif /* BLOCK_INT_H */ diff --git a/include/block/blockjob.h b/include/block/blockjob.h index dd9d5e6aad..289b13f0c0 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -65,6 +65,14 @@ struct BlockJob { BlockDriverState *bs; /** + * The ID of the block job. Currently the BlockBackend name of the BDS + * owning the job at the time when the job is started. + * + * TODO Decouple block job IDs from BlockBackend names + */ + char *id; + + /** * The coroutine that executes the job. If not NULL, it is * reentered when busy is false and the job is cancelled. */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index a63fd6015e..9b93b9b47d 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -84,8 +84,7 @@ void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); #if !defined(CONFIG_USER_ONLY) -bool qemu_in_vcpu_thread(void); -void cpu_reload_memory_map(CPUState *cpu); +void cpu_reloading_memory_map(void); void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as); /* cputlb.c */ /** @@ -357,8 +356,6 @@ extern uintptr_t tci_tb_ptr; #if !defined(CONFIG_USER_ONLY) -void phys_mem_set_alloc(void *(*alloc)(size_t, uint64_t *align)); - struct MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index); @@ -408,7 +405,4 @@ extern int singlestep; extern CPUState *tcg_current_cpu; extern bool exit_request; -#if !defined(CONFIG_USER_ONLY) -void migration_bitmap_extend(ram_addr_t old, ram_addr_t new); -#endif #endif diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h index f8537a8d91..e601061848 100644 --- a/include/exec/memattrs.h +++ b/include/exec/memattrs.h @@ -35,8 +35,8 @@ typedef struct MemTxAttrs { unsigned int secure:1; /* Memory access is usermode (unprivileged) */ unsigned int user:1; - /* Stream ID (for MSI for example) */ - unsigned int stream_id:16; + /* Requester ID (for MSI for example) */ + unsigned int requester_id:16; } MemTxAttrs; /* Bus masters which don't specify any attributes will get this, diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index c400a75a6a..3360ac5fde 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -289,5 +289,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest, return num_dirty; } +void migration_bitmap_extend(ram_addr_t old, ram_addr_t new); #endif #endif diff --git a/include/glib-compat.h b/include/glib-compat.h index 318e000368..fb25f437b4 100644 --- a/include/glib-compat.h +++ b/include/glib-compat.h @@ -165,4 +165,65 @@ static inline GThread *g_thread_new(const char *name, #define CompatGCond GCond #endif /* glib 2.31 */ +#ifndef g_assert_true +#define g_assert_true(expr) \ + do { \ + if (G_LIKELY(expr)) { \ + } else { \ + g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + "'" #expr "' should be TRUE"); \ + } \ + } while (0) +#endif + +#ifndef g_assert_false +#define g_assert_false(expr) \ + do { \ + if (G_LIKELY(!(expr))) { \ + } else { \ + g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + "'" #expr "' should be FALSE"); \ + } \ + } while (0) +#endif + +#ifndef g_assert_null +#define g_assert_null(expr) \ + do { \ + if (G_LIKELY((expr) == NULL)) { \ + } else { \ + g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + "'" #expr "' should be NULL"); \ + } \ + } while (0) +#endif + +#ifndef g_assert_nonnull +#define g_assert_nonnull(expr) \ + do { \ + if (G_LIKELY((expr) != NULL)) { \ + } else { \ + g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + "'" #expr "' should not be NULL"); \ + } \ + } while (0) +#endif + +#ifndef g_assert_cmpmem +#define g_assert_cmpmem(m1, l1, m2, l2) \ + do { \ + gconstpointer __m1 = m1, __m2 = m2; \ + int __l1 = l1, __l2 = l2; \ + if (__l1 != __l2) { \ + g_assertion_message_cmpnum( \ + G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==", \ + __l2, 'i'); \ + } else if (memcmp(__m1, __m2, __l1) != 0) { \ + g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + "assertion failed (" #m1 " == " #m2 ")"); \ + } \ + } while (0) +#endif + #endif diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index e60d3ca212..ee0cd8adb3 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -61,6 +61,15 @@ typedef struct FWCfgFiles { FWCfgFile f[]; } FWCfgFiles; +/* Control as first field allows for different structures selected by this + * field, which might be useful in the future + */ +typedef struct FWCfgDmaAccess { + uint32_t control; + uint32_t length; + uint64_t address; +} QEMU_PACKED FWCfgDmaAccess; + typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset); @@ -77,10 +86,13 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, void *data, size_t len); void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data, size_t len); +FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, + AddressSpace *dma_as); FWCfgState *fw_cfg_init_io(uint32_t iobase); FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr); -FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr, - uint32_t data_width); +FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, + hwaddr data_addr, uint32_t data_width, + hwaddr dma_addr, AddressSpace *dma_as); FWCfgState *fw_cfg_find(void); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 551cb3d608..f5e7fd818a 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -677,6 +677,11 @@ static inline uint32_t pci_config_size(const PCIDevice *d) return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; } +static inline uint16_t pci_requester_id(PCIDevice *dev) +{ + return (pci_bus_num(dev->bus) << 8) | dev->devfn; +} + /* DMA access functions */ static inline AddressSpace *pci_get_address_space(PCIDevice *dev) { diff --git a/include/qemu-common.h b/include/qemu-common.h index 0bd212b218..2f74540a87 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -246,6 +246,14 @@ int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end, #define STR_OR_NULL(str) ((str) ? (str) : "null") /* id.c */ + +typedef enum IdSubSystems { + ID_QDEV, + ID_BLOCK, + ID_MAX /* last element, used as array size */ +} IdSubSystems; + +char *id_generate(IdSubSystems id); bool id_wellformed(const char *id); /* path.c */ diff --git a/include/qemu/buffer.h b/include/qemu/buffer.h new file mode 100644 index 0000000000..b380cec6fa --- /dev/null +++ b/include/qemu/buffer.h @@ -0,0 +1,118 @@ +/* + * QEMU generic buffers + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QEMU_BUFFER_H__ +#define QEMU_BUFFER_H__ + +#include "qemu-common.h" + +typedef struct Buffer Buffer; + +/** + * Buffer: + * + * The Buffer object provides a simple dynamically resizing + * array, with separate tracking of capacity and usage. This + * is typically useful when buffering I/O or processing data. + */ + +struct Buffer { + size_t capacity; + size_t offset; + uint8_t *buffer; +}; + +/** + * buffer_reserve: + * @buffer: the buffer object + * @len: the minimum required free space + * + * Ensure that the buffer has space allocated for at least + * @len bytes. If the current buffer is too small, it will + * be reallocated, possibly to a larger size than requested. + */ +void buffer_reserve(Buffer *buffer, size_t len); + +/** + * buffer_reset: + * @buffer: the buffer object + * + * Reset the length of the stored data to zero, but do + * not free / reallocate the memory buffer + */ +void buffer_reset(Buffer *buffer); + +/** + * buffer_free: + * @buffer: the buffer object + * + * Reset the length of the stored data to zero and also + * free the internal memory buffer + */ +void buffer_free(Buffer *buffer); + +/** + * buffer_append: + * @buffer: the buffer object + * @data: the data block to append + * @len: the length of @data in bytes + * + * Append the contents of @data to the end of the buffer. + * The caller must ensure that the buffer has sufficient + * free space for @len bytes, typically by calling the + * buffer_reserve() method prior to appending. + */ +void buffer_append(Buffer *buffer, const void *data, size_t len); + +/** + * buffer_advance: + * @buffer: the buffer object + * @len: the number of bytes to skip + * + * Remove @len bytes of data from the head of the buffer. + * The internal buffer will not be reallocated, so will + * have at least @len bytes of free space after this + * call completes + */ +void buffer_advance(Buffer *buffer, size_t len); + +/** + * buffer_end: + * @buffer: the buffer object + * + * Get a pointer to the tail end of the internal buffer + * The returned pointer is only valid until the next + * call to buffer_reserve(). + * + * Returns: the tail of the buffer + */ +uint8_t *buffer_end(Buffer *buffer); + +/** + * buffer_empty: + * @buffer: the buffer object + * + * Determine if the buffer contains any current data + * + * Returns: true if the buffer holds data, false otherwise + */ +gboolean buffer_empty(Buffer *buffer); + +#endif /* QEMU_BUFFER_H__ */ diff --git a/include/block/coroutine.h b/include/qemu/coroutine.h index 20c027a7fd..20c027a7fd 100644 --- a/include/block/coroutine.h +++ b/include/qemu/coroutine.h diff --git a/include/block/coroutine_int.h b/include/qemu/coroutine_int.h index 9aa1aae5d5..42d6838401 100644 --- a/include/block/coroutine_int.h +++ b/include/qemu/coroutine_int.h @@ -26,7 +26,7 @@ #define QEMU_COROUTINE_INT_H #include "qemu/queue.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" typedef enum { COROUTINE_YIELD = 1, diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index ef21efb683..b56842420e 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -69,6 +69,8 @@ #include "sysemu/os-posix.h" #endif +#include "qapi/error.h" + #if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10 /* [u]int_fast*_t not in <sys/int_types.h> */ typedef unsigned char uint_fast8_t; @@ -286,4 +288,18 @@ void os_mem_prealloc(int fd, char *area, size_t sz); int qemu_read_password(char *buf, int buf_size); +/** + * qemu_fork: + * + * A version of fork that avoids signal handler race + * conditions that can lead to child process getting + * signals that are otherwise only expected by the + * parent. It also resets all signal handlers to the + * default settings. + * + * Returns 0 to child process, pid number to parent + * or -1 on failure. + */ +pid_t qemu_fork(Error **errp); + #endif diff --git a/include/qemu/queue.h b/include/qemu/queue.h index a8d3cb8e63..f781aa20a8 100644 --- a/include/qemu/queue.h +++ b/include/qemu/queue.h @@ -117,12 +117,6 @@ struct { \ } \ } while (/*CONSTCOND*/0) -#define QLIST_FIX_HEAD_PTR(head, field) do { \ - if ((head)->lh_first != NULL) { \ - (head)->lh_first->field.le_prev = &(head)->lh_first; \ - } \ -} while (/*CONSTCOND*/0) - #define QLIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index c174b5cbdd..5a183c570d 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -88,4 +88,38 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); int parse_host_port(struct sockaddr_in *saddr, const char *str); int socket_init(void); +/** + * socket_local_address: + * @fd: the socket file handle + * @errp: pointer to uninitialized error object + * + * Get the string representation of the local socket + * address. A pointer to the allocated address information + * struct will be returned, which the caller is required to + * release with a call qapi_free_SocketAddress when no + * longer required. + * + * Returns: the socket address struct, or NULL on error + */ +SocketAddress *socket_local_address(int fd, Error **errp); + +/** + * socket_remote_address: + * @fd: the socket file handle + * @errp: pointer to uninitialized error object + * + * Get the string representation of the remote socket + * address. A pointer to the allocated address information + * struct will be returned, which the caller is required to + * release with a call qapi_free_SocketAddress when no + * longer required. + * + * Returns: the socket address struct, or NULL on error + */ +SocketAddress *socket_remote_address(int fd, Error **errp); + + +void qapi_copy_SocketAddress(SocketAddress **p_dest, + SocketAddress *src); + #endif /* QEMU_SOCKET_H */ diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index ee1ce1d44d..d4a8f7a6d5 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -16,6 +16,7 @@ typedef struct BusClass BusClass; typedef struct BusState BusState; typedef struct CharDriverState CharDriverState; typedef struct CompatProperty CompatProperty; +typedef struct CPUAddressSpace CPUAddressSpace; typedef struct DeviceState DeviceState; typedef struct DeviceListener DeviceListener; typedef struct DisplayChangeListener DisplayChangeListener; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index b613ff0329..51a1323ead 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -234,6 +234,10 @@ struct kvm_run; * @can_do_io: Nonzero if memory-mapped IO is safe. Deterministic execution * requires that IO only be performed on the last instruction of a TB * so that interrupts take effect immediately. + * @cpu_ases: Pointer to array of CPUAddressSpaces (which define the + * AddressSpaces this CPU has) + * @as: Pointer to the first AddressSpace, for the convenience of targets which + * only have a single AddressSpace * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @gdb_regs: Additional GDB registers. @@ -280,9 +284,8 @@ struct CPUState { QemuMutex work_mutex; struct qemu_work_item *queued_work_first, *queued_work_last; + CPUAddressSpace *cpu_ases; AddressSpace *as; - struct AddressSpaceDispatch *memory_dispatch; - MemoryListener *tcg_as_listener; void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h index 99d311e4ad..c37c14e018 100644 --- a/include/standard-headers/asm-x86/hyperv.h +++ b/include/standard-headers/asm-x86/hyperv.h @@ -153,6 +153,12 @@ /* MSR used to provide vcpu index */ #define HV_X64_MSR_VP_INDEX 0x40000002 +/* MSR used to reset the guest OS. */ +#define HV_X64_MSR_RESET 0x40000003 + +/* MSR used to provide vcpu runtime in 100ns units */ +#define HV_X64_MSR_VP_RUNTIME 0x40000010 + /* MSR used to read the per-partition time reference counter */ #define HV_X64_MSR_TIME_REF_COUNT 0x40000020 diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 832b7fead4..edf76693d9 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -345,7 +345,9 @@ bool chr_is_ringbuf(const CharDriverState *chr); QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); void register_char_driver(const char *name, ChardevBackendKind kind, - void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)); + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp), + CharDriverState *(*create)(const char *id, ChardevBackend *backend, + ChardevReturn *ret, Error **errp)); /* add an eventfd to the qemu devices that are polled */ CharDriverState *qemu_chr_open_eventfd(int eventfd); @@ -354,18 +356,8 @@ extern int term_escape_char; CharDriverState *qemu_char_get_next_serial(void); -/* msmouse */ -CharDriverState *qemu_chr_open_msmouse(void); - -/* testdev.c */ -CharDriverState *chr_testdev_init(void); - -/* baum.c */ -CharDriverState *chr_baum_init(void); - /* console.c */ -typedef CharDriverState *(VcHandler)(ChardevVC *vc); - +typedef CharDriverState *(VcHandler)(ChardevVC *vc, Error **errp); void register_vc_handler(VcHandler *handler); -CharDriverState *vc_init(ChardevVC *vc); + #endif diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 3f162a9e08..30ddd1220e 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -2,6 +2,7 @@ #define QEMU_CPUS_H /* cpus.c */ +bool qemu_in_vcpu_thread(void); void qemu_init_cpu_loop(void); void resume_all_vcpus(void); void pause_all_vcpus(void); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 2a58b4d19e..461ef65dea 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -52,6 +52,7 @@ extern bool kvm_msi_via_irqfd_allowed; extern bool kvm_gsi_routing_allowed; extern bool kvm_gsi_direct_mapping; extern bool kvm_readonly_mem_allowed; +extern bool kvm_direct_msi_allowed; #if defined CONFIG_KVM || !defined NEED_CPU_H #define kvm_enabled() (kvm_allowed) @@ -145,6 +146,13 @@ extern bool kvm_readonly_mem_allowed; */ #define kvm_readonly_mem_enabled() (kvm_readonly_mem_allowed) +/** + * kvm_direct_msi_enabled: + * + * Returns: true if KVM allows direct MSI injection. + */ +#define kvm_direct_msi_enabled() (kvm_direct_msi_allowed) + #else #define kvm_enabled() (0) #define kvm_irqchip_in_kernel() (false) @@ -157,6 +165,7 @@ extern bool kvm_readonly_mem_allowed; #define kvm_gsi_routing_allowed() (false) #define kvm_gsi_direct_mapping() (false) #define kvm_readonly_mem_enabled() (false) +#define kvm_direct_msi_enabled() (false) #endif struct kvm_run; @@ -182,8 +191,6 @@ int kvm_has_sync_mmu(void); int kvm_has_vcpu_events(void); int kvm_has_robust_singlestep(void); int kvm_has_debugregs(void); -int kvm_has_xsave(void); -int kvm_has_xcrs(void); int kvm_has_pit_state2(void); int kvm_has_many_ioeventfds(void); int kvm_has_gsi_routing(void); @@ -210,6 +217,10 @@ int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset); int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_on_sigbus(int code, void *addr); +/* interface with exec.c */ + +void phys_mem_set_alloc(void *(*alloc)(size_t, uint64_t *align)); + /* internal API */ int kvm_ioctl(KVMState *s, int type, ...); @@ -313,7 +324,7 @@ int kvm_arch_on_sigbus(int code, void *addr); void kvm_arch_init_irq_routing(KVMState *s); int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data); + uint64_t address, uint32_t data, PCIDevice *dev); int kvm_arch_msi_data_to_gsi(uint32_t data); @@ -438,8 +449,9 @@ static inline void cpu_clean_state(CPUState *cpu) } } -int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg); -int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg); +int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg, PCIDevice *dev); +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, + PCIDevice *dev); void kvm_irqchip_release_virq(KVMState *s, int virq); int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter); diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index 0dff4229fc..f9ce357ff3 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -43,9 +43,7 @@ int qemu_spice_set_pw_expire(time_t expires); int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, const char *subject); -CharDriverState *qemu_chr_open_spice_vmc(const char *type); #if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(const char *name); void qemu_spice_register_ports(void); #else static inline CharDriverState *qemu_chr_open_spice_port(const char *name) @@ -77,8 +77,6 @@ struct KVMState #ifdef KVM_CAP_SET_GUEST_DEBUG struct kvm_sw_breakpoint_head kvm_sw_breakpoints; #endif - int pit_state2; - int xsave, xcrs; int many_ioeventfds; int intx_set_mask; /* The man page (and posix) say ioctl numbers are signed int, but @@ -93,7 +91,6 @@ struct KVMState uint32_t *used_gsi_bitmap; unsigned int gsi_count; QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; - bool direct_msi; #endif KVMMemoryListener memory_listener; }; @@ -111,6 +108,7 @@ bool kvm_gsi_direct_mapping; bool kvm_allowed; bool kvm_readonly_mem_allowed; bool kvm_vm_attributes_allowed; +bool kvm_direct_msi_allowed; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -642,15 +640,15 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, /* kvm works in page size chunks, but the function may be called with sub-page size and unaligned start address. Pad the start address to next and truncate size to previous page boundary. */ - delta = (TARGET_PAGE_SIZE - (start_addr & ~TARGET_PAGE_MASK)); - delta &= ~TARGET_PAGE_MASK; + delta = qemu_real_host_page_size - (start_addr & ~qemu_real_host_page_mask); + delta &= ~qemu_real_host_page_mask; if (delta > size) { return; } start_addr += delta; size -= delta; - size &= TARGET_PAGE_MASK; - if (!size || (start_addr & ~TARGET_PAGE_MASK)) { + size &= qemu_real_host_page_mask; + if (!size || (start_addr & ~qemu_real_host_page_mask)) { return; } @@ -979,7 +977,7 @@ void kvm_init_irq_routing(KVMState *s) s->irq_routes = g_malloc0(sizeof(*s->irq_routes)); s->nr_allocated_irq_routes = 0; - if (!s->direct_msi) { + if (!kvm_direct_msi_allowed) { for (i = 0; i < KVM_MSI_HASHTAB_SIZE; i++) { QTAILQ_INIT(&s->msi_hashtab[i]); } @@ -1113,7 +1111,7 @@ static int kvm_irqchip_get_virq(KVMState *s) * number can succeed even though a new route entry cannot be added. * When this happens, flush dynamic MSI entries to free IRQ route entries. */ - if (!s->direct_msi && s->irq_routes->nr == s->gsi_count) { + if (!kvm_direct_msi_allowed && s->irq_routes->nr == s->gsi_count) { kvm_flush_dynamic_msi_routes(s); } @@ -1150,7 +1148,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) struct kvm_msi msi; KVMMSIRoute *route; - if (s->direct_msi) { + if (kvm_direct_msi_allowed) { msi.address_lo = (uint32_t)msg.address; msi.address_hi = msg.address >> 32; msi.data = le32_to_cpu(msg.data); @@ -1189,7 +1187,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) return kvm_set_irq(s, route->kroute.gsi, 1); } -int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) +int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg, PCIDevice *dev) { struct kvm_irq_routing_entry kroute = {}; int virq; @@ -1213,7 +1211,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; kroute.u.msi.data = le32_to_cpu(msg.data); - if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data)) { + if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) { kvm_irqchip_release_virq(s, virq); return -EINVAL; } @@ -1224,7 +1222,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) return virq; } -int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, + PCIDevice *dev) { struct kvm_irq_routing_entry kroute = {}; @@ -1242,7 +1241,7 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; kroute.u.msi.data = le32_to_cpu(msg.data); - if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data)) { + if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) { return -EINVAL; } @@ -1585,20 +1584,8 @@ static int kvm_init(MachineState *ms) s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS); #endif -#ifdef KVM_CAP_XSAVE - s->xsave = kvm_check_extension(s, KVM_CAP_XSAVE); -#endif - -#ifdef KVM_CAP_XCRS - s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS); -#endif - -#ifdef KVM_CAP_PIT_STATE2 - s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2); -#endif - #ifdef KVM_CAP_IRQ_ROUTING - s->direct_msi = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0); + kvm_direct_msi_allowed = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0); #endif s->intx_set_mask = kvm_check_extension(s, KVM_CAP_PCI_2_3); @@ -2062,21 +2049,6 @@ int kvm_has_debugregs(void) return kvm_state->debugregs; } -int kvm_has_xsave(void) -{ - return kvm_state->xsave; -} - -int kvm_has_xcrs(void) -{ - return kvm_state->xcrs; -} - -int kvm_has_pit_state2(void) -{ - return kvm_state->pit_state2; -} - int kvm_has_many_ioeventfds(void) { if (!kvm_enabled()) { diff --git a/kvm-stub.c b/kvm-stub.c index d9ad624eee..a5051f7c6e 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -67,11 +67,6 @@ int kvm_has_many_ioeventfds(void) return 0; } -int kvm_has_pit_state2(void) -{ - return 0; -} - void kvm_setup_guest_memory(void *start, size_t size) { } @@ -115,7 +110,7 @@ int kvm_on_sigbus(int code, void *addr) } #ifndef CONFIG_USER_ONLY -int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) +int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg, PCIDevice *dev) { return -ENOSYS; } @@ -128,7 +123,8 @@ void kvm_irqchip_release_virq(KVMState *s, int virq) { } -int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, + PCIDevice *dev) { return -ENOSYS; } diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 683f713e91..dcc410efe7 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -183,6 +183,7 @@ struct kvm_s390_skeys { #define KVM_EXIT_EPR 23 #define KVM_EXIT_SYSTEM_EVENT 24 #define KVM_EXIT_S390_STSI 25 +#define KVM_EXIT_IOAPIC_EOI 26 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -237,6 +238,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; @@ -285,6 +287,7 @@ struct kvm_run { __u32 data; __u8 is_write; } dcr; + /* KVM_EXIT_INTERNAL_ERROR */ struct { __u32 suberror; /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */ @@ -295,6 +298,7 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; + /* KVM_EXIT_PAPR_HCALL */ struct { __u64 nr; __u64 ret; @@ -330,6 +334,10 @@ struct kvm_run { __u8 sel1; __u16 sel2; } s390_stsi; + /* KVM_EXIT_IOAPIC_EOI */ + struct { + __u8 vector; + } eoi; /* Fix the size of the union. */ char padding[256]; }; @@ -819,6 +827,10 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_DISABLE_QUIRKS 116 #define KVM_CAP_X86_SMM 117 #define KVM_CAP_MULTI_ADDRESS_SPACE 118 +#define KVM_CAP_GUEST_DEBUG_HW_BPS 119 +#define KVM_CAP_GUEST_DEBUG_HW_WPS 120 +#define KVM_CAP_SPLIT_IRQCHIP 121 +#define KVM_CAP_IOEVENTFD_ANY_LENGTH 122 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c index e3fd0859d6..49516b8643 100644 --- a/migration/qemu-file-buf.c +++ b/migration/qemu-file-buf.c @@ -29,7 +29,7 @@ #include "qemu/error-report.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "migration/qemu-file-internal.h" diff --git a/migration/qemu-file-stdio.c b/migration/qemu-file-stdio.c index 889ffb302c..9bde9db566 100644 --- a/migration/qemu-file-stdio.c +++ b/migration/qemu-file-stdio.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/qemu-file.h" typedef struct QEMUFileStdio { diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c index bf7a0e4a2b..809bf070d7 100644 --- a/migration/qemu-file-unix.c +++ b/migration/qemu-file-unix.c @@ -24,7 +24,7 @@ #include "qemu-common.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/qemu-file.h" #include "migration/qemu-file-internal.h" diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 49addf6d06..df49023ed8 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -26,7 +26,7 @@ #include "qemu/error-report.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "migration/qemu-file-internal.h" diff --git a/migration/rdma.c b/migration/rdma.c index 7a7176f7c9..553fbd7503 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -19,7 +19,7 @@ #include "qemu/main-loop.h" #include "qemu/sockets.h" #include "qemu/bitmap.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> @@ -19,7 +19,7 @@ #include "block/nbd.h" #include "sysemu/block-backend.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include <errno.h> #include <string.h> @@ -1005,7 +1005,7 @@ static NBDRequest *nbd_request_get(NBDClient *client) client->nb_requests++; nbd_update_can_read(client); - req = g_slice_new0(NBDRequest); + req = g_new0(NBDRequest, 1); nbd_client_get(client); req->client = client; return req; @@ -1018,7 +1018,7 @@ static void nbd_request_put(NBDRequest *req) if (req->data) { qemu_vfree(req->data); } - g_slice_free(NBDRequest, req); + g_free(req); client->nb_requests--; nbd_update_can_read(client); diff --git a/qapi-schema.json b/qapi-schema.json index 702b7b5dbd..f60be2950c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2614,7 +2614,9 @@ # # @host: host part of the address # -# @port: port part of the address, or lowest port if @to is present +# @port: port part of the address, or lowest port if @to is present. +# Kernel selects a free port if omitted for listener addresses. +# #optional # # @to: highest port to try # @@ -2629,7 +2631,7 @@ { 'struct': 'InetSocketAddress', 'data': { 'host': 'str', - 'port': 'str', + '*port': 'str', '*to': 'uint16', '*ipv4': 'bool', '*ipv6': 'bool' } } diff --git a/qemu-char.c b/qemu-char.c index 653ea10d6f..908e7124eb 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -92,31 +92,6 @@ /***********************************************************/ /* Socket address helpers */ -static void qapi_copy_SocketAddress(SocketAddress **p_dest, - SocketAddress *src) -{ - QmpOutputVisitor *qov; - QmpInputVisitor *qiv; - Visitor *ov, *iv; - QObject *obj; - - *p_dest = NULL; - - qov = qmp_output_visitor_new(); - ov = qmp_output_get_visitor(qov); - visit_type_SocketAddress(ov, &src, NULL, &error_abort); - obj = qmp_output_get_qobject(qov); - qmp_output_visitor_cleanup(qov); - if (!obj) { - return; - } - - qiv = qmp_input_visitor_new(obj); - iv = qmp_input_get_visitor(qiv); - visit_type_SocketAddress(iv, p_dest, NULL, &error_abort); - qmp_input_visitor_cleanup(qiv); - qobject_decref(obj); -} static int SocketAddress_to_str(char *dest, int max_len, const char *prefix, SocketAddress *addr, @@ -383,7 +358,10 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return len; } -static CharDriverState *qemu_chr_open_null(void) +static CharDriverState *qemu_chr_open_null(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { CharDriverState *chr; @@ -679,11 +657,20 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond) return d->drv->chr_add_watch(d->drv, cond); } -static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) +static CharDriverState *qemu_chr_open_mux(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { - CharDriverState *chr; + ChardevMux *mux = backend->mux; + CharDriverState *chr, *drv; MuxDriver *d; + drv = qemu_chr_find(mux->chardev); + if (drv == NULL) { + error_setg(errp, "mux: base chardev %s not found", mux->chardev); + return NULL; + } + chr = qemu_chr_alloc(); d = g_new0(MuxDriver, 1); @@ -1078,18 +1065,17 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) +static CharDriverState *qemu_chr_open_pipe(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + ChardevHostdev *opts = backend->pipe; int fd_in, fd_out; char filename_in[CHR_MAX_FILENAME_SIZE]; char filename_out[CHR_MAX_FILENAME_SIZE]; const char *filename = opts->device; - if (filename == NULL) { - fprintf(stderr, "chardev: pipe: no filename given\n"); - return NULL; - } - snprintf(filename_in, CHR_MAX_FILENAME_SIZE, "%s.in", filename); snprintf(filename_out, CHR_MAX_FILENAME_SIZE, "%s.out", filename); TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY)); @@ -1101,6 +1087,7 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) close(fd_out); TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY)); if (fd_in < 0) { + error_setg_file_open(errp, errno, filename); return NULL; } } @@ -1156,19 +1143,23 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr) fd_chr_close(chr); } -static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) +static CharDriverState *qemu_chr_open_stdio(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + ChardevStdio *opts = backend->stdio; CharDriverState *chr; struct sigaction act; if (is_daemonized()) { - error_report("cannot use stdio with -daemonize"); + error_setg(errp, "cannot use stdio with -daemonize"); return NULL; } if (stdio_in_use) { - error_report("cannot use stdio by multiple character devices"); - exit(1); + error_setg(errp, "cannot use stdio by multiple character devices"); + return NULL; } stdio_in_use = true; @@ -1196,7 +1187,8 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__GLIBC__) -#define HAVE_CHARDEV_TTY 1 +#define HAVE_CHARDEV_SERIAL 1 +#define HAVE_CHARDEV_PTY 1 typedef struct { GIOChannel *fd; @@ -1389,7 +1381,9 @@ static void pty_chr_close(struct CharDriverState *chr) } static CharDriverState *qemu_chr_open_pty(const char *id, - ChardevReturn *ret) + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { CharDriverState *chr; PtyCharDriver *s; @@ -1398,6 +1392,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id, master_fd = qemu_openpty_raw(&slave_fd, pty_name); if (master_fd < 0) { + error_setg_errno(errp, errno, "Failed to create PTY"); return NULL; } @@ -1752,12 +1747,13 @@ static void pp_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pp_fd(int fd) +static CharDriverState *qemu_chr_open_pp_fd(int fd, Error **errp) { CharDriverState *chr; ParallelCharDriver *drv; if (ioctl(fd, PPCLAIM) < 0) { + error_setg_errno(errp, errno, "not a parallel port"); close(fd); return NULL; } @@ -1817,7 +1813,7 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static CharDriverState *qemu_chr_open_pp_fd(int fd) +static CharDriverState *qemu_chr_open_pp_fd(int fd, Error **errp) { CharDriverState *chr; @@ -1832,6 +1828,8 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) #else /* _WIN32 */ +#define HAVE_CHARDEV_SERIAL 1 + typedef struct { int max_size; HANDLE hcom, hrecv, hsend; @@ -1883,7 +1881,7 @@ static void win_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static int win_chr_init(CharDriverState *chr, const char *filename) +static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp) { WinCharState *s = chr->opaque; COMMCONFIG comcfg; @@ -1894,25 +1892,25 @@ static int win_chr_init(CharDriverState *chr, const char *filename) s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); if (!s->hsend) { - fprintf(stderr, "Failed CreateEvent\n"); + error_setg(errp, "Failed CreateEvent"); goto fail; } s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); if (!s->hrecv) { - fprintf(stderr, "Failed CreateEvent\n"); + error_setg(errp, "Failed CreateEvent"); goto fail; } s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if (s->hcom == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError()); + error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); s->hcom = NULL; goto fail; } if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { - fprintf(stderr, "Failed SetupComm\n"); + error_setg(errp, "Failed SetupComm"); goto fail; } @@ -1923,23 +1921,23 @@ static int win_chr_init(CharDriverState *chr, const char *filename) CommConfigDialog(filename, NULL, &comcfg); if (!SetCommState(s->hcom, &comcfg.dcb)) { - fprintf(stderr, "Failed SetCommState\n"); + error_setg(errp, "Failed SetCommState"); goto fail; } if (!SetCommMask(s->hcom, EV_ERR)) { - fprintf(stderr, "Failed SetCommMask\n"); + error_setg(errp, "Failed SetCommMask"); goto fail; } cto.ReadIntervalTimeout = MAXDWORD; if (!SetCommTimeouts(s->hcom, &cto)) { - fprintf(stderr, "Failed SetCommTimeouts\n"); + error_setg(errp, "Failed SetCommTimeouts"); goto fail; } if (!ClearCommError(s->hcom, &err, &comstat)) { - fprintf(stderr, "Failed ClearCommError\n"); + error_setg(errp, "Failed ClearCommError"); goto fail; } qemu_add_polling_cb(win_chr_poll, chr); @@ -2044,7 +2042,8 @@ static int win_chr_poll(void *opaque) return 0; } -static CharDriverState *qemu_chr_open_win_path(const char *filename) +static CharDriverState *qemu_chr_open_win_path(const char *filename, + Error **errp) { CharDriverState *chr; WinCharState *s; @@ -2055,7 +2054,7 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename) chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - if (win_chr_init(chr, filename) < 0) { + if (win_chr_init(chr, filename, errp) < 0) { g_free(s); g_free(chr); return NULL; @@ -2079,7 +2078,8 @@ static int win_chr_pipe_poll(void *opaque) return 0; } -static int win_chr_pipe_init(CharDriverState *chr, const char *filename) +static int win_chr_pipe_init(CharDriverState *chr, const char *filename, + Error **errp) { WinCharState *s = chr->opaque; OVERLAPPED ov; @@ -2091,12 +2091,12 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); if (!s->hsend) { - fprintf(stderr, "Failed CreateEvent\n"); + error_setg(errp, "Failed CreateEvent"); goto fail; } s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); if (!s->hrecv) { - fprintf(stderr, "Failed CreateEvent\n"); + error_setg(errp, "Failed CreateEvent"); goto fail; } @@ -2106,7 +2106,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) PIPE_WAIT, MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); if (s->hcom == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError()); + error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError()); s->hcom = NULL; goto fail; } @@ -2115,13 +2115,13 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ret = ConnectNamedPipe(s->hcom, &ov); if (ret) { - fprintf(stderr, "Failed ConnectNamedPipe\n"); + error_setg(errp, "Failed ConnectNamedPipe"); goto fail; } ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); if (!ret) { - fprintf(stderr, "Failed GetOverlappedResult\n"); + error_setg(errp, "Failed GetOverlappedResult"); if (ov.hEvent) { CloseHandle(ov.hEvent); ov.hEvent = NULL; @@ -2142,8 +2142,12 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) } -static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) +static CharDriverState *qemu_chr_open_pipe(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + ChardevHostdev *opts = backend->pipe; const char *filename = opts->device; CharDriverState *chr; WinCharState *s; @@ -2154,7 +2158,7 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - if (win_chr_pipe_init(chr, filename) < 0) { + if (win_chr_pipe_init(chr, filename, errp) < 0) { g_free(s); g_free(chr); return NULL; @@ -2175,7 +2179,10 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) return chr; } -static CharDriverState *qemu_chr_open_win_con(void) +static CharDriverState *qemu_chr_open_win_con(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); } @@ -2316,7 +2323,10 @@ static void win_stdio_close(CharDriverState *chr) g_free(chr); } -static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) +static CharDriverState *qemu_chr_open_stdio(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { CharDriverState *chr; WinStdioCharState *stdio; @@ -2328,8 +2338,8 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); if (stdio->hStdIn == INVALID_HANDLE_VALUE) { - fprintf(stderr, "cannot open stdio: invalid handle\n"); - exit(1); + error_setg(errp, "cannot open stdio: invalid handle"); + return NULL; } is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; @@ -2341,25 +2351,30 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) if (is_console) { if (qemu_add_wait_object(stdio->hStdIn, win_stdio_wait_func, chr)) { - fprintf(stderr, "qemu_add_wait_object: failed\n"); + error_setg(errp, "qemu_add_wait_object: failed"); + goto err1; } } else { DWORD dwId; stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, - chr, 0, &dwId); - - if (stdio->hInputThread == INVALID_HANDLE_VALUE - || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE + if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { - fprintf(stderr, "cannot create stdio thread or event\n"); - exit(1); + error_setg(errp, "cannot create event"); + goto err2; } if (qemu_add_wait_object(stdio->hInputReadyEvent, win_stdio_thread_wait_func, chr)) { - fprintf(stderr, "qemu_add_wait_object: failed\n"); + error_setg(errp, "qemu_add_wait_object: failed"); + goto err2; + } + stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, + chr, 0, &dwId); + + if (stdio->hInputThread == INVALID_HANDLE_VALUE) { + error_setg(errp, "cannot create stdio thread"); + goto err3; } } @@ -2377,6 +2392,15 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) qemu_chr_fe_set_echo(chr, false); return chr; + +err3: + qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); +err2: + CloseHandle(stdio->hInputReadyEvent); + CloseHandle(stdio->hInputDoneEvent); +err1: + qemu_del_wait_object(stdio->hStdIn, NULL, NULL); + return NULL; } #endif /* !_WIN32 */ @@ -3173,9 +3197,12 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, +static CharDriverState *qemu_chr_open_ringbuf(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { + ChardevRingbuf *opts = backend->ringbuf; CharDriverState *chr; RingBufCharDriver *d; @@ -3462,6 +3489,7 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, backend->stdio->signal = qemu_opt_get_bool(opts, "signal", true); } +#ifdef HAVE_CHARDEV_SERIAL static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, Error **errp) { @@ -3474,7 +3502,9 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, backend->serial = g_new0(ChardevHostdev, 1); backend->serial->device = g_strdup(device); } +#endif +#ifdef HAVE_CHARDEV_PARPORT static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, Error **errp) { @@ -3487,6 +3517,7 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, backend->parallel = g_new0(ChardevHostdev, 1); backend->parallel->device = g_strdup(device); } +#endif static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, Error **errp) @@ -3641,12 +3672,16 @@ typedef struct CharDriver { const char *name; ChardevBackendKind kind; void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp); + CharDriverState *(*create)(const char *id, ChardevBackend *backend, + ChardevReturn *ret, Error **errp); } CharDriver; static GSList *backends; void register_char_driver(const char *name, ChardevBackendKind kind, - void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)) + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp), + CharDriverState *(*create)(const char *id, ChardevBackend *backend, + ChardevReturn *ret, Error **errp)) { CharDriver *s; @@ -3654,6 +3689,7 @@ void register_char_driver(const char *name, ChardevBackendKind kind, s->name = g_strdup(name); s->kind = kind; s->parse = parse; + s->create = create; backends = g_slist_append(backends, s); } @@ -4002,8 +4038,12 @@ QemuOptsList qemu_chardev_opts = { #ifdef _WIN32 -static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) +static CharDriverState *qmp_chardev_open_file(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + ChardevFile *file = backend->file; HANDLE out; if (file->has_in) { @@ -4020,17 +4060,13 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_win_file(out); } -static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, +static CharDriverState *qmp_chardev_open_serial(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { - return qemu_chr_open_win_path(serial->device); -} - -static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel, - Error **errp) -{ - error_setg(errp, "character device backend type 'parallel' not supported"); - return NULL; + ChardevHostdev *serial = backend->serial; + return qemu_chr_open_win_path(serial->device, errp); } #else /* WIN32 */ @@ -4047,8 +4083,12 @@ static int qmp_chardev_open_file_source(char *src, int flags, return fd; } -static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) +static CharDriverState *qmp_chardev_open_file(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + ChardevFile *file = backend->file; int flags, in = -1, out; flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY; @@ -4069,10 +4109,13 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_fd(in, out); } -static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, +#ifdef HAVE_CHARDEV_SERIAL +static CharDriverState *qmp_chardev_open_serial(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { -#ifdef HAVE_CHARDEV_TTY + ChardevHostdev *serial = backend->serial; int fd; fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); @@ -4081,28 +4124,25 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, } qemu_set_nonblock(fd); return qemu_chr_open_tty_fd(fd); -#else - error_setg(errp, "character device backend type 'serial' not supported"); - return NULL; -#endif } +#endif -static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel, +#ifdef HAVE_CHARDEV_PARPORT +static CharDriverState *qmp_chardev_open_parallel(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { -#ifdef HAVE_CHARDEV_PARPORT + ChardevHostdev *parallel = backend->parallel; int fd; fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp); if (fd < 0) { return NULL; } - return qemu_chr_open_pp_fd(fd); -#else - error_setg(errp, "character device backend type 'parallel' not supported"); - return NULL; -#endif + return qemu_chr_open_pp_fd(fd, errp); } +#endif #endif /* WIN32 */ @@ -4131,11 +4171,14 @@ static gboolean socket_reconnect_timeout(gpointer opaque) return false; } -static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, +static CharDriverState *qmp_chardev_open_socket(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { CharDriverState *chr; TCPCharDriver *s; + ChardevSocket *sock = backend->socket; SocketAddress *addr = sock->addr; bool do_nodelay = sock->has_nodelay ? sock->nodelay : false; bool is_listen = sock->has_server ? sock->server : true; @@ -4197,9 +4240,12 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, return chr; } -static CharDriverState *qmp_chardev_open_udp(ChardevUdp *udp, +static CharDriverState *qmp_chardev_open_udp(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { + ChardevUdp *udp = backend->udp; int fd; fd = socket_dgram(udp->remote, udp->local, errp); @@ -4213,7 +4259,10 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { ChardevReturn *ret = g_new0(ChardevReturn, 1); - CharDriverState *base, *chr = NULL; + CharDriverState *chr = NULL; + Error *local_err = NULL; + GSList *i; + CharDriver *cd; chr = qemu_chr_find(id); if (chr) { @@ -4222,106 +4271,40 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, return NULL; } - switch (backend->kind) { - case CHARDEV_BACKEND_KIND_FILE: - chr = qmp_chardev_open_file(backend->file, errp); - break; - case CHARDEV_BACKEND_KIND_SERIAL: - chr = qmp_chardev_open_serial(backend->serial, errp); - break; - case CHARDEV_BACKEND_KIND_PARALLEL: - chr = qmp_chardev_open_parallel(backend->parallel, errp); - break; - case CHARDEV_BACKEND_KIND_PIPE: - chr = qemu_chr_open_pipe(backend->pipe); - break; - case CHARDEV_BACKEND_KIND_SOCKET: - chr = qmp_chardev_open_socket(backend->socket, errp); - break; - case CHARDEV_BACKEND_KIND_UDP: - chr = qmp_chardev_open_udp(backend->udp, errp); - break; -#ifdef HAVE_CHARDEV_TTY - case CHARDEV_BACKEND_KIND_PTY: - chr = qemu_chr_open_pty(id, ret); - break; -#endif - case CHARDEV_BACKEND_KIND_NULL: - chr = qemu_chr_open_null(); - break; - case CHARDEV_BACKEND_KIND_MUX: - base = qemu_chr_find(backend->mux->chardev); - if (base == NULL) { - error_setg(errp, "mux: base chardev %s not found", - backend->mux->chardev); + for (i = backends; i; i = i->next) { + cd = i->data; + + if (cd->kind == backend->kind) { + chr = cd->create(id, backend, ret, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto out_error; + } break; } - chr = qemu_chr_open_mux(base); - break; - case CHARDEV_BACKEND_KIND_MSMOUSE: - chr = qemu_chr_open_msmouse(); - break; -#ifdef CONFIG_BRLAPI - case CHARDEV_BACKEND_KIND_BRAILLE: - chr = chr_baum_init(); - break; -#endif - case CHARDEV_BACKEND_KIND_TESTDEV: - chr = chr_testdev_init(); - break; - case CHARDEV_BACKEND_KIND_STDIO: - chr = qemu_chr_open_stdio(backend->stdio); - break; -#ifdef _WIN32 - case CHARDEV_BACKEND_KIND_CONSOLE: - chr = qemu_chr_open_win_con(); - break; -#endif -#ifdef CONFIG_SPICE - case CHARDEV_BACKEND_KIND_SPICEVMC: - chr = qemu_chr_open_spice_vmc(backend->spicevmc->type); - break; - case CHARDEV_BACKEND_KIND_SPICEPORT: - chr = qemu_chr_open_spice_port(backend->spiceport->fqdn); - break; -#endif - case CHARDEV_BACKEND_KIND_VC: - chr = vc_init(backend->vc); - break; - case CHARDEV_BACKEND_KIND_RINGBUF: - case CHARDEV_BACKEND_KIND_MEMORY: - chr = qemu_chr_open_ringbuf(backend->ringbuf, errp); - break; - default: - error_setg(errp, "unknown chardev backend (%d)", backend->kind); - break; } - /* - * Character backend open hasn't been fully converted to the Error - * API. Some opens fail without setting an error. Set a generic - * error then. - * TODO full conversion to Error API - */ - if (chr == NULL && errp && !*errp) { - error_setg(errp, "Failed to create chardev"); + if (chr == NULL) { + assert(!i); + error_setg(errp, "chardev backend not available"); + goto out_error; } - if (chr) { - chr->label = g_strdup(id); - chr->avail_connections = - (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1; - if (!chr->filename) { - chr->filename = g_strdup(ChardevBackendKind_lookup[backend->kind]); - } - if (!chr->explicit_be_open) { - qemu_chr_be_event(chr, CHR_EVENT_OPENED); - } - QTAILQ_INSERT_TAIL(&chardevs, chr, next); - return ret; - } else { - g_free(ret); - return NULL; + + chr->label = g_strdup(id); + chr->avail_connections = + (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1; + if (!chr->filename) { + chr->filename = g_strdup(ChardevBackendKind_lookup[backend->kind]); + } + if (!chr->explicit_be_open) { + qemu_chr_be_event(chr, CHR_EVENT_OPENED); } + QTAILQ_INSERT_TAIL(&chardevs, chr, next); + return ret; + +out_error: + g_free(ret); + return NULL; } void qmp_chardev_remove(const char *id, Error **errp) @@ -4343,32 +4326,45 @@ void qmp_chardev_remove(const char *id, Error **errp) static void register_types(void) { - register_char_driver("null", CHARDEV_BACKEND_KIND_NULL, NULL); + register_char_driver("null", CHARDEV_BACKEND_KIND_NULL, NULL, + qemu_chr_open_null); register_char_driver("socket", CHARDEV_BACKEND_KIND_SOCKET, - qemu_chr_parse_socket); - register_char_driver("udp", CHARDEV_BACKEND_KIND_UDP, qemu_chr_parse_udp); + qemu_chr_parse_socket, qmp_chardev_open_socket); + register_char_driver("udp", CHARDEV_BACKEND_KIND_UDP, qemu_chr_parse_udp, + qmp_chardev_open_udp); register_char_driver("ringbuf", CHARDEV_BACKEND_KIND_RINGBUF, - qemu_chr_parse_ringbuf); + qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf); register_char_driver("file", CHARDEV_BACKEND_KIND_FILE, - qemu_chr_parse_file_out); + qemu_chr_parse_file_out, qmp_chardev_open_file); register_char_driver("stdio", CHARDEV_BACKEND_KIND_STDIO, - qemu_chr_parse_stdio); + qemu_chr_parse_stdio, qemu_chr_open_stdio); +#if defined HAVE_CHARDEV_SERIAL register_char_driver("serial", CHARDEV_BACKEND_KIND_SERIAL, - qemu_chr_parse_serial); + qemu_chr_parse_serial, qmp_chardev_open_serial); register_char_driver("tty", CHARDEV_BACKEND_KIND_SERIAL, - qemu_chr_parse_serial); + qemu_chr_parse_serial, qmp_chardev_open_serial); +#endif +#ifdef HAVE_CHARDEV_PARPORT register_char_driver("parallel", CHARDEV_BACKEND_KIND_PARALLEL, - qemu_chr_parse_parallel); + qemu_chr_parse_parallel, qmp_chardev_open_parallel); register_char_driver("parport", CHARDEV_BACKEND_KIND_PARALLEL, - qemu_chr_parse_parallel); - register_char_driver("pty", CHARDEV_BACKEND_KIND_PTY, NULL); - register_char_driver("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL); + qemu_chr_parse_parallel, qmp_chardev_open_parallel); +#endif +#ifdef HAVE_CHARDEV_PTY + register_char_driver("pty", CHARDEV_BACKEND_KIND_PTY, NULL, + qemu_chr_open_pty); +#endif +#ifdef _WIN32 + register_char_driver("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL, + qemu_chr_open_win_con); +#endif register_char_driver("pipe", CHARDEV_BACKEND_KIND_PIPE, - qemu_chr_parse_pipe); - register_char_driver("mux", CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux); + qemu_chr_parse_pipe, qemu_chr_open_pipe); + register_char_driver("mux", CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux, + qemu_chr_open_mux); /* Bug-compatibility: */ register_char_driver("memory", CHARDEV_BACKEND_KIND_MEMORY, - qemu_chr_parse_ringbuf); + qemu_chr_parse_ringbuf, qemu_chr_open_ringbuf); /* this must be done after machine init, since we register FEs with muxes * as part of realize functions like serial_isa_realizefn when -nographic * is specified diff --git a/qemu-img.c b/qemu-img.c index 7d65c0a78c..3025776e14 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -748,7 +748,7 @@ static int img_commit(int argc, char **argv) /* This is different from QMP, which by default uses the deepest file in * the backing chain (i.e., the very base); however, the traditional * behavior of qemu-img commit is using the immediate backing file. */ - base_bs = bs->backing_hd; + base_bs = backing_bs(bs); if (!base_bs) { error_setg(&local_err, "Image does not have a backing file"); goto done; @@ -766,12 +766,12 @@ static int img_commit(int argc, char **argv) goto done; } - /* The block job will swap base_bs and bs (which is not what we really want - * here, but okay) and unref base_bs (after the swap, i.e., the old top - * image). In order to still be able to empty that top image afterwards, - * increment the reference counter here preemptively. */ + /* When the block job completes, the BlockBackend reference will point to + * the old backing file. In order to avoid that the top image is already + * deleted, so we can still empty it afterwards, increment the reference + * counter here preemptively. */ if (!drop) { - bdrv_ref(base_bs); + bdrv_ref(bs); } run_block_job(bs->job, &local_err); @@ -779,8 +779,8 @@ static int img_commit(int argc, char **argv) goto unref_backing; } - if (!drop && base_bs->drv->bdrv_make_empty) { - ret = base_bs->drv->bdrv_make_empty(base_bs); + if (!drop && bs->drv->bdrv_make_empty) { + ret = bs->drv->bdrv_make_empty(bs); if (ret) { error_setg_errno(&local_err, -ret, "Could not empty %s", filename); @@ -790,7 +790,7 @@ static int img_commit(int argc, char **argv) unref_backing: if (!drop) { - bdrv_unref(base_bs); + bdrv_unref(bs); } done: @@ -2207,7 +2207,7 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num, if (ret & (BDRV_BLOCK_ZERO|BDRV_BLOCK_DATA)) { break; } - bs = bs->backing_hd; + bs = backing_bs(bs); if (bs == NULL) { ret = 0; break; diff --git a/qemu-nbd.c b/qemu-nbd.c index 6428c15403..422a607bdd 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -98,9 +98,7 @@ static void usage(const char *name) " '[ID_OR_NAME]'\n" " -n, --nocache disable host cache\n" " --cache=MODE set cache mode (none, writeback, ...)\n" -#ifdef CONFIG_LINUX_AIO " --aio=MODE set AIO mode (native or threads)\n" -#endif " --discard=MODE set discard mode (ignore, unmap)\n" " --detect-zeroes=MODE set detect-zeroes mode (off, on, unmap)\n" "\n" @@ -412,9 +410,7 @@ int main(int argc, char **argv) { "load-snapshot", 1, NULL, 'l' }, { "nocache", 0, NULL, 'n' }, { "cache", 1, NULL, QEMU_NBD_OPT_CACHE }, -#ifdef CONFIG_LINUX_AIO { "aio", 1, NULL, QEMU_NBD_OPT_AIO }, -#endif { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD }, { "detect-zeroes", 1, NULL, QEMU_NBD_OPT_DETECT_ZEROES }, { "shared", 1, NULL, 'e' }, @@ -432,9 +428,7 @@ int main(int argc, char **argv) int fd; bool seen_cache = false; bool seen_discard = false; -#ifdef CONFIG_LINUX_AIO bool seen_aio = false; -#endif pthread_t client_thread; const char *fmt = NULL; Error *local_err = NULL; @@ -467,7 +461,6 @@ int main(int argc, char **argv) errx(EXIT_FAILURE, "Invalid cache mode `%s'", optarg); } break; -#ifdef CONFIG_LINUX_AIO case QEMU_NBD_OPT_AIO: if (seen_aio) { errx(EXIT_FAILURE, "--aio can only be specified once"); @@ -481,7 +474,6 @@ int main(int argc, char **argv) errx(EXIT_FAILURE, "invalid aio mode `%s'", optarg); } break; -#endif case QEMU_NBD_OPT_DISCARD: if (seen_discard) { errx(EXIT_FAILURE, "--discard can only be specified once"); diff --git a/qemu-options.hx b/qemu-options.hx index 2485b94b16..edee5f4844 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2724,13 +2724,18 @@ ETEXI DEF("fw_cfg", HAS_ARG, QEMU_OPTION_fwcfg, "-fw_cfg [name=]<name>,file=<file>\n" - " add named fw_cfg entry from file\n", + " add named fw_cfg entry from file\n" + "-fw_cfg [name=]<name>,string=<str>\n" + " add named fw_cfg entry from string\n", QEMU_ARCH_ALL) STEXI @item -fw_cfg [name=]@var{name},file=@var{file} @findex -fw_cfg Add named fw_cfg entry from file. @var{name} determines the name of the entry in the fw_cfg file directory exposed to the guest. + +@item -fw_cfg [name=]@var{name},string=@var{str} +Add named fw_cfg entry from string. ETEXI DEF("serial", HAS_ARG, QEMU_OPTION_serial, \ diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 8aad4fee9f..50d9dd3747 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -217,25 +217,24 @@ GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size) GIOStatus status = G_IO_STATUS_NORMAL; while (size) { + g_debug("sending data, count: %d", (int)size); status = g_io_channel_write_chars(c->client_channel, buf, size, &written, &err); - g_debug("sending data, count: %d", (int)size); - if (err != NULL) { + if (status == G_IO_STATUS_NORMAL) { + size -= written; + buf += written; + } else if (status != G_IO_STATUS_AGAIN) { g_warning("error writing to channel: %s", err->message); - return G_IO_STATUS_ERROR; - } - if (status != G_IO_STATUS_NORMAL) { - break; + return status; } - size -= written; } - if (status == G_IO_STATUS_NORMAL) { + do { status = g_io_channel_flush(c->client_channel, &err); - if (err != NULL) { - g_warning("error flushing channel: %s", err->message); - return G_IO_STATUS_ERROR; - } + } while (status == G_IO_STATUS_AGAIN); + + if (status != G_IO_STATUS_NORMAL) { + g_warning("error flushing channel: %s", err->message); } return status; @@ -249,7 +248,7 @@ GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count) GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, GAChannelCallback cb, gpointer opaque) { - GAChannel *c = g_malloc0(sizeof(GAChannel)); + GAChannel *c = g_new0(GAChannel, 1); c->event_cb = cb; c->user_data = opaque; diff --git a/qga/channel-win32.c b/qga/channel-win32.c index 04fa5e4d1d..0452b9f75e 100644 --- a/qga/channel-win32.c +++ b/qga/channel-win32.c @@ -269,7 +269,7 @@ static GIOStatus ga_channel_write(GAChannel *c, const char *buf, size_t size, GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size) { GIOStatus status = G_IO_STATUS_NORMAL; - size_t count; + size_t count = 0; while (size) { status = ga_channel_write(c, buf, size, &count); @@ -322,7 +322,7 @@ static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method, GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, GAChannelCallback cb, gpointer opaque) { - GAChannel *c = g_malloc0(sizeof(GAChannel)); + GAChannel *c = g_new0(GAChannel, 1); SECURITY_ATTRIBUTES sec_attrs; if (!ga_channel_open(c, method, path)) { diff --git a/qga/commands-posix.c b/qga/commands-posix.c index b03c316a5e..67a173af4f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -223,7 +223,9 @@ typedef struct GuestFileHandle { static struct { QTAILQ_HEAD(, GuestFileHandle) filehandles; -} guest_file_state; +} guest_file_state = { + .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles), +}; static int64_t guest_file_handle_add(FILE *fh, Error **errp) { @@ -235,7 +237,7 @@ static int64_t guest_file_handle_add(FILE *fh, Error **errp) return -1; } - gfh = g_malloc0(sizeof(GuestFileHandle)); + gfh = g_new0(GuestFileHandle, 1); gfh->id = handle; gfh->fh = fh; QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); @@ -488,7 +490,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, slog("guest-file-read failed, handle: %" PRId64, handle); } else { buf[read_count] = 0; - read_data = g_malloc0(sizeof(GuestFileRead)); + read_data = g_new0(GuestFileRead, 1); read_data->count = read_count; read_data->eof = feof(fh); if (read_count) { @@ -533,7 +535,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, 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)); + write_data = g_new0(GuestFileWrite, 1); write_data->count = write_count; write_data->eof = feof(fh); } @@ -586,11 +588,6 @@ void qmp_guest_file_flush(int64_t handle, Error **errp) } } -static void guest_file_init(void) -{ - QTAILQ_INIT(&guest_file_state.filehandles); -} - /* linux-specific implementations. avoid this if at all possible. */ #if defined(__linux__) @@ -678,7 +675,7 @@ static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) continue; } - mount = g_malloc0(sizeof(FsMount)); + mount = g_new0(FsMount, 1); mount->dirname = g_strdup(ment->mnt_dir); mount->devtype = g_strdup(ment->mnt_type); mount->devmajor = devmajor; @@ -757,7 +754,7 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp) } } - mount = g_malloc0(sizeof(FsMount)); + mount = g_new0(FsMount, 1); mount->dirname = g_strdup(line + dir_s); mount->devtype = g_strdup(dash + type_s); mount->devmajor = devmajor; @@ -2213,8 +2210,14 @@ GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp) dp = opendir("/sys/devices/system/memory/"); if (!dp) { - error_setg_errno(errp, errno, "Can't open directory" - "\"/sys/devices/system/memory/\"\n"); + /* it's ok if this happens to be a system that doesn't expose + * memory blocks via sysfs, but otherwise we should report + * an error + */ + if (errno != ENOENT) { + error_setg_errno(errp, errno, "Can't open directory" + "\"/sys/devices/system/memory/\"\n"); + } return NULL; } @@ -2486,5 +2489,4 @@ void ga_command_state_init(GAState *s, GACommandState *cs) #if defined(CONFIG_FSFREEZE) ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); #endif - ga_command_state_add(cs, guest_file_init, NULL); } diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 41bdd3f7cc..d9de23bbb8 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -55,7 +55,9 @@ typedef struct GuestFileHandle { static struct { QTAILQ_HEAD(, GuestFileHandle) filehandles; -} guest_file_state; +} guest_file_state = { + .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles), +}; typedef struct OpenFlags { @@ -106,7 +108,7 @@ static int64_t guest_file_handle_add(HANDLE fh, Error **errp) if (handle < 0) { return -1; } - gfh = g_malloc0(sizeof(GuestFileHandle)); + gfh = g_new0(GuestFileHandle, 1); gfh->id = handle; gfh->fh = fh; QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); @@ -298,7 +300,7 @@ GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, slog("guest-file-read failed, handle %" PRId64, handle); } else { buf[read_count] = 0; - read_data = g_malloc0(sizeof(GuestFileRead)); + read_data = g_new0(GuestFileRead, 1); read_data->count = (size_t)read_count; read_data->eof = read_count == 0; @@ -342,7 +344,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, error_setg_win32(errp, GetLastError(), "failed to write to file"); slog("guest-file-write-failed, handle: %" PRId64, handle); } else { - write_data = g_malloc0(sizeof(GuestFileWrite)); + write_data = g_new0(GuestFileWrite, 1); write_data->count = (size_t) write_count; } @@ -390,11 +392,6 @@ void qmp_guest_file_flush(int64_t handle, Error **errp) } } -static void guest_file_init(void) -{ - QTAILQ_INIT(&guest_file_state.filehandles); -} - #ifdef CONFIG_QGA_NTDDSCSI static STORAGE_BUS_TYPE win2qemu[] = { @@ -865,7 +862,7 @@ static DWORD WINAPI do_suspend(LPVOID opaque) void qmp_guest_suspend_disk(Error **errp) { Error *local_err = NULL; - GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); + GuestSuspendMode *mode = g_new(GuestSuspendMode, 1); *mode = GUEST_SUSPEND_MODE_DISK; check_suspend_mode(*mode, &local_err); @@ -881,7 +878,7 @@ void qmp_guest_suspend_disk(Error **errp) void qmp_guest_suspend_ram(Error **errp) { Error *local_err = NULL; - GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); + GuestSuspendMode *mode = g_new(GuestSuspendMode, 1); *mode = GUEST_SUSPEND_MODE_RAM; check_suspend_mode(*mode, &local_err); @@ -1330,5 +1327,4 @@ void ga_command_state_init(GAState *s, GACommandState *cs) if (!vss_initialized()) { ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); } - ga_command_state_add(cs, guest_file_init, NULL); } diff --git a/qga/commands.c b/qga/commands.c index 783496791e..0f80ce65a4 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -15,6 +15,11 @@ #include "qga-qmp-commands.h" #include "qapi/qmp/qerror.h" +/* Maximum captured guest-exec out_data/err_data - 16MB */ +#define GUEST_EXEC_MAX_OUTPUT (16*1024*1024) +/* Allocation and I/O buffer for reading guest-exec out_data/err_data - 4KB */ +#define GUEST_EXEC_IO_SIZE (4*1024) + /* Note: in some situations, like with the fsfreeze, logging may be * temporarilly disabled. if it is necessary that a command be able * to log for accounting purposes, check ga_logging_enabled() beforehand, @@ -51,12 +56,12 @@ static void qmp_command_info(QmpCommand *cmd, void *opaque) GuestAgentCommandInfo *cmd_info; GuestAgentCommandInfoList *cmd_info_list; - cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo)); + cmd_info = g_new0(GuestAgentCommandInfo, 1); cmd_info->name = g_strdup(qmp_command_name(cmd)); cmd_info->enabled = qmp_command_is_enabled(cmd); cmd_info->success_response = qmp_has_success_response(cmd); - cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList)); + cmd_info_list = g_new0(GuestAgentCommandInfoList, 1); cmd_info_list->value = cmd_info; cmd_info_list->next = info->supported_commands; info->supported_commands = cmd_info_list; @@ -64,9 +69,392 @@ static void qmp_command_info(QmpCommand *cmd, void *opaque) struct GuestAgentInfo *qmp_guest_info(Error **errp) { - GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo)); + GuestAgentInfo *info = g_new0(GuestAgentInfo, 1); info->version = g_strdup(QEMU_VERSION); qmp_for_each_command(qmp_command_info, info); return info; } + +struct GuestExecIOData { + guchar *data; + gsize size; + gsize length; + gint closed; + bool truncated; + const char *name; +}; +typedef struct GuestExecIOData GuestExecIOData; + +struct GuestExecInfo { + GPid pid; + int64_t pid_numeric; + gint status; + bool has_output; + gint finished; + GuestExecIOData in; + GuestExecIOData out; + GuestExecIOData err; + QTAILQ_ENTRY(GuestExecInfo) next; +}; +typedef struct GuestExecInfo GuestExecInfo; + +static struct { + QTAILQ_HEAD(, GuestExecInfo) processes; +} guest_exec_state = { + .processes = QTAILQ_HEAD_INITIALIZER(guest_exec_state.processes), +}; + +static int64_t gpid_to_int64(GPid pid) +{ +#ifdef G_OS_WIN32 + return GetProcessId(pid); +#else + return (int64_t)pid; +#endif +} + +static GuestExecInfo *guest_exec_info_add(GPid pid) +{ + GuestExecInfo *gei; + + gei = g_new0(GuestExecInfo, 1); + gei->pid = pid; + gei->pid_numeric = gpid_to_int64(pid); + QTAILQ_INSERT_TAIL(&guest_exec_state.processes, gei, next); + + return gei; +} + +static GuestExecInfo *guest_exec_info_find(int64_t pid_numeric) +{ + GuestExecInfo *gei; + + QTAILQ_FOREACH(gei, &guest_exec_state.processes, next) { + if (gei->pid_numeric == pid_numeric) { + return gei; + } + } + + return NULL; +} + +GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **err) +{ + GuestExecInfo *gei; + GuestExecStatus *ges; + + slog("guest-exec-status called, pid: %u", (uint32_t)pid); + + gei = guest_exec_info_find(pid); + if (gei == NULL) { + error_setg(err, QERR_INVALID_PARAMETER, "pid"); + return NULL; + } + + ges = g_new0(GuestExecStatus, 1); + + bool finished = g_atomic_int_get(&gei->finished); + + /* need to wait till output channels are closed + * to be sure we captured all output at this point */ + if (gei->has_output) { + finished = finished && g_atomic_int_get(&gei->out.closed); + finished = finished && g_atomic_int_get(&gei->err.closed); + } + + ges->exited = finished; + if (finished) { + /* Glib has no portable way to parse exit status. + * On UNIX, we can get either exit code from normal termination + * or signal number. + * On Windows, it is either the same exit code or the exception + * value for an unhandled exception that caused the process + * to terminate. + * See MSDN for GetExitCodeProcess() and ntstatus.h for possible + * well-known codes, e.g. C0000005 ACCESS_DENIED - analog of SIGSEGV + * References: + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms683189(v=vs.85).aspx + * https://msdn.microsoft.com/en-us/library/aa260331(v=vs.60).aspx + */ +#ifdef G_OS_WIN32 + /* Additionally WIN32 does not provide any additional information + * on whetherthe child exited or terminated via signal. + * We use this simple range check to distingish application exit code + * (usually value less then 256) and unhandled exception code with + * ntstatus (always value greater then 0xC0000005). */ + if ((uint32_t)gei->status < 0xC0000000U) { + ges->has_exitcode = true; + ges->exitcode = gei->status; + } else { + ges->has_signal = true; + ges->signal = gei->status; + } +#else + if (WIFEXITED(gei->status)) { + ges->has_exitcode = true; + ges->exitcode = WEXITSTATUS(gei->status); + } else if (WIFSIGNALED(gei->status)) { + ges->has_signal = true; + ges->signal = WTERMSIG(gei->status); + } +#endif + if (gei->out.length > 0) { + ges->has_out_data = true; + ges->out_data = g_base64_encode(gei->out.data, gei->out.length); + g_free(gei->out.data); + ges->has_out_truncated = gei->out.truncated; + } + + if (gei->err.length > 0) { + ges->has_err_data = true; + ges->err_data = g_base64_encode(gei->err.data, gei->err.length); + g_free(gei->err.data); + ges->has_err_truncated = gei->err.truncated; + } + + QTAILQ_REMOVE(&guest_exec_state.processes, gei, next); + g_free(gei); + } + + return ges; +} + +/* Get environment variables or arguments array for execve(). */ +static char **guest_exec_get_args(const strList *entry, bool log) +{ + const strList *it; + int count = 1, i = 0; /* reserve for NULL terminator */ + char **args; + char *str; /* for logging array of arguments */ + size_t str_size = 1; + + for (it = entry; it != NULL; it = it->next) { + count++; + str_size += 1 + strlen(it->value); + } + + str = g_malloc(str_size); + *str = 0; + args = g_malloc(count * sizeof(char *)); + for (it = entry; it != NULL; it = it->next) { + args[i++] = it->value; + pstrcat(str, str_size, it->value); + if (it->next) { + pstrcat(str, str_size, " "); + } + } + args[i] = NULL; + + if (log) { + slog("guest-exec called: \"%s\"", str); + } + g_free(str); + + return args; +} + +static void guest_exec_child_watch(GPid pid, gint status, gpointer data) +{ + GuestExecInfo *gei = (GuestExecInfo *)data; + + g_debug("guest_exec_child_watch called, pid: %d, status: %u", + (int32_t)gpid_to_int64(pid), (uint32_t)status); + + gei->status = status; + gei->finished = true; + + g_spawn_close_pid(pid); +} + +/** Reset ignored signals back to default. */ +static void guest_exec_task_setup(gpointer data) +{ +#if !defined(G_OS_WIN32) + struct sigaction sigact; + + memset(&sigact, 0, sizeof(struct sigaction)); + sigact.sa_handler = SIG_DFL; + + if (sigaction(SIGPIPE, &sigact, NULL) != 0) { + slog("sigaction() failed to reset child process's SIGPIPE: %s", + strerror(errno)); + } +#endif +} + +static gboolean guest_exec_input_watch(GIOChannel *ch, + GIOCondition cond, gpointer p_) +{ + GuestExecIOData *p = (GuestExecIOData *)p_; + gsize bytes_written = 0; + GIOStatus status; + GError *gerr = NULL; + + /* nothing left to write */ + if (p->size == p->length) { + goto done; + } + + status = g_io_channel_write_chars(ch, (gchar *)p->data + p->length, + p->size - p->length, &bytes_written, &gerr); + + /* can be not 0 even if not G_IO_STATUS_NORMAL */ + if (bytes_written != 0) { + p->length += bytes_written; + } + + /* continue write, our callback will be called again */ + if (status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_AGAIN) { + return true; + } + + if (gerr) { + g_warning("qga: i/o error writing to input_data channel: %s", + gerr->message); + g_error_free(gerr); + } + +done: + g_io_channel_shutdown(ch, true, NULL); + g_io_channel_unref(ch); + g_atomic_int_set(&p->closed, 1); + g_free(p->data); + + return false; +} + +static gboolean guest_exec_output_watch(GIOChannel *ch, + GIOCondition cond, gpointer p_) +{ + GuestExecIOData *p = (GuestExecIOData *)p_; + gsize bytes_read; + GIOStatus gstatus; + + if (cond == G_IO_HUP || cond == G_IO_ERR) { + goto close; + } + + if (p->size == p->length) { + gpointer t = NULL; + if (!p->truncated && p->size < GUEST_EXEC_MAX_OUTPUT) { + t = g_try_realloc(p->data, p->size + GUEST_EXEC_IO_SIZE); + } + if (t == NULL) { + /* ignore truncated output */ + gchar buf[GUEST_EXEC_IO_SIZE]; + + p->truncated = true; + gstatus = g_io_channel_read_chars(ch, buf, sizeof(buf), + &bytes_read, NULL); + if (gstatus == G_IO_STATUS_EOF || gstatus == G_IO_STATUS_ERROR) { + goto close; + } + + return true; + } + p->size += GUEST_EXEC_IO_SIZE; + p->data = t; + } + + /* Calling read API once. + * On next available data our callback will be called again */ + gstatus = g_io_channel_read_chars(ch, (gchar *)p->data + p->length, + p->size - p->length, &bytes_read, NULL); + if (gstatus == G_IO_STATUS_EOF || gstatus == G_IO_STATUS_ERROR) { + goto close; + } + + p->length += bytes_read; + + return true; + +close: + g_io_channel_unref(ch); + g_atomic_int_set(&p->closed, 1); + return false; +} + +GuestExec *qmp_guest_exec(const char *path, + bool has_arg, strList *arg, + bool has_env, strList *env, + bool has_input_data, const char *input_data, + bool has_capture_output, bool capture_output, + Error **err) +{ + GPid pid; + GuestExec *ge = NULL; + GuestExecInfo *gei; + char **argv, **envp; + strList arglist; + gboolean ret; + GError *gerr = NULL; + gint in_fd, out_fd, err_fd; + GIOChannel *in_ch, *out_ch, *err_ch; + GSpawnFlags flags; + bool has_output = (has_capture_output && capture_output); + + arglist.value = (char *)path; + arglist.next = has_arg ? arg : NULL; + + argv = guest_exec_get_args(&arglist, true); + envp = guest_exec_get_args(has_env ? env : NULL, false); + + flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD; + if (!has_output) { + flags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; + } + + ret = g_spawn_async_with_pipes(NULL, argv, envp, flags, + guest_exec_task_setup, NULL, &pid, has_input_data ? &in_fd : NULL, + has_output ? &out_fd : NULL, has_output ? &err_fd : NULL, &gerr); + if (!ret) { + error_setg(err, QERR_QGA_COMMAND_FAILED, gerr->message); + g_error_free(gerr); + goto done; + } + + ge = g_new0(GuestExec, 1); + ge->pid = gpid_to_int64(pid); + + gei = guest_exec_info_add(pid); + gei->has_output = has_output; + g_child_watch_add(pid, guest_exec_child_watch, gei); + + if (has_input_data) { + gei->in.data = g_base64_decode(input_data, &gei->in.size); +#ifdef G_OS_WIN32 + in_ch = g_io_channel_win32_new_fd(in_fd); +#else + in_ch = g_io_channel_unix_new(in_fd); +#endif + g_io_channel_set_encoding(in_ch, NULL, NULL); + g_io_channel_set_buffered(in_ch, false); + g_io_channel_set_flags(in_ch, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(in_ch, G_IO_OUT, guest_exec_input_watch, &gei->in); + } + + if (has_output) { +#ifdef G_OS_WIN32 + out_ch = g_io_channel_win32_new_fd(out_fd); + err_ch = g_io_channel_win32_new_fd(err_fd); +#else + out_ch = g_io_channel_unix_new(out_fd); + err_ch = g_io_channel_unix_new(err_fd); +#endif + g_io_channel_set_encoding(out_ch, NULL, NULL); + g_io_channel_set_encoding(err_ch, NULL, NULL); + g_io_channel_set_buffered(out_ch, false); + g_io_channel_set_buffered(err_ch, false); + g_io_add_watch(out_ch, G_IO_IN | G_IO_HUP, + guest_exec_output_watch, &gei->out); + g_io_add_watch(err_ch, G_IO_IN | G_IO_HUP, + guest_exec_output_watch, &gei->err); + } + +done: + g_free(argv); + g_free(envp); + + return ge; +} diff --git a/qga/guest-agent-command-state.c b/qga/guest-agent-command-state.c index 969da23282..128c549edb 100644 --- a/qga/guest-agent-command-state.c +++ b/qga/guest-agent-command-state.c @@ -27,7 +27,7 @@ void ga_command_state_add(GACommandState *cs, void (*init)(void), void (*cleanup)(void)) { - GACommandGroup *cg = g_malloc0(sizeof(GACommandGroup)); + GACommandGroup *cg = g_new0(GACommandGroup, 1); cg->init = init; cg->cleanup = cleanup; cs->groups = g_slist_append(cs->groups, cg); @@ -67,7 +67,7 @@ void ga_command_state_cleanup_all(GACommandState *cs) GACommandState *ga_command_state_new(void) { - GACommandState *cs = g_malloc0(sizeof(GACommandState)); + GACommandState *cs = g_new0(GACommandState, 1); cs->groups = NULL; return cs; } diff --git a/qga/main.c b/qga/main.c index d8e063a4a3..068169fcbc 100644 --- a/qga/main.c +++ b/qga/main.c @@ -161,6 +161,12 @@ static gboolean register_signal_handlers(void) g_error("error configuring signal handler: %s", strerror(errno)); } + sigact.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &sigact, NULL) != 0) { + g_error("error configuring SIGPIPE signal handler: %s", + strerror(errno)); + } + return true; } @@ -945,10 +951,11 @@ static void config_load(GAConfig *config) { GError *gerr = NULL; GKeyFile *keyfile; + const char *conf = g_getenv("QGA_CONF") ?: QGA_CONF_DEFAULT; /* read system config */ keyfile = g_key_file_new(); - if (!g_key_file_load_from_file(keyfile, QGA_CONF_DEFAULT, 0, &gerr)) { + if (!g_key_file_load_from_file(keyfile, conf, 0, &gerr)) { goto end; } if (g_key_file_has_key(keyfile, "general", "daemon", NULL)) { @@ -1082,8 +1089,6 @@ static void config_parse(GAConfig *config, int argc, char **argv) { NULL, 0, NULL, 0 } }; - config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; - while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { switch (ch) { case 'm': @@ -1331,6 +1336,8 @@ int main(int argc, char **argv) GAState *s = g_new0(GAState, 1); GAConfig *config = g_new0(GAConfig, 1); + config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; + module_call_init(MODULE_INIT_QAPI); init_dfl_pathnames(); diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 82894c63db..78362e071d 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -930,3 +930,70 @@ ## { 'command': 'guest-get-memory-block-info', 'returns': 'GuestMemoryBlockInfo' } + +# @GuestExecStatus: +# +# @exited: true if process has already terminated. +# @exitcode: #optional process exit code if it was normally terminated. +# @signal: #optional signal number (linux) or unhandled exception code +# (windows) if the process was abnormally terminated. +# @out-data: #optional base64-encoded stdout of the process +# @err-data: #optional base64-encoded stderr of the process +# Note: @out-data and @err-data are present only +# if 'capture-output' was specified for 'guest-exec' +# @out-truncated: #optional true if stdout was not fully captured +# due to size limitation. +# @err-truncated: #optional true if stderr was not fully captured +# due to size limitation. +# +# Since: 2.5 +## +{ 'struct': 'GuestExecStatus', + 'data': { 'exited': 'bool', '*exitcode': 'int', '*signal': 'int', + '*out-data': 'str', '*err-data': 'str', + '*out-truncated': 'bool', '*err-truncated': 'bool' }} +## +# @guest-exec-status +# +# Check status of process associated with PID retrieved via guest-exec. +# Reap the process and associated metadata if it has exited. +# +# @pid: pid returned from guest-exec +# +# Returns: GuestExecStatus on success. +# +# Since 2.5 +## +{ 'command': 'guest-exec-status', + 'data': { 'pid': 'int' }, + 'returns': 'GuestExecStatus' } + +## +# @GuestExec: +# @pid: pid of child process in guest OS +# +#Since: 2.5 +## +{ 'struct': 'GuestExec', + 'data': { 'pid': 'int'} } + +## +# @guest-exec: +# +# Execute a command in the guest +# +# @path: path or executable name to execute +# @arg: #optional argument list to pass to executable +# @env: #optional environment variables to pass to executable +# @input-data: #optional data to be passed to process stdin (base64 encoded) +# @capture-output: #optional bool flag to enable capture of +# stdout/stderr of running process. defaults to false. +# +# Returns: PID on success. +# +# Since: 2.5 +## +{ 'command': 'guest-exec', + 'data': { 'path': 'str', '*arg': ['str'], '*env': ['str'], + '*input-data': 'str', '*capture-output': 'bool' }, + 'returns': 'GuestExec' } diff --git a/qmp-commands.hx b/qmp-commands.hx index d2ba800d5e..2b52980cfc 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1270,11 +1270,22 @@ SQMP transaction ----------- -Atomically operate on one or more block devices. The only supported operations -for now are drive-backup, internal and external snapshotting. A list of -dictionaries is accepted, that contains the actions to be performed. -If there is any failure performing any of the operations, all operations -for the group are abandoned. +Atomically operate on one or more block devices. Operations that are +currently supported: + + - drive-backup + - blockdev-backup + - blockdev-snapshot-sync + - blockdev-snapshot-internal-sync + - abort + - block-dirty-bitmap-add + - block-dirty-bitmap-clear + +Refer to the qemu/qapi-schema.json file for minimum required QEMU +versions for these operations. A list of dictionaries is accepted, +that contains the actions to be performed. If there is any failure +performing any of the operations, all operations for the group are +abandoned. For external snapshots, the dictionary contains the device, the file to use for the new snapshot, and the format. The default format, if not specified, is @@ -1301,8 +1312,12 @@ it later with qemu-img or other command. Arguments: actions array: - - "type": the operation to perform. The only supported - value is "blockdev-snapshot-sync". (json-string) + - "type": the operation to perform (json-string). Possible + values: "drive-backup", "blockdev-backup", + "blockdev-snapshot-sync", + "blockdev-snapshot-internal-sync", + "abort", "block-dirty-bitmap-add", + "block-dirty-bitmap-clear" - "data": a dictionary. The contents depend on the value of "type". When "type" is "blockdev-snapshot-sync": - "device": device name to snapshot (json-string) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index b6d71eae17..b0f6e113c5 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1010,7 +1010,9 @@ sub possible { case| else| asm|__asm__| - do + do| + \#| + \#\# )(?:\s|$)| ^(?:typedef|struct|enum)\b )}x; @@ -1704,11 +1706,6 @@ sub process { ERROR("open brace '{' following $1 go on the same line\n" . $hereprev); } -# ... however, open braces on typedef lines should be avoided. - if ($line =~ /^.\s*typedef\s+(enum|union|struct)(?:\s+$Ident\b)?.*[^;]$/) { - ERROR("typedefs should be separate from struct declaration\n" . $herecurr); - } - # missing space after union, struct or enum definition if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { ERROR("missing space after $1 definition\n" . $herecurr); diff --git a/spice-qemu-char.c b/spice-qemu-char.c index d41bb745a8..a20fb5c90c 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -296,15 +296,14 @@ static CharDriverState *chr_open(const char *subtype, return chr; } -CharDriverState *qemu_chr_open_spice_vmc(const char *type) +static CharDriverState *qemu_chr_open_spice_vmc(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + const char *type = backend->spicevmc->type; const char **psubtype = spice_server_char_device_recognized_subtypes(); - if (type == NULL) { - fprintf(stderr, "spice-qemu-char: missing name parameter\n"); - print_allowed_subtypes(); - return NULL; - } for (; *psubtype != NULL; ++psubtype) { if (strcmp(type, *psubtype) == 0) { break; @@ -320,8 +319,12 @@ CharDriverState *qemu_chr_open_spice_vmc(const char *type) } #if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(const char *name) +static CharDriverState *qemu_chr_open_spice_port(const char *id, + ChardevBackend *backend, + ChardevReturn *ret, + Error **errp) { + const char *name = backend->spiceport->fqdn; CharDriverState *chr; SpiceCharDriver *s; @@ -379,9 +382,9 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, static void register_types(void) { register_char_driver("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC, - qemu_chr_parse_spice_vmc); + qemu_chr_parse_spice_vmc, qemu_chr_open_spice_vmc); register_char_driver("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT, - qemu_chr_parse_spice_port); + qemu_chr_parse_spice_port, qemu_chr_open_spice_port); } type_init(register_types); diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index ce6ce11ba2..251443b7d6 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -1,8 +1,5 @@ stub-obj-y += arch-query-cpu-def.o stub-obj-y += bdrv-commit-all.o -stub-obj-y += chr-baum-init.o -stub-obj-y += chr-msmouse.o -stub-obj-y += chr-testdev.o stub-obj-y += clock-warp.o stub-obj-y += cpu-get-clock.o stub-obj-y += cpu-get-icount.o @@ -23,7 +20,6 @@ stub-obj-y += mon-is-qmp.o stub-obj-y += mon-printf.o stub-obj-y += monitor-init.o stub-obj-y += notify-event.o -stub-obj-$(CONFIG_SPICE) += qemu-chr-open-spice.o stub-obj-y += qtest.o stub-obj-y += reset.o stub-obj-y += runstate-check.o @@ -31,7 +27,6 @@ stub-obj-y += set-fd-handler.o stub-obj-y += slirp.o stub-obj-y += sysbus.o stub-obj-y += uuid.o -stub-obj-y += vc-init.o stub-obj-y += vm-stop.o stub-obj-y += vmstate.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/chr-baum-init.c b/stubs/chr-baum-init.c deleted file mode 100644 index f5cc6ce1f8..0000000000 --- a/stubs/chr-baum-init.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "qemu-common.h" -#include "sysemu/char.h" - -CharDriverState *chr_baum_init(void) -{ - return NULL; -} diff --git a/stubs/chr-msmouse.c b/stubs/chr-msmouse.c deleted file mode 100644 index 812f8b0abe..0000000000 --- a/stubs/chr-msmouse.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "qemu-common.h" -#include "sysemu/char.h" - -CharDriverState *qemu_chr_open_msmouse(void) -{ - return 0; -} diff --git a/stubs/chr-testdev.c b/stubs/chr-testdev.c deleted file mode 100644 index 23112a2c07..0000000000 --- a/stubs/chr-testdev.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "qemu-common.h" -#include "sysemu/char.h" - -CharDriverState *chr_testdev_init(void) -{ - return 0; -} diff --git a/stubs/qemu-chr-open-spice.c b/stubs/qemu-chr-open-spice.c deleted file mode 100644 index f1c4849d9c..0000000000 --- a/stubs/qemu-chr-open-spice.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "qemu-common.h" -#include "ui/qemu-spice.h" - -CharDriverState *qemu_chr_open_spice_vmc(const char *type) -{ - return NULL; -} - -#if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(const char *name) -{ - return NULL; -} -#endif diff --git a/stubs/vc-init.c b/stubs/vc-init.c deleted file mode 100644 index 308dfa0800..0000000000 --- a/stubs/vc-init.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "qemu-common.h" -#include "sysemu/char.h" - -CharDriverState *vc_init(ChardevVC *vc) -{ - return 0; -} diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 6aadcd88f7..79ef4c61de 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -605,7 +605,7 @@ int kvm_arm_vgic_probe(void) } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data) + uint64_t address, uint32_t data, PCIDevice *dev) { return 0; } diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index c35b624c9d..e3bfe9d07e 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -88,8 +88,12 @@ typedef struct X86CPU { bool hyperv_vapic; bool hyperv_relaxed_timing; int hyperv_spinlock_attempts; + char *hyperv_vendor_id; bool hyperv_time; bool hyperv_crash; + bool hyperv_reset; + bool hyperv_vpindex; + bool hyperv_runtime; bool check_cpuid; bool enforce_cpuid; bool expose_kvm; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 05d7f26bf1..5f53af248f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3140,12 +3140,16 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false), DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false), DEFINE_PROP_BOOL("hv-crash", X86CPU, hyperv_crash, false), + DEFINE_PROP_BOOL("hv-reset", X86CPU, hyperv_reset, false), + DEFINE_PROP_BOOL("hv-vpindex", X86CPU, hyperv_vpindex, false), + DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false), DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false), DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, 0), DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0), DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0), + DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id), DEFINE_PROP_END_OF_LIST() }; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 54d9d50140..a395b4b07a 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -911,6 +911,7 @@ typedef struct CPUX86State { uint64_t msr_hv_vapic; uint64_t msr_hv_tsc; uint64_t msr_hv_crash_params[HV_X64_MSR_CRASH_PARAMS]; + uint64_t msr_hv_runtime; /* exception/interrupt handling */ int error_code; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 80d1a7e01e..64046cb69d 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -28,6 +28,7 @@ #include "exec/gdbstub.h" #include "qemu/host-utils.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" #include "hw/i386/apic_internal.h" @@ -82,12 +83,24 @@ static bool has_msr_hv_hypercall; static bool has_msr_hv_vapic; static bool has_msr_hv_tsc; static bool has_msr_hv_crash; +static bool has_msr_hv_reset; +static bool has_msr_hv_vpindex; +static bool has_msr_hv_runtime; static bool has_msr_mtrr; static bool has_msr_xss; static bool has_msr_architectural_pmu; static uint32_t num_architectural_pmu_counters; +static int has_xsave; +static int has_xcrs; +static int has_pit_state2; + +int kvm_has_pit_state2(void) +{ + return has_pit_state2; +} + bool kvm_has_smm(void) { return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM); @@ -460,7 +473,10 @@ static bool hyperv_enabled(X86CPU *cpu) (hyperv_hypercall_available(cpu) || cpu->hyperv_time || cpu->hyperv_relaxed_timing || - cpu->hyperv_crash); + cpu->hyperv_crash || + cpu->hyperv_reset || + cpu->hyperv_vpindex || + cpu->hyperv_runtime); } static Error *invtsc_mig_blocker; @@ -490,7 +506,18 @@ int kvm_arch_init_vcpu(CPUState *cs) if (hyperv_enabled(cpu)) { c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS; - memcpy(signature, "Microsoft Hv", 12); + if (!cpu->hyperv_vendor_id) { + memcpy(signature, "Microsoft Hv", 12); + } else { + size_t len = strlen(cpu->hyperv_vendor_id); + + if (len > 12) { + error_report("hv-vendor-id truncated to 12 characters"); + len = 12; + } + memset(signature, 0, 12); + memcpy(signature, cpu->hyperv_vendor_id, len); + } c->eax = HYPERV_CPUID_MIN; c->ebx = signature[0]; c->ecx = signature[1]; @@ -529,7 +556,15 @@ int kvm_arch_init_vcpu(CPUState *cs) if (cpu->hyperv_crash && has_msr_hv_crash) { c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; } - + if (cpu->hyperv_reset && has_msr_hv_reset) { + c->eax |= HV_X64_MSR_RESET_AVAILABLE; + } + if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { + c->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE; + } + if (cpu->hyperv_runtime && has_msr_hv_runtime) { + c->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; + } c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { @@ -752,7 +787,7 @@ int kvm_arch_init_vcpu(CPUState *cs) } } - if (kvm_has_xsave()) { + if (has_xsave) { env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); } @@ -858,6 +893,18 @@ static int kvm_get_supported_msrs(KVMState *s) has_msr_hv_crash = true; continue; } + if (kvm_msr_list->indices[i] == HV_X64_MSR_RESET) { + has_msr_hv_reset = true; + continue; + } + if (kvm_msr_list->indices[i] == HV_X64_MSR_VP_INDEX) { + has_msr_hv_vpindex = true; + continue; + } + if (kvm_msr_list->indices[i] == HV_X64_MSR_VP_RUNTIME) { + has_msr_hv_runtime = true; + continue; + } } } @@ -908,6 +955,18 @@ int kvm_arch_init(MachineState *ms, KVMState *s) int ret; struct utsname utsname; +#ifdef KVM_CAP_XSAVE + has_xsave = kvm_check_extension(s, KVM_CAP_XSAVE); +#endif + +#ifdef KVM_CAP_XCRS + has_xcrs = kvm_check_extension(s, KVM_CAP_XCRS); +#endif + +#ifdef KVM_CAP_PIT_STATE2 + has_pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2); +#endif + ret = kvm_get_supported_msrs(s); if (ret < 0) { return ret; @@ -1116,7 +1175,7 @@ static int kvm_put_xsave(X86CPU *cpu) uint8_t *xmm, *ymmh, *zmmh; int i, r; - if (!kvm_has_xsave()) { + if (!has_xsave) { return kvm_put_fpu(cpu); } @@ -1170,7 +1229,7 @@ static int kvm_put_xcrs(X86CPU *cpu) CPUX86State *env = &cpu->env; struct kvm_xcrs xcrs = {}; - if (!kvm_has_xcrs()) { + if (!has_xcrs) { return 0; } @@ -1403,6 +1462,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_CRASH_CTL, HV_X64_MSR_CRASH_CTL_NOTIFY); } + if (has_msr_hv_runtime) { + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_VP_RUNTIME, + env->msr_hv_runtime); + } if (has_msr_mtrr) { kvm_msr_entry_set(&msrs[n++], MSR_MTRRdefType, env->mtrr_deftype); kvm_msr_entry_set(&msrs[n++], @@ -1495,7 +1558,7 @@ static int kvm_get_xsave(X86CPU *cpu) const uint8_t *xmm, *ymmh, *zmmh; uint16_t cwd, swd, twd; - if (!kvm_has_xsave()) { + if (!has_xsave) { return kvm_get_fpu(cpu); } @@ -1554,7 +1617,7 @@ static int kvm_get_xcrs(X86CPU *cpu) int i, ret; struct kvm_xcrs xcrs; - if (!kvm_has_xcrs()) { + if (!has_xcrs) { return 0; } @@ -1768,6 +1831,9 @@ static int kvm_get_msrs(X86CPU *cpu) msrs[n++].index = HV_X64_MSR_CRASH_P0 + j; } } + if (has_msr_hv_runtime) { + msrs[n++].index = HV_X64_MSR_VP_RUNTIME; + } if (has_msr_mtrr) { msrs[n++].index = MSR_MTRRdefType; msrs[n++].index = MSR_MTRRfix64K_00000; @@ -1921,6 +1987,9 @@ static int kvm_get_msrs(X86CPU *cpu) case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: env->msr_hv_crash_params[index - HV_X64_MSR_CRASH_P0] = msrs[i].data; break; + case HV_X64_MSR_VP_RUNTIME: + env->msr_hv_runtime = msrs[i].data; + break; case MSR_MTRRdefType: env->mtrr_deftype = msrs[i].data; break; @@ -2956,7 +3025,7 @@ int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id) } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data) + uint64_t address, uint32_t data, PCIDevice *dev) { return 0; } diff --git a/target-i386/machine.c b/target-i386/machine.c index 9fa056341a..67373663d0 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -687,6 +687,25 @@ static const VMStateDescription vmstate_msr_hyperv_crash = { } }; +static bool hyperv_runtime_enable_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return env->msr_hv_runtime != 0; +} + +static const VMStateDescription vmstate_msr_hyperv_runtime = { + .name = "cpu/msr_hyperv_runtime", + .version_id = 1, + .minimum_version_id = 1, + .needed = hyperv_runtime_enable_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.msr_hv_runtime, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + static bool avx512_needed(void *opaque) { X86CPU *cpu = opaque; @@ -869,6 +888,7 @@ VMStateDescription vmstate_x86_cpu = { &vmstate_msr_hyperv_vapic, &vmstate_msr_hyperv_time, &vmstate_msr_hyperv_crash, + &vmstate_msr_hyperv_runtime, &vmstate_avx512, &vmstate_xss, NULL diff --git a/target-mips/kvm.c b/target-mips/kvm.c index d287d42883..12d7db311e 100644 --- a/target-mips/kvm.c +++ b/target-mips/kvm.c @@ -678,7 +678,7 @@ int kvm_arch_get_registers(CPUState *cs) } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data) + uint64_t address, uint32_t data, PCIDevice *dev) { return 0; } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 72762991dc..38aa927eb0 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2483,7 +2483,7 @@ error_out: } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data) + uint64_t address, uint32_t data, PCIDevice *dev) { return 0; } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index e4de8632f3..658cd9d554 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1160,12 +1160,13 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); int kvm_s390_cpu_restart(S390CPU *cpu); int kvm_s390_get_memslot_count(KVMState *s); -void kvm_s390_clear_cmma_callback(void *opaque); +void kvm_s390_cmma_reset(void); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); void kvm_s390_reset_vcpu(S390CPU *cpu); int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); +void kvm_s390_crypto_reset(void); #else static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1189,7 +1190,7 @@ static inline int kvm_s390_cpu_restart(S390CPU *cpu) { return -ENOSYS; } -static inline void kvm_s390_clear_cmma_callback(void *opaque) +static inline void kvm_s390_cmma_reset(void) { } static inline int kvm_s390_get_memslot_count(KVMState *s) @@ -1215,6 +1216,9 @@ static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) { return 0; } +static inline void kvm_s390_crypto_reset(void) +{ +} #endif static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) @@ -1225,11 +1229,10 @@ static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) return 0; } -static inline void cmma_reset(S390CPU *cpu) +static inline void s390_cmma_reset(void) { if (kvm_enabled()) { - CPUState *cs = CPU(cpu); - kvm_s390_clear_cmma_callback(cs->kvm_state); + kvm_s390_cmma_reset(); } } @@ -1261,6 +1264,13 @@ static inline int s390_assign_subch_ioeventfd(EventNotifier *notifier, return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign); } +static inline void s390_crypto_reset(void) +{ + if (kvm_enabled()) { + kvm_s390_crypto_reset(); + } +} + #ifdef CONFIG_KVM static inline bool vregs_needed(void *opaque) { @@ -1275,4 +1285,49 @@ static inline bool vregs_needed(void *opaque) return 0; } #endif + +/* machine check interruption code */ + +/* subclasses */ +#define MCIC_SC_SD 0x8000000000000000ULL +#define MCIC_SC_PD 0x4000000000000000ULL +#define MCIC_SC_SR 0x2000000000000000ULL +#define MCIC_SC_CD 0x0800000000000000ULL +#define MCIC_SC_ED 0x0400000000000000ULL +#define MCIC_SC_DG 0x0100000000000000ULL +#define MCIC_SC_W 0x0080000000000000ULL +#define MCIC_SC_CP 0x0040000000000000ULL +#define MCIC_SC_SP 0x0020000000000000ULL +#define MCIC_SC_CK 0x0010000000000000ULL + +/* subclass modifiers */ +#define MCIC_SCM_B 0x0002000000000000ULL +#define MCIC_SCM_DA 0x0000000020000000ULL +#define MCIC_SCM_AP 0x0000000000080000ULL + +/* storage errors */ +#define MCIC_SE_SE 0x0000800000000000ULL +#define MCIC_SE_SC 0x0000400000000000ULL +#define MCIC_SE_KE 0x0000200000000000ULL +#define MCIC_SE_DS 0x0000100000000000ULL +#define MCIC_SE_IE 0x0000000080000000ULL + +/* validity bits */ +#define MCIC_VB_WP 0x0000080000000000ULL +#define MCIC_VB_MS 0x0000040000000000ULL +#define MCIC_VB_PM 0x0000020000000000ULL +#define MCIC_VB_IA 0x0000010000000000ULL +#define MCIC_VB_FA 0x0000008000000000ULL +#define MCIC_VB_VR 0x0000004000000000ULL +#define MCIC_VB_EC 0x0000002000000000ULL +#define MCIC_VB_FP 0x0000001000000000ULL +#define MCIC_VB_GR 0x0000000800000000ULL +#define MCIC_VB_CR 0x0000000400000000ULL +#define MCIC_VB_ST 0x0000000100000000ULL +#define MCIC_VB_AR 0x0000000040000000ULL +#define MCIC_VB_PR 0x0000000000200000ULL +#define MCIC_VB_FC 0x0000000000100000ULL +#define MCIC_VB_CT 0x0000000000020000ULL +#define MCIC_VB_CC 0x0000000000010000ULL + #endif diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 5fdee1b20b..c3be180de2 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -173,16 +173,15 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit) return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); } -void kvm_s390_clear_cmma_callback(void *opaque) +void kvm_s390_cmma_reset(void) { int rc; - KVMState *s = opaque; struct kvm_device_attr attr = { .group = KVM_S390_VM_MEM_CTRL, .attr = KVM_S390_VM_MEM_CLR_CMMA, }; - rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); + rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); trace_kvm_clear_cmma(rc); } @@ -200,9 +199,6 @@ static void kvm_s390_enable_cmma(KVMState *s) } rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); - if (!rc) { - qemu_register_reset(kvm_s390_clear_cmma_callback, s); - } trace_kvm_enable_cmma(rc); } @@ -249,7 +245,7 @@ static void kvm_s390_init_dea_kw(void) } } -static void kvm_s390_init_crypto(void) +void kvm_s390_crypto_reset(void) { kvm_s390_init_aes_kw(); kvm_s390_init_dea_kw(); @@ -301,8 +297,6 @@ void kvm_s390_reset_vcpu(S390CPU *cpu) if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) { error_report("Initial CPU reset failed on CPU %i", cs->cpu_index); } - - kvm_s390_init_crypto(); } static int can_sync_regs(CPUState *cs, int regs) @@ -2065,12 +2059,30 @@ void kvm_s390_io_interrupt(uint16_t subchannel_id, kvm_s390_floating_interrupt(&irq); } +static uint64_t build_channel_report_mcic(void) +{ + uint64_t mcic; + + /* subclass: indicate channel report pending */ + mcic = MCIC_SC_CP | + /* subclass modifiers: none */ + /* storage errors: none */ + /* validity bits: no damage */ + MCIC_VB_WP | MCIC_VB_MS | MCIC_VB_PM | MCIC_VB_IA | MCIC_VB_FP | + MCIC_VB_GR | MCIC_VB_CR | MCIC_VB_ST | MCIC_VB_AR | MCIC_VB_PR | + MCIC_VB_FC | MCIC_VB_CT | MCIC_VB_CC; + if (kvm_check_extension(kvm_state, KVM_CAP_S390_VECTOR_REGISTERS)) { + mcic |= MCIC_VB_VR; + } + return mcic; +} + void kvm_s390_crw_mchk(void) { struct kvm_s390_irq irq = { .type = KVM_S390_MCHK, .u.mchk.cr14 = 1 << 28, - .u.mchk.mcic = 0x00400f1d40330000ULL, + .u.mchk.mcic = build_channel_report_mcic(), }; kvm_s390_floating_interrupt(&irq); } @@ -2208,7 +2220,7 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data) + uint64_t address, uint32_t data, PCIDevice *dev) { S390PCIBusDevice *pbdev; uint32_t fid = data >> ZPCI_MSI_VEC_BITS; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 3a19e321c8..b601a33606 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -127,8 +127,9 @@ static int modified_clear_reset(S390CPU *cpu) CPU_FOREACH(t) { run_on_cpu(t, s390_do_cpu_full_reset, t); } - cmma_reset(cpu); + s390_cmma_reset(); subsystem_reset(); + s390_crypto_reset(); scc->load_normal(CPU(cpu)); cpu_synchronize_all_post_reset(); resume_all_vcpus(); @@ -145,7 +146,7 @@ static int load_normal_reset(S390CPU *cpu) CPU_FOREACH(t) { run_on_cpu(t, s390_do_cpu_reset, t); } - cmma_reset(cpu); + s390_cmma_reset(); subsystem_reset(); scc->initial_cpu_reset(CPU(cpu)); scc->load_normal(CPU(cpu)); @@ -233,11 +234,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) } iplb = g_malloc0(sizeof(struct IplParameterBlock)); cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock)); - if (!s390_ipl_update_diag308(iplb)) { - env->regs[r1 + 1] = DIAG_308_RC_OK; - } else { - env->regs[r1 + 1] = DIAG_308_RC_INVALID; - } + s390_ipl_update_diag308(iplb); + env->regs[r1 + 1] = DIAG_308_RC_OK; g_free(iplb); return; case 6: diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 006bcb78b8..15ce0107d6 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -64,6 +64,7 @@ enum { XTENSA_OPTION_MP_SYNCHRO, XTENSA_OPTION_CONDITIONAL_STORE, XTENSA_OPTION_ATOMCTL, + XTENSA_OPTION_DEPBITS, /* Interrupts and exceptions */ XTENSA_OPTION_EXCEPTION, diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index 76be50d09c..2c3447ba6b 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -541,8 +541,8 @@ static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb, wi = ++env->autorefill_idx & 0x3; xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte); env->sregs[EXCVADDR] = vaddr; - qemu_log("%s: autorefill(%08x): %08x -> %08x\n", - __func__, vaddr, vpn, pte); + qemu_log_mask(CPU_LOG_MMU, "%s: autorefill(%08x): %08x -> %08x\n", + __func__, vaddr, vpn, pte); } else { xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte); entry = &tmp_entry; @@ -590,8 +590,8 @@ static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte) int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0, &paddr, &page_size, &access, false); - qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__, - vaddr, ret ? ~0 : paddr); + qemu_log_mask(CPU_LOG_MMU, "%s: trying autorefill(%08x) -> %08x\n", + __func__, vaddr, ret ? ~0 : paddr); if (ret == 0) { *pte = ldl_phys(cs->as, paddr); diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index be657e615d..718e54e7b5 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -57,8 +57,8 @@ void tlb_fill(CPUState *cs, int ret = xtensa_get_physical_addr(env, true, vaddr, is_write, mmu_idx, &paddr, &page_size, &access); - qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__, - vaddr, is_write, mmu_idx, paddr, ret); + qemu_log_mask(CPU_LOG_MMU, "%s(%08x, %d, %d) -> %08x, ret = %d\n", + __func__, vaddr, is_write, mmu_idx, paddr, ret); if (ret == 0) { tlb_set_page(cs, diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h index eda03aaca9..e8a7fda3d8 100644 --- a/target-xtensa/overlay_tool.h +++ b/target-xtensa/overlay_tool.h @@ -30,6 +30,10 @@ { .targno = (no), .type = (typ), .group = (grp), .size = (sz) }, #define XTREG_END { .targno = -1 }, +#ifndef XCHAL_HAVE_DEPBITS +#define XCHAL_HAVE_DEPBITS 0 +#endif + #ifndef XCHAL_HAVE_DIV32 #define XCHAL_HAVE_DIV32 0 #endif @@ -69,6 +73,7 @@ XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \ XCHAL_OPTION(XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000, \ XTENSA_OPTION_ATOMCTL) | \ + XCHAL_OPTION(XCHAL_HAVE_DEPBITS, XTENSA_OPTION_DEPBITS) | \ /* Interrupts and exceptions */ \ XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \ XCHAL_OPTION(XCHAL_HAVE_VECBASE, XTENSA_OPTION_RELOCATABLE_VECTOR) | \ diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index fda91b7e5d..aa0c527dc4 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -1943,7 +1943,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) switch (OP2) { case 0: /*L32E*/ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_check_privilege(dc)) { + if (gen_check_privilege(dc) && + gen_window_check2(dc, RRR_S, RRR_T)) { TCGv_i32 addr = tcg_temp_new_i32(); tcg_gen_addi_i32(addr, cpu_R[RRR_S], (0xffffffc0 | (RRR_R << 2))); @@ -1954,7 +1955,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 4: /*S32E*/ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_check_privilege(dc)) { + if (gen_check_privilege(dc) && + gen_window_check2(dc, RRR_S, RRR_T)) { TCGv_i32 addr = tcg_temp_new_i32(); tcg_gen_addi_i32(addr, cpu_R[RRR_S], (0xffffffc0 | (RRR_R << 2))); @@ -1963,6 +1965,17 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) } break; + case 5: /*S32N*/ + if (gen_window_check2(dc, RRI4_S, RRI4_T)) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_addi_i32(addr, cpu_R[RRI4_S], RRI4_IMM4 << 2); + gen_load_store_alignment(dc, 2, addr, false); + tcg_gen_qemu_st32(cpu_R[RRI4_T], addr, dc->cring); + tcg_temp_free(addr); + } + break; + default: RESERVED(); break; @@ -1970,6 +1983,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) break; case 10: /*FP0*/ + /*DEPBITS*/ + if (option_enabled(dc, XTENSA_OPTION_DEPBITS)) { + if (!gen_window_check2(dc, RRR_S, RRR_T)) { + break; + } + tcg_gen_deposit_i32(cpu_R[RRR_T], cpu_R[RRR_T], cpu_R[RRR_S], + OP2, RRR_R + 1); + break; + } + HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); switch (OP2) { case 0: /*ADD.Sf*/ @@ -2104,6 +2127,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) break; case 11: /*FP1*/ + /*DEPBITS*/ + if (option_enabled(dc, XTENSA_OPTION_DEPBITS)) { + if (!gen_window_check2(dc, RRR_S, RRR_T)) { + break; + } + tcg_gen_deposit_i32(cpu_R[RRR_T], cpu_R[RRR_T], cpu_R[RRR_S], + OP2 + 16, RRR_R + 1); + break; + } + HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); #define gen_compare(rel, br, a, b) \ diff --git a/tests/Makefile b/tests/Makefile index cb221dec22..0531b30929 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -80,6 +80,7 @@ check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF) check-unit-y += tests/test-crypto-cipher$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF) +check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -534,6 +535,8 @@ endif qtest-obj-y = tests/libqtest.o $(test-util-obj-y) $(check-qtest-y): $(qtest-obj-y) +tests/test-qga: tests/test-qga.o $(qtest-obj-y) + .PHONY: check-help check-help: @echo "Regression testing targets:" diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c index 9be78e9564..b7d4007e32 100644 --- a/tests/fw_cfg-test.c +++ b/tests/fw_cfg-test.c @@ -37,7 +37,9 @@ static void test_fw_cfg_signature(void) static void test_fw_cfg_id(void) { - g_assert_cmpint(qfw_cfg_get_u32(fw_cfg, FW_CFG_ID), ==, 1); + uint32_t id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID); + g_assert((id == 1) || + (id == 3)); } static void test_fw_cfg_uuid(void) diff --git a/tests/libqtest.c b/tests/libqtest.c index 2a396ba08d..b6d700c606 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -356,7 +356,7 @@ static void qmp_response(JSONMessageParser *parser, QList *tokens) qmp->response = (QDict *)obj; } -QDict *qtest_qmp_receive(QTestState *s) +QDict *qmp_fd_receive(int fd) { QMPResponseParser qmp; bool log = getenv("QTEST_LOG") != NULL; @@ -367,7 +367,7 @@ QDict *qtest_qmp_receive(QTestState *s) ssize_t len; char c; - len = read(s->qmp_fd, &c, 1); + len = read(fd, &c, 1); if (len == -1 && errno == EINTR) { continue; } @@ -387,12 +387,17 @@ QDict *qtest_qmp_receive(QTestState *s) return qmp.response; } +QDict *qtest_qmp_receive(QTestState *s) +{ + return qmp_fd_receive(s->qmp_fd); +} + /** * Allow users to send a message without waiting for the reply, * in the case that they choose to discard all replies up until * a particular EVENT is received. */ -void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) +void qmp_fd_sendv(int fd, const char *fmt, va_list ap) { va_list ap_copy; QObject *qobj; @@ -416,13 +421,25 @@ void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) fprintf(stderr, "%s", str); } /* Send QMP request */ - socket_send(s->qmp_fd, str, size); + socket_send(fd, str, size); QDECREF(qstr); qobject_decref(qobj); } } +void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) +{ + qmp_fd_sendv(s->qmp_fd, fmt, ap); +} + +QDict *qmp_fdv(int fd, const char *fmt, va_list ap) +{ + qmp_fd_sendv(fd, fmt, ap); + + return qmp_fd_receive(fd); +} + QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) { qtest_async_qmpv(s, fmt, ap); @@ -431,6 +448,26 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) return qtest_qmp_receive(s); } +QDict *qmp_fd(int fd, const char *fmt, ...) +{ + va_list ap; + QDict *response; + + va_start(ap, fmt); + response = qmp_fdv(fd, fmt, ap); + va_end(ap); + return response; +} + +void qmp_fd_send(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qmp_fd_sendv(fd, fmt, ap); + va_end(ap); +} + QDict *qtest_qmp(QTestState *s, const char *fmt, ...) { va_list ap; diff --git a/tests/libqtest.h b/tests/libqtest.h index 55bccbf0e6..9818ef712d 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -851,4 +851,11 @@ static inline int64_t clock_set(int64_t val) */ bool qtest_big_endian(void); + +QDict *qmp_fd_receive(int fd); +void qmp_fd_sendv(int fd, const char *fmt, va_list ap); +void qmp_fd_send(int fd, const char *fmt, ...); +QDict *qmp_fdv(int fd, const char *fmt, va_list ap); +QDict *qmp_fd(int fd, const char *fmt, ...); + #endif diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 59c1a762a2..05b5962cee 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -780,7 +780,7 @@ class TestRepairQuorum(iotests.QMPTestCase): # here we check that the last registered quorum file has not been # swapped out and unref result = self.vm.qmp('query-named-block-nodes') - self.assert_qmp(result, 'return[0]/file', quorum_img3) + self.assert_qmp(result, 'return[1]/file', quorum_img3) self.vm.shutdown() def test_cancel_after_ready(self): @@ -799,7 +799,7 @@ class TestRepairQuorum(iotests.QMPTestCase): result = self.vm.qmp('query-named-block-nodes') # here we check that the last registered quorum file has not been # swapped out and unref - self.assert_qmp(result, 'return[0]/file', quorum_img3) + self.assert_qmp(result, 'return[1]/file', quorum_img3) self.vm.shutdown() self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), 'target image does not match source after mirroring') diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 4a8055b673..17dbf04af4 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -108,7 +108,8 @@ echo echo === Overriding backing file === echo -echo "info block" | run_qemu -drive file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" -nodefaults +echo "info block" | run_qemu -drive file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" -nodefaults\ + | _filter_generated_node_ids # Drivers that don't support backing files run_qemu -drive file="$TEST_IMG",driver=raw,backing.file.filename="$TEST_IMG.orig" diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 0429be296c..7765aa0bb2 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -59,7 +59,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K -ide0-hd0: TEST_DIR/t.qcow2 (qcow2) +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 67e3cf57e4..00057fef9b 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -16,17 +16,17 @@ qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big no file open, try 'help open' === Testing monolithicFlat creation and opening === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 2.0G (2147483648 bytes) === Testing monolithicFlat with zeroed_grain === qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat === Testing big twoGbMaxExtentFlat === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMaxExtentFlat image: TEST_DIR/t.vmdk file format: vmdk virtual size: 1.0T (1073741824000 bytes) @@ -2043,7 +2043,7 @@ RW 12582912 VMFS "dummy.IMGFMT" 1 === Testing truncated sparse === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 subformat=monolithicSparse 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=== @@ -2054,7 +2054,7 @@ wrote 512/512 bytes at offset 10240 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing monolithicFlat with internally generated JSON file name === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}' === Testing version 3 === @@ -2264,7 +2264,7 @@ read 512/512 bytes at offset 64931328 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing 4TB monolithicFlat creation and IO === -Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 +Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat image: TEST_DIR/iotest-version3.IMGFMT file format: IMGFMT virtual size: 4.0T (4398046511104 bytes) diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index 1df887a01d..e191e65d5f 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -58,8 +58,8 @@ echo 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" 2>&1 \ - | _filter_qemu_io +$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \ + -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io $PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" $PYTHON qcow2.py "$TEST_IMG" dump-header @@ -92,8 +92,8 @@ echo 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" 2>&1 \ - | _filter_qemu_io +$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \ + -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io $PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG" $PYTHON qcow2.py "$TEST_IMG" dump-header diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index a683f46a12..b16bea95d2 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -57,7 +57,7 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -./common.config: Aborted (core dumped) ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" ) +./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" ) magic 0x514649fb version 3 backing_file_offset 0x0 @@ -215,7 +215,7 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -./common.config: Aborted (core dumped) ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" ) +./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" ) magic 0x514649fb version 3 backing_file_offset 0x0 diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index 3e9a053ef3..3788534d67 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -48,7 +48,8 @@ function do_run_qemu() function run_qemu() { do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \ - | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' + | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \ + | _filter_generated_node_ids } size=128M diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out index 5fbc881b72..27ad56fe2f 100644 --- a/tests/qemu-iotests/067.out +++ b/tests/qemu-iotests/067.out @@ -40,6 +40,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -151,6 +152,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -270,6 +272,7 @@ Testing: }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -390,6 +393,7 @@ Testing: }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -480,6 +484,7 @@ Testing: }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index d9b042cfc7..51873ff7db 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -53,7 +53,8 @@ function do_run_qemu() function run_qemu() { - do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp | _filter_qemu_io + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\ + | _filter_qemu_io | _filter_generated_node_ids } test_quorum=$($QEMU_IMG --help|grep quorum) diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out index 692c4a4343..044793dcc5 100644 --- a/tests/qemu-iotests/081.out +++ b/tests/qemu-iotests/081.out @@ -30,7 +30,7 @@ Testing: -drive file=TEST_DIR/2.IMGFMT,format=IMGFMT,if=none,id=drive2 QMP_VERSION {"return": {}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "", "sectors-count": 20480, "sector-num": 0}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "NODE_NAME", "sectors-count": 20480, "sector-num": 0}} read 10485760/10485760 bytes at offset 0 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} diff --git a/tests/qemu-iotests/096 b/tests/qemu-iotests/096 new file mode 100644 index 0000000000..e34204b8ff --- /dev/null +++ b/tests/qemu-iotests/096 @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# +# Test that snapshots move the throttling configuration to the active +# layer +# +# Copyright (C) 2015 Igalia, S.L. +# +# 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/>. +# + +import iotests +import os + +class TestLiveSnapshot(iotests.QMPTestCase): + base_img = os.path.join(iotests.test_dir, 'base.img') + target_img = os.path.join(iotests.test_dir, 'target.img') + group = 'mygroup' + iops = 6000 + iops_size = 1024 + + def setUp(self): + opts = [] + opts.append('node-name=base') + opts.append('throttling.group=%s' % self.group) + opts.append('throttling.iops-total=%d' % self.iops) + opts.append('throttling.iops-size=%d' % self.iops_size) + iotests.qemu_img('create', '-f', iotests.imgfmt, self.base_img, '100M') + self.vm = iotests.VM().add_drive(self.base_img, ','.join(opts)) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(self.base_img) + os.remove(self.target_img) + + def checkConfig(self, active_layer): + result = self.vm.qmp('query-named-block-nodes') + for r in result['return']: + if r['node-name'] == active_layer: + self.assertEqual(r['group'], self.group) + self.assertEqual(r['iops'], self.iops) + self.assertEqual(r['iops_size'], self.iops_size) + else: + self.assertFalse(r.has_key('group')) + self.assertEqual(r['iops'], 0) + self.assertFalse(r.has_key('iops_size')) + + def testSnapshot(self): + self.checkConfig('base') + self.vm.qmp('blockdev-snapshot-sync', + node_name = 'base', + snapshot_node_name = 'target', + snapshot_file = self.target_img, + format = iotests.imgfmt) + self.checkConfig('target') + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/096.out b/tests/qemu-iotests/096.out new file mode 100644 index 0000000000..ae1213e6f8 --- /dev/null +++ b/tests/qemu-iotests/096.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index d6d05de2da..cfdb6338aa 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -128,6 +128,11 @@ _filter_date() -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/' } +_filter_generated_node_ids() +{ + sed -re 's/\#block[0-9]{3,}/NODE_NAME/' +} + # replace occurrences of the actual TEST_DIR value with TEST_DIR _filter_testdir() { diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 439b1d237d..30c784e940 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -102,6 +102,7 @@ 093 auto 094 rw auto quick 095 rw auto quick +096 rw auto quick 097 rw auto backing 098 rw auto backing quick 099 rw auto quick diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c index b552d9f5e9..f5951cb1f1 100644 --- a/tests/test-coroutine.c +++ b/tests/test-coroutine.c @@ -12,8 +12,8 @@ */ #include <glib.h> -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" /* * Check that qemu_in_coroutine() works diff --git a/tests/test-qga.c b/tests/test-qga.c new file mode 100644 index 0000000000..0531c9f3bc --- /dev/null +++ b/tests/test-qga.c @@ -0,0 +1,783 @@ +#include <locale.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <inttypes.h> + +#include "libqtest.h" +#include "config-host.h" + +typedef struct { + char *test_dir; + GMainLoop *loop; + int fd; + GPid pid; +} TestFixture; + +static int connect_qga(char *path) +{ + int s, ret, len, i = 0; + struct sockaddr_un remote; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + g_assert(s != -1); + + remote.sun_family = AF_UNIX; + do { + strcpy(remote.sun_path, path); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + ret = connect(s, (struct sockaddr *)&remote, len); + if (ret == -1) { + g_usleep(G_USEC_PER_SEC); + } + if (i++ == 10) { + return -1; + } + } while (ret == -1); + + return s; +} + +static void qga_watch(GPid pid, gint status, gpointer user_data) +{ + TestFixture *fixture = user_data; + + g_assert_cmpint(status, ==, 0); + g_main_loop_quit(fixture->loop); +} + +static void +fixture_setup(TestFixture *fixture, gconstpointer data) +{ + const gchar *extra_arg = data; + GError *error = NULL; + gchar *cwd, *path, *cmd, **argv = NULL; + + fixture->loop = g_main_loop_new(NULL, FALSE); + + fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX"); + g_assert_nonnull(mkdtemp(fixture->test_dir)); + + path = g_build_filename(fixture->test_dir, "sock", NULL); + cwd = g_get_current_dir(); + cmd = g_strdup_printf("%s%cqemu-ga -m unix-listen -t %s -p %s %s %s", + cwd, G_DIR_SEPARATOR, + fixture->test_dir, path, + getenv("QTEST_LOG") ? "-v" : "", + extra_arg ?: ""); + g_shell_parse_argv(cmd, NULL, &argv, &error); + g_assert_no_error(error); + + g_spawn_async(fixture->test_dir, argv, NULL, + G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &fixture->pid, &error); + g_assert_no_error(error); + + g_child_watch_add(fixture->pid, qga_watch, fixture); + + fixture->fd = connect_qga(path); + g_assert_cmpint(fixture->fd, !=, -1); + + g_strfreev(argv); + g_free(cmd); + g_free(cwd); + g_free(path); +} + +static void +fixture_tear_down(TestFixture *fixture, gconstpointer data) +{ + gchar *tmp; + + kill(fixture->pid, SIGTERM); + + g_main_loop_run(fixture->loop); + g_main_loop_unref(fixture->loop); + + g_spawn_close_pid(fixture->pid); + + tmp = g_build_filename(fixture->test_dir, "foo", NULL); + g_unlink(tmp); + g_free(tmp); + + tmp = g_build_filename(fixture->test_dir, "qga.state", NULL); + g_unlink(tmp); + g_free(tmp); + + tmp = g_build_filename(fixture->test_dir, "sock", NULL); + g_unlink(tmp); + g_free(tmp); + + g_rmdir(fixture->test_dir); + g_free(fixture->test_dir); +} + +static void qmp_assertion_message_error(const char *domain, + const char *file, + int line, + const char *func, + const char *expr, + QDict *dict) +{ + const char *class, *desc; + char *s; + QDict *error; + + error = qdict_get_qdict(dict, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + + s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc); + g_assertion_message(domain, file, line, func, s); + g_free(s); +} + +#define qmp_assert_no_error(err) do { \ + if (qdict_haskey(err, "error")) { \ + qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__, \ + G_STRFUNC, #err, err); \ + } \ +} while (0) + +static void test_qga_sync_delimited(gconstpointer fix) +{ + const TestFixture *fixture = fix; + guint32 v, r = g_random_int(); + unsigned char c; + QDict *ret; + gchar *cmd; + + cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited'," + " 'arguments': {'id': %u } }", 0xff, r); + qmp_fd_send(fixture->fd, cmd); + g_free(cmd); + + v = read(fixture->fd, &c, 1); + g_assert_cmpint(v, ==, 1); + g_assert_cmpint(c, ==, 0xff); + + ret = qmp_fd_receive(fixture->fd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + v = qdict_get_int(ret, "return"); + g_assert_cmpint(r, ==, v); + + QDECREF(ret); +} + +static void test_qga_sync(gconstpointer fix) +{ + const TestFixture *fixture = fix; + guint32 v, r = g_random_int(); + QDict *ret; + gchar *cmd; + + cmd = g_strdup_printf("%c{'execute': 'guest-sync'," + " 'arguments': {'id': %u } }", 0xff, r); + ret = qmp_fd(fixture->fd, cmd); + g_free(cmd); + + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + v = qdict_get_int(ret, "return"); + g_assert_cmpint(r, ==, v); + + QDECREF(ret); +} + +static void test_qga_ping(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + QDECREF(ret); +} + +static void test_qga_invalid_cmd(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *error; + const gchar *class, *desc; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}"); + g_assert_nonnull(ret); + + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + + g_assert_cmpstr(class, ==, "CommandNotFound"); + g_assert_cmpint(strlen(desc), >, 0); + + QDECREF(ret); +} + +static void test_qga_info(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *val; + const gchar *version; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + val = qdict_get_qdict(ret, "return"); + version = qdict_get_try_str(val, "version"); + g_assert_cmpstr(version, ==, QEMU_VERSION); + + QDECREF(ret); +} + +static void test_qga_get_vcpus(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + /* check there is at least a cpu */ + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id")); + + QDECREF(ret); +} + +static void test_qga_get_fsinfo(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + /* check there is at least a fs */ + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk")); + + QDECREF(ret); +} + +static void test_qga_get_memory_block_info(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *val; + int64_t size; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}"); + g_assert_nonnull(ret); + + /* some systems might not expose memory block info in sysfs */ + if (!qdict_haskey(ret, "error")) { + /* check there is at least some memory */ + val = qdict_get_qdict(ret, "return"); + size = qdict_get_int(val, "size"); + g_assert_cmpint(size, >, 0); + } + + QDECREF(ret); +} + +static void test_qga_get_memory_blocks(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}"); + g_assert_nonnull(ret); + + /* some systems might not expose memory block info in sysfs */ + if (!qdict_haskey(ret, "error")) { + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + /* newer versions of qga may return empty list without error */ + if (entry) { + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online")); + } + } + + QDECREF(ret); +} + +static void test_qga_network_get_interfaces(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + /* check there is at least an interface */ + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name")); + + QDECREF(ret); +} + +static void test_qga_file_ops(gconstpointer fix) +{ + const TestFixture *fixture = fix; + const guchar helloworld[] = "Hello World!\n"; + const char *b64; + gchar *cmd, *path, *enc; + guchar *dec; + QDict *ret, *val; + int64_t id, eof; + gsize count; + FILE *f; + char tmp[100]; + + /* open */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," + " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); + QDECREF(ret); + + enc = g_base64_encode(helloworld, sizeof(helloworld)); + /* write */ + cmd = g_strdup_printf("{'execute': 'guest-file-write'," + " 'arguments': { 'handle': %" PRId64 "," + " 'buf-b64': '%s' } }", id, enc); + ret = qmp_fd(fixture->fd, cmd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert_cmpint(eof, ==, 0); + QDECREF(ret); + g_free(cmd); + + /* flush */ + cmd = g_strdup_printf("{'execute': 'guest-file-flush'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); + + /* close */ + cmd = g_strdup_printf("{'execute': 'guest-file-close'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); + + /* check content */ + path = g_build_filename(fixture->test_dir, "foo", NULL); + f = fopen(path, "r"); + g_assert_nonnull(f); + count = fread(tmp, 1, sizeof(tmp), f); + g_assert_cmpint(count, ==, sizeof(helloworld)); + tmp[count] = 0; + g_assert_cmpstr(tmp, ==, (char *)helloworld); + fclose(f); + + /* open */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," + " 'arguments': { 'path': 'foo', 'mode': 'r' } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); + QDECREF(ret); + + /* read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert(eof); + g_assert_cmpstr(b64, ==, enc); + + QDECREF(ret); + g_free(cmd); + g_free(enc); + + /* read eof */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, 0); + g_assert(eof); + g_assert_cmpstr(b64, ==, ""); + QDECREF(ret); + g_free(cmd); + + /* seek */ + cmd = g_strdup_printf("{'execute': 'guest-file-seek'," + " 'arguments': { 'handle': %" PRId64 ", " + " 'offset': %d, 'whence': %d } }", + id, 6, SEEK_SET); + ret = qmp_fd(fixture->fd, cmd); + qmp_assert_no_error(ret); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "position"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, 6); + g_assert(!eof); + QDECREF(ret); + g_free(cmd); + + /* partial read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, sizeof(helloworld) - 6); + g_assert(eof); + dec = g_base64_decode(b64, &count); + g_assert_cmpint(count, ==, sizeof(helloworld) - 6); + g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6); + g_free(dec); + + QDECREF(ret); + g_free(cmd); + + /* close */ + cmd = g_strdup_printf("{'execute': 'guest-file-close'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); +} + +static void test_qga_get_time(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + int64_t time; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + time = qdict_get_int(ret, "return"); + g_assert_cmpint(time, >, 0); + + QDECREF(ret); +} + +static void test_qga_set_time(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + int64_t current, time; + gchar *cmd; + + /* get current time */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + current = qdict_get_int(ret, "return"); + g_assert_cmpint(current, >, 0); + QDECREF(ret); + + /* set some old time */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-set-time'," + " 'arguments': { 'time': 1000 } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); + + /* check old time */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + time = qdict_get_int(ret, "return"); + g_assert_cmpint(time / 1000, <, G_USEC_PER_SEC * 10); + QDECREF(ret); + + /* set back current time */ + cmd = g_strdup_printf("{'execute': 'guest-set-time'," + " 'arguments': { 'time': %" PRId64 " } }", + current + time * 1000); + ret = qmp_fd(fixture->fd, cmd); + g_free(cmd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); +} + +static void test_qga_fstrim(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fstrim'," + " arguments: { minimum: 4194304 } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "paths")); + + QDECREF(ret); +} + +static void test_qga_blacklist(gconstpointer data) +{ + TestFixture fix; + QDict *ret, *error; + const gchar *class, *desc; + + fixture_setup(&fix, "-b guest-ping,guest-get-time"); + + /* check blacklist */ + ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}"); + g_assert_nonnull(ret); + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); + QDECREF(ret); + + ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); + QDECREF(ret); + + /* check something work */ + ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}"); + qmp_assert_no_error(ret); + QDECREF(ret); + + fixture_tear_down(&fix, NULL); +} + +static void test_qga_config(gconstpointer data) +{ + GError *error = NULL; + char *cwd, *cmd, *out, *err, *str, **strv, *conf, **argv = NULL; + char *env[2]; + int status, tmp; + gsize n; + GKeyFile *kf; + const char *qga_config = + "[general]\n" + "daemon=false\n" + "method=virtio-serial\n" + "path=/path/to/org.qemu.guest_agent.0\n" + "pidfile=/var/foo/qemu-ga.pid\n" + "statedir=/var/state\n" + "verbose=true\n" + "blacklist=guest-ping;guest-get-time\n"; + + tmp = g_file_open_tmp(NULL, &conf, &error); + g_assert_no_error(error); + g_assert_cmpint(tmp, >=, 0); + g_assert_cmpstr(conf, !=, ""); + + g_file_set_contents(conf, qga_config, -1, &error); + g_assert_no_error(error); + + cwd = g_get_current_dir(); + cmd = g_strdup_printf("%s%cqemu-ga -D", + cwd, G_DIR_SEPARATOR); + g_shell_parse_argv(cmd, NULL, &argv, &error); + g_assert_no_error(error); + + env[0] = g_strdup_printf("QGA_CONF=%s", conf); + env[1] = NULL; + g_spawn_sync(NULL, argv, env, 0, + NULL, NULL, &out, &err, &status, &error); + g_assert_no_error(error); + g_assert_cmpstr(err, ==, ""); + g_assert_cmpint(status, ==, 0); + + kf = g_key_file_new(); + g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error); + g_assert_no_error(error); + + str = g_key_file_get_start_group(kf); + g_assert_cmpstr(str, ==, "general"); + g_free(str); + + g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error)); + g_assert_no_error(error); + + str = g_key_file_get_string(kf, "general", "method", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "virtio-serial"); + g_free(str); + + str = g_key_file_get_string(kf, "general", "path", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0"); + g_free(str); + + str = g_key_file_get_string(kf, "general", "pidfile", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid"); + g_free(str); + + str = g_key_file_get_string(kf, "general", "statedir", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "/var/state"); + g_free(str); + + g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error)); + g_assert_no_error(error); + + strv = g_key_file_get_string_list(kf, "general", "blacklist", &n, &error); + g_assert_cmpint(n, ==, 2); +#if GLIB_CHECK_VERSION(2, 44, 0) + g_assert_true(g_strv_contains((const char * const *)strv, + "guest-ping")); + g_assert_true(g_strv_contains((const char * const *)strv, + "guest-get-time")); +#endif + g_assert_no_error(error); + g_strfreev(strv); + + g_free(out); + g_free(err); + g_free(conf); + g_free(env[0]); + g_key_file_free(kf); + + close(tmp); +} + +static void test_qga_fsfreeze_status(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + const gchar *status; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + status = qdict_get_try_str(ret, "return"); + g_assert_cmpstr(status, ==, "thawed"); + + QDECREF(ret); +} + +static void test_qga_fsfreeze_and_thaw(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + const gchar *status; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-freeze'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + status = qdict_get_try_str(ret, "return"); + g_assert_cmpstr(status, ==, "frozen"); + QDECREF(ret); + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-thaw'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); +} + +int main(int argc, char **argv) +{ + TestFixture fix; + int ret; + + setlocale (LC_ALL, ""); + g_test_init(&argc, &argv, NULL); + fixture_setup(&fix, NULL); + + g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited); + g_test_add_data_func("/qga/sync", &fix, test_qga_sync); + g_test_add_data_func("/qga/ping", &fix, test_qga_ping); + g_test_add_data_func("/qga/info", &fix, test_qga_info); + g_test_add_data_func("/qga/network-get-interfaces", &fix, + test_qga_network_get_interfaces); + g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus); + g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo); + g_test_add_data_func("/qga/get-memory-block-info", &fix, + test_qga_get_memory_block_info); + g_test_add_data_func("/qga/get-memory-blocks", &fix, + test_qga_get_memory_blocks); + g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops); + g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time); + g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd); + g_test_add_data_func("/qga/fsfreeze-status", &fix, + test_qga_fsfreeze_status); + + g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist); + g_test_add_data_func("/qga/config", NULL, test_qga_config); + + if (g_getenv("QGA_TEST_SIDE_EFFECTING")) { + g_test_add_data_func("/qga/fsfreeze-and-thaw", &fix, + test_qga_fsfreeze_and_thaw); + g_test_add_data_func("/qga/set-time", &fix, test_qga_set_time); + g_test_add_data_func("/qga/fstrim", &fix, test_qga_fstrim); + } + + ret = g_test_run(); + + fixture_tear_down(&fix, NULL); + + return ret; +} diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index 1d620e04fb..4d13bd09b3 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -27,7 +27,7 @@ #include "qemu-common.h" #include "migration/migration.h" #include "migration/vmstate.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" static char temp_file[] = "/tmp/vmst.test.XXXXXX"; static int temp_fd; diff --git a/thread-pool.c b/thread-pool.c index ac909f4986..402c778b47 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -18,7 +18,7 @@ #include "qemu/queue.h" #include "qemu/thread.h" #include "qemu/osdep.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "trace.h" #include "block/thread-pool.h" #include "qemu/main-loop.h" diff --git a/ui/console.c b/ui/console.c index 31f0d35987..cf649b2612 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1962,7 +1962,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) chr->init(chr); } -static CharDriverState *text_console_init(ChardevVC *vc) +static CharDriverState *text_console_init(ChardevVC *vc, Error **errp) { CharDriverState *chr; QemuConsole *s; @@ -1993,6 +1993,7 @@ static CharDriverState *text_console_init(ChardevVC *vc) if (!s) { g_free(chr); + error_setg(errp, "cannot create text console"); return NULL; } @@ -2012,9 +2013,10 @@ static CharDriverState *text_console_init(ChardevVC *vc) static VcHandler *vc_handler = text_console_init; -CharDriverState *vc_init(ChardevVC *vc) +static CharDriverState *vc_init(const char *id, ChardevBackend *backend, + ChardevReturn *ret, Error **errp) { - return vc_handler(vc); + return vc_handler(backend->vc, errp); } void register_vc_handler(VcHandler *handler) @@ -2093,7 +2095,8 @@ static const TypeInfo qemu_console_info = { static void register_types(void) { type_register_static(&qemu_console_info); - register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc); + register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc, + vc_init); } type_init(register_types); @@ -1591,7 +1591,7 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) static int nb_vcs; static CharDriverState *vcs[MAX_VCS]; -static CharDriverState *gd_vc_handler(ChardevVC *unused) +static CharDriverState *gd_vc_handler(ChardevVC *unused, Error **errp) { CharDriverState *chr; @@ -647,49 +647,6 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, vnc_write_s32(vs, encoding); } -void buffer_reserve(Buffer *buffer, size_t len) -{ - if ((buffer->capacity - buffer->offset) < len) { - buffer->capacity += (len + 1024); - buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); - } -} - -static int buffer_empty(Buffer *buffer) -{ - return buffer->offset == 0; -} - -uint8_t *buffer_end(Buffer *buffer) -{ - return buffer->buffer + buffer->offset; -} - -void buffer_reset(Buffer *buffer) -{ - buffer->offset = 0; -} - -void buffer_free(Buffer *buffer) -{ - g_free(buffer->buffer); - buffer->offset = 0; - buffer->capacity = 0; - buffer->buffer = NULL; -} - -void buffer_append(Buffer *buffer, const void *data, size_t len) -{ - memcpy(buffer->buffer + buffer->offset, data, len); - buffer->offset += len; -} - -void buffer_advance(Buffer *buf, size_t len) -{ - memmove(buf->buffer, buf->buffer + len, - (buf->offset - len)); - buf->offset -= len; -} static void vnc_desktop_resize(VncState *vs) { @@ -3506,18 +3463,14 @@ void vnc_display_open(const char *id, Error **errp) { VncDisplay *vs = vnc_display_find(id); QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); - QemuOpts *sopts, *wsopts; + SocketAddress *saddr = NULL, *wsaddr = NULL; const char *share, *device_id; QemuConsole *con; bool password = false; bool reverse = false; const char *vnc; - const char *has_to; char *h; - bool has_ipv4 = false; - bool has_ipv6 = false; const char *credid; - const char *websocket; bool sasl = false; #ifdef CONFIG_VNC_SASL int saslErr; @@ -3539,44 +3492,83 @@ void vnc_display_open(const char *id, Error **errp) return; } - sopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - wsopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - h = strrchr(vnc, ':'); if (h) { - char *host; size_t hlen = h - vnc; - if (vnc[0] == '[' && vnc[hlen - 1] == ']') { - host = g_strndup(vnc + 1, hlen - 2); + const char *websocket = qemu_opt_get(opts, "websocket"); + int to = qemu_opt_get_number(opts, "to", 0); + bool has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false); + bool has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false); + + saddr = g_new0(SocketAddress, 1); + if (websocket) { + if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) { + error_setg(errp, + "SHA1 hash support is required for websockets"); + goto fail; + } + + wsaddr = g_new0(SocketAddress, 1); + vs->ws_enabled = true; + } + + if (strncmp(vnc, "unix:", 5) == 0) { + saddr->kind = SOCKET_ADDRESS_KIND_UNIX; + saddr->q_unix = g_new0(UnixSocketAddress, 1); + saddr->q_unix->path = g_strdup(vnc + 5); + + if (vs->ws_enabled) { + error_setg(errp, "UNIX sockets not supported with websock"); + goto fail; + } } else { - host = g_strndup(vnc, hlen); + unsigned long long baseport; + saddr->kind = SOCKET_ADDRESS_KIND_INET; + saddr->inet = g_new0(InetSocketAddress, 1); + if (vnc[0] == '[' && vnc[hlen - 1] == ']') { + saddr->inet->host = g_strndup(vnc + 1, hlen - 2); + } else { + saddr->inet->host = g_strndup(vnc, hlen); + } + if (parse_uint_full(h + 1, &baseport, 10) < 0) { + error_setg(errp, "can't convert to a number: %s", h + 1); + goto fail; + } + if (baseport > 65535 || + baseport + 5900 > 65535) { + error_setg(errp, "port %s out of range", h + 1); + goto fail; + } + saddr->inet->port = g_strdup_printf( + "%d", (int)baseport + 5900); + + if (to) { + saddr->inet->has_to = true; + saddr->inet->to = to; + } + saddr->inet->ipv4 = saddr->inet->has_ipv4 = has_ipv4; + saddr->inet->ipv6 = saddr->inet->has_ipv6 = has_ipv6; + + if (vs->ws_enabled) { + wsaddr->kind = SOCKET_ADDRESS_KIND_INET; + wsaddr->inet = g_new0(InetSocketAddress, 1); + wsaddr->inet->host = g_strdup(saddr->inet->host); + wsaddr->inet->port = g_strdup(websocket); + + if (to) { + wsaddr->inet->has_to = true; + wsaddr->inet->to = to; + } + wsaddr->inet->ipv4 = wsaddr->inet->has_ipv4 = has_ipv4; + wsaddr->inet->ipv6 = wsaddr->inet->has_ipv6 = has_ipv6; + } } - qemu_opt_set(sopts, "host", host, &error_abort); - qemu_opt_set(wsopts, "host", host, &error_abort); - qemu_opt_set(sopts, "port", h+1, &error_abort); - g_free(host); } else { error_setg(errp, "no vnc port specified"); goto fail; } - has_to = qemu_opt_get(opts, "to"); - has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false); - has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false); - if (has_to) { - qemu_opt_set(sopts, "to", has_to, &error_abort); - qemu_opt_set(wsopts, "to", has_to, &error_abort); - } - if (has_ipv4) { - qemu_opt_set(sopts, "ipv4", "on", &error_abort); - qemu_opt_set(wsopts, "ipv4", "on", &error_abort); - } - if (has_ipv6) { - qemu_opt_set(sopts, "ipv6", "on", &error_abort); - qemu_opt_set(wsopts, "ipv6", "on", &error_abort); - } - password = qemu_opt_get_bool(opts, "password", false); if (password) { if (fips_get_state()) { @@ -3682,16 +3674,6 @@ void vnc_display_open(const char *id, Error **errp) } vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); - websocket = qemu_opt_get(opts, "websocket"); - if (websocket) { - vs->ws_enabled = true; - qemu_opt_set(wsopts, "port", websocket, &error_abort); - if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) { - error_setg(errp, "SHA1 hash support is required for websockets"); - goto fail; - } - } - #ifdef CONFIG_VNC_JPEG vs->lossy = qemu_opt_get_bool(opts, "lossy", false); #endif @@ -3725,7 +3707,7 @@ void vnc_display_open(const char *id, Error **errp) } #endif - if (vnc_display_setup_auth(vs, password, sasl, websocket, errp) < 0) { + if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) { goto fail; } @@ -3770,37 +3752,31 @@ void vnc_display_open(const char *id, Error **errp) int csock; vs->lsock = -1; vs->lwebsock = -1; - if (strncmp(vnc, "unix:", 5) == 0) { - csock = unix_connect(vnc+5, errp); - } else { - csock = inet_connect(vnc, errp); + if (vs->ws_enabled) { + error_setg(errp, "Cannot use websockets in reverse mode"); + goto fail; } + csock = socket_connect(saddr, errp, NULL, NULL); if (csock < 0) { goto fail; } + vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX; vnc_connect(vs, csock, false, false); } else { /* listen for connects */ - if (strncmp(vnc, "unix:", 5) == 0) { - vs->lsock = unix_listen(vnc+5, NULL, 0, errp); - if (vs->lsock < 0) { - goto fail; - } - vs->is_unix = true; - } else { - vs->lsock = inet_listen_opts(sopts, 5900, errp); - if (vs->lsock < 0) { - goto fail; - } - if (vs->ws_enabled) { - vs->lwebsock = inet_listen_opts(wsopts, 0, errp); - if (vs->lwebsock < 0) { - if (vs->lsock != -1) { - close(vs->lsock); - vs->lsock = -1; - } - goto fail; + vs->lsock = socket_listen(saddr, errp); + if (vs->lsock < 0) { + goto fail; + } + vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX; + if (vs->ws_enabled) { + vs->lwebsock = socket_listen(wsaddr, errp); + if (vs->lwebsock < 0) { + if (vs->lsock != -1) { + close(vs->lsock); + vs->lsock = -1; } + goto fail; } } vs->enabled = true; @@ -3810,13 +3786,14 @@ void vnc_display_open(const char *id, Error **errp) NULL, vs); } } - qemu_opts_del(sopts); - qemu_opts_del(wsopts); + + qapi_free_SocketAddress(saddr); + qapi_free_SocketAddress(wsaddr); return; fail: - qemu_opts_del(sopts); - qemu_opts_del(wsopts); + qapi_free_SocketAddress(saddr); + qapi_free_SocketAddress(wsaddr); vs->enabled = false; vs->ws_enabled = false; } @@ -34,6 +34,7 @@ #include "audio/audio.h" #include "qemu/bitmap.h" #include "crypto/tlssession.h" +#include "qemu/buffer.h" #include <zlib.h> #include <stdbool.h> @@ -56,13 +57,6 @@ * *****************************************************************************/ -typedef struct Buffer -{ - size_t capacity; - size_t offset; - uint8_t *buffer; -} Buffer; - typedef struct VncState VncState; typedef struct VncJob VncJob; typedef struct VncRect VncRect; @@ -535,14 +529,6 @@ ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, int last_errno); void start_client_init(VncState *vs); void start_auth_vnc(VncState *vs); -/* Buffer management */ -void buffer_reserve(Buffer *buffer, size_t len); -void buffer_reset(Buffer *buffer); -void buffer_free(Buffer *buffer); -void buffer_append(Buffer *buffer, const void *data, size_t len); -void buffer_advance(Buffer *buf, size_t len); -uint8_t *buffer_end(Buffer *buffer); - /* Misc helpers */ diff --git a/util/Makefile.objs b/util/Makefile.objs index bab1722fc8..d7cc39907f 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -25,3 +25,7 @@ util-obj-y += getauxval.o util-obj-y += readline.o util-obj-y += rfifolock.o util-obj-y += rcu.o +util-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o +util-obj-y += qemu-coroutine-sleep.o +util-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o +util-obj-y += buffer.o diff --git a/util/buffer.c b/util/buffer.c new file mode 100644 index 0000000000..cedd055680 --- /dev/null +++ b/util/buffer.c @@ -0,0 +1,65 @@ +/* + * QEMU generic buffers + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/buffer.h" + +void buffer_reserve(Buffer *buffer, size_t len) +{ + if ((buffer->capacity - buffer->offset) < len) { + buffer->capacity += (len + 1024); + buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); + } +} + +gboolean buffer_empty(Buffer *buffer) +{ + return buffer->offset == 0; +} + +uint8_t *buffer_end(Buffer *buffer) +{ + return buffer->buffer + buffer->offset; +} + +void buffer_reset(Buffer *buffer) +{ + buffer->offset = 0; +} + +void buffer_free(Buffer *buffer) +{ + g_free(buffer->buffer); + buffer->offset = 0; + buffer->capacity = 0; + buffer->buffer = NULL; +} + +void buffer_append(Buffer *buffer, const void *data, size_t len) +{ + memcpy(buffer->buffer + buffer->offset, data, len); + buffer->offset += len; +} + +void buffer_advance(Buffer *buffer, size_t len) +{ + memmove(buffer->buffer, buffer->buffer + len, + (buffer->offset - len)); + buffer->offset -= len; +} diff --git a/coroutine-gthread.c b/util/coroutine-gthread.c index 6bd6d6b22f..0bcd77867d 100644 --- a/coroutine-gthread.c +++ b/util/coroutine-gthread.c @@ -20,7 +20,7 @@ #include <glib.h> #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" typedef struct { Coroutine base; diff --git a/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index 63519fffc7..39842a4a90 100644 --- a/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -31,7 +31,7 @@ #include <pthread.h> #include <signal.h> #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" typedef struct { Coroutine base; diff --git a/coroutine-ucontext.c b/util/coroutine-ucontext.c index 259fcb48a4..26cbebb7a7 100644 --- a/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -27,7 +27,7 @@ #include <stdint.h> #include <ucontext.h> #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" #ifdef CONFIG_VALGRIND_H #include <valgrind/valgrind.h> diff --git a/coroutine-win32.c b/util/coroutine-win32.c index 17ace37dee..4f922c53af 100644 --- a/coroutine-win32.c +++ b/util/coroutine-win32.c @@ -23,7 +23,7 @@ */ #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" typedef struct { @@ -26,3 +26,40 @@ bool id_wellformed(const char *id) } return true; } + +#define ID_SPECIAL_CHAR '#' + +static const char *const id_subsys_str[] = { + [ID_QDEV] = "qdev", + [ID_BLOCK] = "block", +}; + +/* + * Generates an ID of the form PREFIX SUBSYSTEM NUMBER + * where: + * + * - PREFIX is the reserved character '#' + * - SUBSYSTEM identifies the subsystem creating the ID + * - NUMBER is a decimal number unique within SUBSYSTEM. + * + * Example: "#block146" + * + * Note that these IDs do not satisfy id_wellformed(). + * + * The caller is responsible for freeing the returned string with g_free() + */ +char *id_generate(IdSubSystems id) +{ + static uint64_t id_counters[ID_MAX]; + uint32_t rnd; + + assert(id < ID_MAX); + assert(id_subsys_str[id]); + + rnd = g_random_int_range(0, 100); + + return g_strdup_printf("%c%s%" PRIu64 "%02" PRId32, ID_SPECIAL_CHAR, + id_subsys_str[id], + id_counters[id]++, + rnd); +} diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 892d2d8ad2..914cef5c2c 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -470,3 +470,74 @@ int qemu_read_password(char *buf, int buf_size) printf("\n"); return ret; } + + +pid_t qemu_fork(Error **errp) +{ + sigset_t oldmask, newmask; + struct sigaction sig_action; + int saved_errno; + pid_t pid; + + /* + * Need to block signals now, so that child process can safely + * kill off caller's signal handlers without a race. + */ + sigfillset(&newmask); + if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) { + error_setg_errno(errp, errno, + "cannot block signals"); + return -1; + } + + pid = fork(); + saved_errno = errno; + + if (pid < 0) { + /* attempt to restore signal mask, but ignore failure, to + * avoid obscuring the fork failure */ + (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL); + error_setg_errno(errp, saved_errno, + "cannot fork child process"); + errno = saved_errno; + return -1; + } else if (pid) { + /* parent process */ + + /* Restore our original signal mask now that the child is + * safely running. Only documented failures are EFAULT (not + * possible, since we are using just-grabbed mask) or EINVAL + * (not possible, since we are using correct arguments). */ + (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL); + } else { + /* child process */ + size_t i; + + /* Clear out all signal handlers from parent so nothing + * unexpected can happen in our child once we unblock + * signals */ + sig_action.sa_handler = SIG_DFL; + sig_action.sa_flags = 0; + sigemptyset(&sig_action.sa_mask); + + for (i = 1; i < NSIG; i++) { + /* Only possible errors are EFAULT or EINVAL The former + * won't happen, the latter we expect, so no need to check + * return value */ + (void)sigaction(i, &sig_action, NULL); + } + + /* Unmask all signals in child, since we've no idea what the + * caller's done with their signal mask and don't want to + * propagate that to children */ + sigemptyset(&newmask); + if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) { + Error *local_err = NULL; + error_setg_errno(&local_err, errno, + "cannot unblock signals"); + error_report_err(local_err); + _exit(1); + } + } + return pid; +} diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 08f5a9cda2..09f9e98a40 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -496,3 +496,12 @@ int qemu_read_password(char *buf, int buf_size) buf[i] = '\0'; return 0; } + + +pid_t qemu_fork(Error **errp) +{ + errno = ENOSYS; + error_setg_errno(errp, errno, + "cannot fork child process"); + return -1; +} diff --git a/util/qemu-config.c b/util/qemu-config.c index 5fcfd0e6ac..687fd34cc6 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -219,6 +219,14 @@ static QemuOptsList machine_opts = { .name = "suppress-vmdesc", .type = QEMU_OPT_BOOL, .help = "Set on to disable self-describing migration", + },{ + .name = "aes-key-wrap", + .type = QEMU_OPT_BOOL, + .help = "enable/disable AES key wrapping using the CPACF wrapping key", + },{ + .name = "dea-key-wrap", + .type = QEMU_OPT_BOOL, + .help = "enable/disable DEA key wrapping using the CPACF wrapping key", }, { /* End of list */ } } diff --git a/qemu-coroutine-io.c b/util/qemu-coroutine-io.c index 28dc7351ac..e1eae7331e 100644 --- a/qemu-coroutine-io.c +++ b/util/qemu-coroutine-io.c @@ -24,7 +24,7 @@ */ #include "qemu-common.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qemu/iov.h" #include "qemu/main-loop.h" diff --git a/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 6b4903334b..130ee19d17 100644 --- a/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -23,8 +23,8 @@ */ #include "qemu-common.h" -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" #include "qemu/queue.h" #include "trace.h" diff --git a/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index 9abb7fdf31..b35db56356 100644 --- a/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -11,7 +11,7 @@ * */ -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qemu/timer.h" #include "block/aio.h" diff --git a/qemu-coroutine.c b/util/qemu-coroutine.c index c17a92b107..8953560223 100644 --- a/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -16,8 +16,8 @@ #include "qemu-common.h" #include "qemu/thread.h" #include "qemu/atomic.h" -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" enum { POOL_BATCH_SIZE = 64, diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 2add83a0fc..9142917be5 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -25,6 +25,9 @@ #include "monitor/monitor.h" #include "qemu/sockets.h" #include "qemu/main-loop.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi-visit.h" #ifndef AI_ADDRCONFIG # define AI_ADDRCONFIG 0 @@ -125,12 +128,15 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; - if ((qemu_opt_get(opts, "host") == NULL) || - (qemu_opt_get(opts, "port") == NULL)) { - error_setg(errp, "host and/or port not specified"); + if ((qemu_opt_get(opts, "host") == NULL)) { + error_setg(errp, "host not specified"); return -1; } - pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); + if (qemu_opt_get(opts, "port") != NULL) { + pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); + } else { + port[0] = '\0'; + } addr = qemu_opt_get(opts, "host"); to = qemu_opt_get_number(opts, "to", 0); @@ -142,6 +148,10 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) /* lookup */ if (port_offset) { unsigned long long baseport; + if (strlen(port) == 0) { + error_setg(errp, "port not specified"); + return -1; + } if (parse_uint_full(port, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", port); return -1; @@ -153,7 +163,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) } snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); } - rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); + rc = getaddrinfo(strlen(addr) ? addr : NULL, + strlen(port) ? port : NULL, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); @@ -586,12 +597,15 @@ fail: static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr) { - bool ipv4 = addr->ipv4 || !addr->has_ipv4; - bool ipv6 = addr->ipv6 || !addr->has_ipv6; + bool ipv4 = addr->has_ipv4 && addr->ipv4; + bool ipv6 = addr->has_ipv6 && addr->ipv6; - if (!ipv4 || !ipv6) { + if (ipv4 || ipv6) { qemu_opt_set_bool(opts, "ipv4", ipv4, &error_abort); qemu_opt_set_bool(opts, "ipv6", ipv6, &error_abort); + } else if (addr->has_ipv4 || addr->has_ipv6) { + qemu_opt_set_bool(opts, "ipv4", !addr->has_ipv4, &error_abort); + qemu_opt_set_bool(opts, "ipv6", !addr->has_ipv6, &error_abort); } if (addr->has_to) { qemu_opt_set_number(opts, "to", addr->to, &error_abort); @@ -1015,3 +1029,140 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) qemu_opts_del(opts); return fd; } + + +static SocketAddress * +socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, + socklen_t salen, + Error **errp) +{ + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + SocketAddress *addr; + int ret; + + ret = getnameinfo((struct sockaddr *)sa, salen, + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) { + error_setg(errp, "Cannot format numeric socket address: %s", + gai_strerror(ret)); + return NULL; + } + + addr = g_new0(SocketAddress, 1); + addr->kind = SOCKET_ADDRESS_KIND_INET; + addr->inet = g_new0(InetSocketAddress, 1); + addr->inet->host = g_strdup(host); + addr->inet->port = g_strdup(serv); + if (sa->ss_family == AF_INET) { + addr->inet->has_ipv4 = addr->inet->ipv4 = true; + } else { + addr->inet->has_ipv6 = addr->inet->ipv6 = true; + } + + return addr; +} + + +#ifndef WIN32 +static SocketAddress * +socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, + socklen_t salen, + Error **errp) +{ + SocketAddress *addr; + struct sockaddr_un *su = (struct sockaddr_un *)sa; + + addr = g_new0(SocketAddress, 1); + addr->kind = SOCKET_ADDRESS_KIND_UNIX; + addr->q_unix = g_new0(UnixSocketAddress, 1); + if (su->sun_path[0]) { + addr->q_unix->path = g_strndup(su->sun_path, + sizeof(su->sun_path)); + } + + return addr; +} +#endif /* WIN32 */ + +static SocketAddress * +socket_sockaddr_to_address(struct sockaddr_storage *sa, + socklen_t salen, + Error **errp) +{ + switch (sa->ss_family) { + case AF_INET: + case AF_INET6: + return socket_sockaddr_to_address_inet(sa, salen, errp); + +#ifndef WIN32 + case AF_UNIX: + return socket_sockaddr_to_address_unix(sa, salen, errp); +#endif /* WIN32 */ + + default: + error_setg(errp, "socket family %d unsupported", + sa->ss_family); + return NULL; + } + return 0; +} + + +SocketAddress *socket_local_address(int fd, Error **errp) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) { + error_setg_errno(errp, socket_error(), "%s", + "Unable to query local socket address"); + return NULL; + } + + return socket_sockaddr_to_address(&ss, sslen, errp); +} + + +SocketAddress *socket_remote_address(int fd, Error **errp) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) { + error_setg_errno(errp, socket_error(), "%s", + "Unable to query remote socket address"); + return NULL; + } + + return socket_sockaddr_to_address(&ss, sslen, errp); +} + + +void qapi_copy_SocketAddress(SocketAddress **p_dest, + SocketAddress *src) +{ + QmpOutputVisitor *qov; + QmpInputVisitor *qiv; + Visitor *ov, *iv; + QObject *obj; + + *p_dest = NULL; + + qov = qmp_output_visitor_new(); + ov = qmp_output_get_visitor(qov); + visit_type_SocketAddress(ov, &src, NULL, &error_abort); + obj = qmp_output_get_qobject(qov); + qmp_output_visitor_cleanup(qov); + if (!obj) { + return; + } + + qiv = qmp_input_visitor_new(obj); + iv = qmp_input_get_visitor(qiv); + visit_type_SocketAddress(iv, p_dest, NULL, &error_abort); + qmp_input_visitor_cleanup(qiv); + qobject_decref(obj); +} @@ -512,6 +512,10 @@ static QemuOptsList qemu_fw_cfg_opts = { .type = QEMU_OPT_STRING, .help = "Sets the name of the file from which\n" "the fw_cfg blob will be loaded", + }, { + .name = "string", + .type = QEMU_OPT_STRING, + .help = "Sets content of the blob to be inserted from a string", }, { /* end of list */ } }, @@ -2239,11 +2243,16 @@ char *qemu_find_file(int type, const char *name) return NULL; } +static inline bool nonempty_str(const char *str) +{ + return str && *str; +} + static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) { gchar *buf; size_t size; - const char *name, *file; + const char *name, *file, *str; if (opaque == NULL) { error_report("fw_cfg device not available"); @@ -2251,8 +2260,15 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) } name = qemu_opt_get(opts, "name"); file = qemu_opt_get(opts, "file"); - if (name == NULL || *name == '\0' || file == NULL || *file == '\0') { - error_report("invalid argument value"); + str = qemu_opt_get(opts, "string"); + + /* we need name and either a file or the content string */ + if (!(nonempty_str(name) && (nonempty_str(file) || nonempty_str(str)))) { + error_report("invalid argument(s)"); + return -1; + } + if (nonempty_str(file) && nonempty_str(str)) { + error_report("file and string are mutually exclusive"); return -1; } if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) { @@ -2263,9 +2279,14 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) error_report("WARNING: externally provided fw_cfg item names " "should be prefixed with \"opt/\"!"); } - if (!g_file_get_contents(file, &buf, &size, NULL)) { - error_report("can't load %s", file); - return -1; + if (nonempty_str(str)) { + size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */ + buf = g_memdup(str, size); + } else { + if (!g_file_get_contents(file, &buf, &size, NULL)) { + error_report("can't load %s", file); + return -1; + } } fw_cfg_add_file((FWCfgState *)opaque, name, buf, size); return 0; |