mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +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
|
||||
|
||||
/* 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;
|
||||
|
@ -141,5 +141,6 @@ int qemuCapsParseHelpStr(const char *qemu,
|
||||
int qemuCapsParseDeviceStr(const char *str,
|
||||
virBitmapPtr qemuCaps);
|
||||
|
||||
VIR_ENUM_DECL(qemuCaps);
|
||||
|
||||
#endif /* __QEMU_CAPABILITIES_H__*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 libvirtd 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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user