To cope with the QEMU binary being changed while a VM is running, it is neccessary to persist the original qemu capabilities at the time the VM is booted. * src/qemu/qemu_capabilities.c, src/qemu/qemu_capabilities.h: Add an enum for a string rep of every capability * src/qemu/qemu_domain.c, src/qemu/qemu_domain.h: Support for storing capabilities in the domain status XML * src/qemu/qemu_process.c: Populate & free QEMU capabilities at domain startup --- src/qemu/qemu_capabilities.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 45 ++++++++++++++++++++++++ src/qemu/qemu_domain.h | 3 ++ src/qemu/qemu_process.c | 42 +++++++++++----------- 5 files changed, 148 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 63486cc..620143e 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -43,6 +43,84 @@ #define VIR_FROM_THIS VIR_FROM_QEMU +/* While not public, these strings must not change. They + * are used in domain status files which are read on + * daemon restarts + */ +VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, + "kqemu", /* 0 */ + "vnc-colon", + "no-reboot", + "drive", + "drive-boot", + + "name", /* 5 */ + "uuid", + "domid", + "vnet-hdr", + "migrate-kvm-stdio", + + "migrate-qemu-tcp", /* 10 */ + "migrate-qemu-exec", + "drive-cache-v2", + "kvm", + "drive-format", + + "vga", /* 15 */ + "0.10", + "pci-device", + "mem-path", + "drive-serial", + + "xen-domid", /* 20 */ + "migrate-qemu-unix", + "chardev", + "enable-kvm", + "monitor-json", + + "balloon", /* 25 */ + "device", + "sdl", + "smp-topology", + "netdev", + + "rtc", /* 30 */ + "vnet-host", + "rtc-td-hack", + "no-hpet", + "no-kvm-pit", + + "tdf", /* 35 */ + "pci-configfd", + "nodefconfig", + "boot-menu", + "enable-kqemu", + + "fsdev", /* 40 */ + "nesting", + "name-process", + "drive-readonly", + "smbios-type", + + "vga-qxl", /* 45 */ + "spice", + "vga-none", + "migrate-qemu-fd", + "boot-index", + + "hda-duplex", /* 50 */ + "drive-aio", + "pci-multibus", + "pci-bootindex", + "ccid-emulated", + + "ccid-passthru", /* 55 */ + "chardev-spicevmc", + "device-spicevmc", + "virtio-tx-alg", + "device-qxl-vga", + ); + struct qemu_feature_flags { const char *name; const int default_on; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 68c5958..ab47f22 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -141,5 +141,6 @@ int qemuCapsParseHelpStr(const char *qemu, int qemuCapsParseDeviceStr(const char *str, virBitmapPtr qemuCaps); +VIR_ENUM_DECL(qemuCaps); #endif /* __QEMU_CAPABILITIES_H__*/ diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index a947b4e..3033ff5 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -25,6 +25,7 @@ #include "qemu_domain.h" #include "qemu_command.h" +#include "qemu_capabilities.h" #include "memory.h" #include "logging.h" #include "virterror_internal.h" @@ -113,6 +114,8 @@ static void qemuDomainObjPrivateFree(void *data) { qemuDomainObjPrivatePtr priv = data; + qemuCapsFree(priv->qemuCaps); + qemuDomainPCIAddressSetFree(priv->pciaddrs); virDomainChrSourceDefFree(priv->monConfig); VIR_FREE(priv->vcpupids); @@ -160,6 +163,18 @@ static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data) virBufferAddLit(buf, " </vcpus>\n"); } + if (priv->qemuCaps) { + int i; + virBufferAddLit(buf, " <qemuCaps>\n"); + for (i = 0 ; i < QEMU_CAPS_LAST ; i++) { + if (qemuCapsGet(priv->qemuCaps, i)) { + virBufferVSprintf(buf, " <flag name='%s'/>\n", + qemuCapsTypeToString(i)); + } + } + virBufferAddLit(buf, " </qemuCaps>\n"); + } + return 0; } @@ -170,6 +185,7 @@ static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data) char *tmp; int n, i; xmlNodePtr *nodes = NULL; + virBitmapPtr qemuCaps = NULL; if (VIR_ALLOC(priv->monConfig) < 0) { virReportOOMError(); @@ -235,12 +251,41 @@ static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data) VIR_FREE(nodes); } + if ((n = virXPathNodeSet("./qemuCaps/flag", ctxt, &nodes)) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("failed to parse qemu capabilities flags")); + goto error; + } + if (n > 0) { + if (!(qemuCaps = qemuCapsNew())) + goto error; + + for (i = 0 ; i < n ; i++) { + char *str = virXMLPropString(nodes[i], "name"); + if (str) { + int flag = qemuCapsTypeFromString(str); + VIR_FREE(str); + if (flag < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown qemu capabilities flag %s"), str); + goto error; + } + qemuCapsSet(qemuCaps, flag); + } + } + + priv->qemuCaps = qemuCaps; + } + VIR_FREE(nodes); + + return 0; error: virDomainChrSourceDefFree(priv->monConfig); priv->monConfig = NULL; VIR_FREE(nodes); + qemuCapsFree(qemuCaps); return -1; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 8258900..b0ecc5a 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -28,6 +28,7 @@ # include "domain_conf.h" # include "qemu_monitor.h" # include "qemu_conf.h" +# include "bitmap.h" /* Only 1 job is allowed at any time * A job includes *all* monitor commands, even those just querying @@ -77,6 +78,8 @@ struct _qemuDomainObjPrivate { qemuDomainPCIAddressSetPtr pciaddrs; int persistentAddrs; + + virBitmapPtr qemuCaps; }; struct qemuDomainWatchdogEvent diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7691cbe..eb2050d 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1288,8 +1288,7 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn, static int qemuProcessInitPasswords(virConnectPtr conn, struct qemud_driver *driver, - virDomainObjPtr vm, - virBitmapPtr qemuCaps) + virDomainObjPtr vm) { int ret = 0; qemuDomainObjPrivatePtr priv = vm->privateData; @@ -1311,7 +1310,7 @@ qemuProcessInitPasswords(virConnectPtr conn, if (ret < 0) goto cleanup; - if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { int i; for (i = 0 ; i < vm->def->ndisks ; i++) { @@ -1965,7 +1964,6 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa struct qemuProcessReconnectData *data = opaque; struct qemud_driver *driver = data->driver; qemuDomainObjPrivatePtr priv; - virBitmapPtr qemuCaps = NULL; virConnectPtr conn = data->conn; virDomainObjLock(obj); @@ -1986,13 +1984,16 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa goto error; } - /* XXX we should be persisting the original flags in the XML - * not re-detecting them, since the binary may have changed - * since launch time */ - if (qemuCapsExtractVersionInfo(obj->def->emulator, obj->def->os.arch, + /* If upgrading from old QEMU we won't have found any + * caps in the domain status, so re-query them + */ + if (!priv->qemuCaps && + qemuCapsExtractVersionInfo(obj->def->emulator, obj->def->os.arch, NULL, - &qemuCaps) >= 0 && - qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { + &priv->qemuCaps) < 0) + goto error; + + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { priv->persistentAddrs = 1; if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)) || @@ -2012,11 +2013,9 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa if (virDomainObjUnref(obj) > 0) virDomainObjUnlock(obj); - qemuCapsFree(qemuCaps); return; error: - qemuCapsFree(qemuCaps); if (!virDomainObjIsActive(obj)) { if (virDomainObjUnref(obj) > 0) virDomainObjUnlock(obj); @@ -2058,7 +2057,6 @@ int qemuProcessStart(virConnectPtr conn, enum virVMOperationType vmop) { int ret; - virBitmapPtr qemuCaps = NULL; off_t pos = -1; char ebuf[1024]; char *pidfile = NULL; @@ -2204,9 +2202,11 @@ int qemuProcessStart(virConnectPtr conn, goto cleanup; VIR_DEBUG0("Determining emulator version"); + qemuCapsFree(priv->qemuCaps); + priv->qemuCaps = NULL; if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch, NULL, - &qemuCaps) < 0) + &priv->qemuCaps) < 0) goto cleanup; VIR_DEBUG0("Setting up domain cgroup (if required)"); @@ -2223,7 +2223,7 @@ int qemuProcessStart(virConnectPtr conn, goto cleanup; #if HAVE_YAJL - if (qemuCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) priv->monJSON = 1; else #endif @@ -2252,7 +2252,7 @@ int qemuProcessStart(virConnectPtr conn, * we also need to populate the PCi address set cache for later * use in hotplug */ - if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { VIR_DEBUG0("Assigning domain PCI addresses"); /* Populate cache with current addresses */ if (priv->pciaddrs) { @@ -2274,7 +2274,7 @@ int qemuProcessStart(virConnectPtr conn, VIR_DEBUG0("Building emulator command line"); if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig, - priv->monJSON != 0, qemuCaps, + priv->monJSON != 0, priv->qemuCaps, migrateFrom, stdin_fd, vm->current_snapshot, vmop))) goto cleanup; @@ -2385,12 +2385,12 @@ int qemuProcessStart(virConnectPtr conn, goto cleanup; VIR_DEBUG0("Setting any required VM passwords"); - if (qemuProcessInitPasswords(conn, driver, vm, qemuCaps) < 0) + if (qemuProcessInitPasswords(conn, driver, vm) < 0) goto cleanup; /* If we have -device, then addresses are assigned explicitly. * If not, then we have to detect dynamic ones here */ - if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { + if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { VIR_DEBUG0("Determining domain device PCI addresses"); if (qemuProcessInitPCIAddresses(driver, vm) < 0) goto cleanup; @@ -2421,7 +2421,6 @@ int qemuProcessStart(virConnectPtr conn, if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) goto cleanup; - qemuCapsFree(qemuCaps); virCommandFree(cmd); VIR_FORCE_CLOSE(logfile); @@ -2431,7 +2430,6 @@ cleanup: /* We jump here if we failed to start the VM for any reason, or * if we failed to initialize the now running VM. kill it off and * pretend we never started it */ - qemuCapsFree(qemuCaps); virCommandFree(cmd); VIR_FORCE_CLOSE(logfile); qemuProcessStop(driver, vm, 0); @@ -2602,6 +2600,8 @@ retry: vm->state = VIR_DOMAIN_SHUTOFF; VIR_FREE(priv->vcpupids); priv->nvcpupids = 0; + qemuCapsFree(priv->qemuCaps); + priv->qemuCaps = NULL; /* The "release" hook cleans up additional resources */ if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list