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:
parent
9b889aacef
commit
43c01d3838
@ -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;
|
||||||
|
@ -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__*/
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user