1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-07 17:28:15 +00:00

Persist qemu capabilities in the domain status file

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
This commit is contained in:
Daniel P. Berrange 2011-05-04 12:55:38 +01:00
parent 9b889aacef
commit 43c01d3838
5 changed files with 148 additions and 21 deletions

View File

@ -43,6 +43,84 @@
#define VIR_FROM_THIS VIR_FROM_QEMU #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 { struct qemu_feature_flags {
const char *name; const char *name;
const int default_on; const int default_on;

View File

@ -141,5 +141,6 @@ int qemuCapsParseHelpStr(const char *qemu,
int qemuCapsParseDeviceStr(const char *str, int qemuCapsParseDeviceStr(const char *str,
virBitmapPtr qemuCaps); virBitmapPtr qemuCaps);
VIR_ENUM_DECL(qemuCaps);
#endif /* __QEMU_CAPABILITIES_H__*/ #endif /* __QEMU_CAPABILITIES_H__*/

View File

@ -25,6 +25,7 @@
#include "qemu_domain.h" #include "qemu_domain.h"
#include "qemu_command.h" #include "qemu_command.h"
#include "qemu_capabilities.h"
#include "memory.h" #include "memory.h"
#include "logging.h" #include "logging.h"
#include "virterror_internal.h" #include "virterror_internal.h"
@ -113,6 +114,8 @@ static void qemuDomainObjPrivateFree(void *data)
{ {
qemuDomainObjPrivatePtr priv = data; qemuDomainObjPrivatePtr priv = data;
qemuCapsFree(priv->qemuCaps);
qemuDomainPCIAddressSetFree(priv->pciaddrs); qemuDomainPCIAddressSetFree(priv->pciaddrs);
virDomainChrSourceDefFree(priv->monConfig); virDomainChrSourceDefFree(priv->monConfig);
VIR_FREE(priv->vcpupids); VIR_FREE(priv->vcpupids);
@ -160,6 +163,18 @@ static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data)
virBufferAddLit(buf, " </vcpus>\n"); 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; return 0;
} }
@ -170,6 +185,7 @@ static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
char *tmp; char *tmp;
int n, i; int n, i;
xmlNodePtr *nodes = NULL; xmlNodePtr *nodes = NULL;
virBitmapPtr qemuCaps = NULL;
if (VIR_ALLOC(priv->monConfig) < 0) { if (VIR_ALLOC(priv->monConfig) < 0) {
virReportOOMError(); virReportOOMError();
@ -235,12 +251,41 @@ static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
VIR_FREE(nodes); 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; return 0;
error: error:
virDomainChrSourceDefFree(priv->monConfig); virDomainChrSourceDefFree(priv->monConfig);
priv->monConfig = NULL; priv->monConfig = NULL;
VIR_FREE(nodes); VIR_FREE(nodes);
qemuCapsFree(qemuCaps);
return -1; return -1;
} }

View File

