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