@ -28,6 +28,7 @@
# include "domain_conf.h" # include "domain_conf.h"
# include "qemu_monitor.h" # include "qemu_monitor.h"
# include "qemu_conf.h" # include "qemu_conf.h"
# include "bitmap.h"
/* Only 1 job is allowed at any time /* Only 1 job is allowed at any time
* A job includes *all* monitor commands, even those just querying * A job includes *all* monitor commands, even those just querying
@ -77,6 +78,8 @@ struct _qemuDomainObjPrivate {
qemuDomainPCIAddressSetPtr pciaddrs; qemuDomainPCIAddressSetPtr pciaddrs;
int persistentAddrs; int persistentAddrs;
virBitmapPtr qemuCaps;
}; };
struct qemuDomainWatchdogEvent struct qemuDomainWatchdogEvent

View File

@ -1288,8 +1288,7 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn,
static int static int
qemuProcessInitPasswords(virConnectPtr conn, qemuProcessInitPasswords(virConnectPtr conn,
struct qemud_driver *driver, struct qemud_driver *driver,
virDomainObjPtr vm, virDomainObjPtr vm)
virBitmapPtr qemuCaps)
{ {
int ret = 0; int ret = 0;
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
@ -1311,7 +1310,7 @@ qemuProcessInitPasswords(virConnectPtr conn,
if (ret < 0) if (ret < 0)
goto cleanup; goto cleanup;
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
int i; int i;
for (i = 0 ; i < vm->def->ndisks ; 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 qemuProcessReconnectData *data = opaque;
struct qemud_driver *driver = data->driver; struct qemud_driver *driver = data->driver;
qemuDomainObjPrivatePtr priv; qemuDomainObjPrivatePtr priv;
virBitmapPtr qemuCaps = NULL;
virConnectPtr conn = data->conn; virConnectPtr conn = data->conn;
virDomainObjLock(obj); virDomainObjLock(obj);
@ -1986,13 +1984,16 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa
goto error; goto error;
} }
/* XXX we should be persisting the original flags in the XML /* If upgrading from old libvirtd we won't have found any
* not re-detecting them, since the binary may have changed * caps in the domain status, so re-query them
* since launch time */ */
if (qemuCapsExtractVersionInfo(obj->def->emulator, obj->def->os.arch, if (!priv->qemuCaps &&
qemuCapsExtractVersionInfo(obj->def->emulator, obj->def->os.arch,
NULL, NULL,
&qemuCaps) >= 0 && &priv->qemuCaps) < 0)
qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { goto error;
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
priv->persistentAddrs = 1; priv->persistentAddrs = 1;
if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)) || if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)) ||
@ -2012,11 +2013,9 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa
if (virDomainObjUnref(obj) > 0) if (virDomainObjUnref(obj) > 0)
virDomainObjUnlock(obj); virDomainObjUnlock(obj);
qemuCapsFree(qemuCaps);
return; return;
error: error:
qemuCapsFree(qemuCaps);
if (!virDomainObjIsActive(obj)) { if (!virDomainObjIsActive(obj)) {
if (virDomainObjUnref(obj) > 0) if (virDomainObjUnref(obj) > 0)
virDomainObjUnlock(obj); virDomainObjUnlock(obj);
@ -2058,7 +2057,6 @@ int qemuProcessStart(virConnectPtr conn,
enum virVMOperationType vmop) enum virVMOperationType vmop)
{ {
int ret; int ret;
virBitmapPtr qemuCaps = NULL;
off_t pos = -1; off_t pos = -1;
char ebuf[1024]; char ebuf[1024];
char *pidfile = NULL; char *pidfile = NULL;
@ -2204,9 +2202,11 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup; goto cleanup;
VIR_DEBUG0("Determining emulator version"); VIR_DEBUG0("Determining emulator version");
qemuCapsFree(priv->qemuCaps);
priv->qemuCaps = NULL;
if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch, if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch,
NULL, NULL,
&qemuCaps) < 0) &priv->qemuCaps) < 0)
goto cleanup; goto cleanup;
VIR_DEBUG0("Setting up domain cgroup (if required)"); VIR_DEBUG0("Setting up domain cgroup (if required)");
@ -2223,7 +2223,7 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup; goto cleanup;
#if HAVE_YAJL #if HAVE_YAJL
if (qemuCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON))
priv->monJSON = 1; priv->monJSON = 1;
else else
#endif #endif
@ -2252,7 +2252,7 @@ int qemuProcessStart(virConnectPtr conn,
* we also need to populate the PCi address set cache for later * we also need to populate the PCi address set cache for later
* use in hotplug * use in hotplug
*/ */
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
VIR_DEBUG0("Assigning domain PCI addresses"); VIR_DEBUG0("Assigning domain PCI addresses");
/* Populate cache with current addresses */ /* Populate cache with current addresses */
if (priv->pciaddrs) { if (priv->pciaddrs) {
@ -2274,7 +2274,7 @@ int qemuProcessStart(virConnectPtr conn,
VIR_DEBUG0("Building emulator command line"); VIR_DEBUG0("Building emulator command line");
if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig, if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig,
priv->monJSON != 0, qemuCaps, priv->monJSON != 0, priv->qemuCaps,
migrateFrom, stdin_fd, migrateFrom, stdin_fd,
vm->current_snapshot, vmop))) vm->current_snapshot, vmop)))
goto cleanup; goto cleanup;
@ -2385,12 +2385,12 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup; goto cleanup;
VIR_DEBUG0("Setting any required VM passwords"); VIR_DEBUG0("Setting any required VM passwords");
if (qemuProcessInitPasswords(conn, driver, vm, qemuCaps) < 0) if (qemuProcessInitPasswords(conn, driver, vm) < 0)
goto cleanup; goto cleanup;
/* If we have -device, then addresses are assigned explicitly. /* If we have -device, then addresses are assigned explicitly.
* If not, then we have to detect dynamic ones here */ * 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"); VIR_DEBUG0("Determining domain device PCI addresses");
if (qemuProcessInitPCIAddresses(driver, vm) < 0) if (qemuProcessInitPCIAddresses(driver, vm) < 0)
goto cleanup; goto cleanup;
@ -2421,7 +2421,6 @@ int qemuProcessStart(virConnectPtr conn,
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
goto cleanup; goto cleanup;
qemuCapsFree(qemuCaps);
virCommandFree(cmd); virCommandFree(cmd);
VIR_FORCE_CLOSE(logfile); VIR_FORCE_CLOSE(logfile);
@ -2431,7 +2430,6 @@ cleanup:
/* We jump here if we failed to start the VM for any reason, or /* 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 * if we failed to initialize the now running VM. kill it off and
* pretend we never started it */ * pretend we never started it */
qemuCapsFree(qemuCaps);
virCommandFree(cmd); virCommandFree(cmd);
VIR_FORCE_CLOSE(logfile); VIR_FORCE_CLOSE(logfile);
qemuProcessStop(driver, vm, 0); qemuProcessStop(driver, vm, 0);
@ -2602,6 +2600,8 @@ retry:
vm->state = VIR_DOMAIN_SHUTOFF; vm->state = VIR_DOMAIN_SHUTOFF;
VIR_FREE(priv->vcpupids); VIR_FREE(priv->vcpupids);
priv->nvcpupids = 0; priv->nvcpupids = 0;
qemuCapsFree(priv->qemuCaps);
priv->qemuCaps = NULL;
/* The "release" hook cleans up additional resources */ /* The "release" hook cleans up additional resources */
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {