mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
qemu: Emit compatible XML when migrating a domain
When we added the default USB controller into domain XML, we efficiently broke migration to older versions of libvirt that didn't support USB controllers at all (0.9.4 and earlier) even for domains that don't use anything that the older libvirt can't provide. We still want to present the default USB controller in any XML seen by a user/app but we can safely remove it from the domain XML used during migration. If we are migrating to a new enough libvirt, it will add the controller XML back, while older libvirt won't be confused with it although it will still tell qemu to create the controller. Similar approach can be used in the future whenever we find out we always enabled some kind of device without properly advertising it in domain XML.
This commit is contained in:
parent
cd603008b1
commit
409b5f5495
@ -1227,11 +1227,14 @@ int
|
|||||||
qemuDomainDefFormatBuf(struct qemud_driver *driver,
|
qemuDomainDefFormatBuf(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
bool compatible,
|
||||||
virBuffer *buf)
|
virBuffer *buf)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
virCPUDefPtr cpu = NULL;
|
virCPUDefPtr cpu = NULL;
|
||||||
virCPUDefPtr def_cpu = def->cpu;
|
virCPUDefPtr def_cpu = def->cpu;
|
||||||
|
virDomainControllerDefPtr *controllers = NULL;
|
||||||
|
int ncontrollers = 0;
|
||||||
|
|
||||||
/* Update guest CPU requirements according to host CPU */
|
/* Update guest CPU requirements according to host CPU */
|
||||||
if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) &&
|
if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) &&
|
||||||
@ -1249,21 +1252,64 @@ qemuDomainDefFormatBuf(struct qemud_driver *driver,
|
|||||||
def->cpu = cpu;
|
def->cpu = cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compatible) {
|
||||||
|
int i;
|
||||||
|
virDomainControllerDefPtr usb = NULL;
|
||||||
|
|
||||||
|
/* If only the default USB controller is present, we can remove it
|
||||||
|
* and make the XML compatible with older versions of libvirt which
|
||||||
|
* didn't support USB controllers in the XML but always added the
|
||||||
|
* default one to qemu anyway.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < def->ncontrollers; i++) {
|
||||||
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
|
||||||
|
if (usb) {
|
||||||
|
usb = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usb = def->controllers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (usb && usb->idx == 0 && usb->model == -1) {
|
||||||
|
VIR_DEBUG("Removing default USB controller from domain '%s'"
|
||||||
|
" for migration compatibility", def->name);
|
||||||
|
controllers = def->controllers;
|
||||||
|
ncontrollers = def->ncontrollers;
|
||||||
|
if (VIR_ALLOC_N(def->controllers, ncontrollers - 1) < 0) {
|
||||||
|
controllers = NULL;
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
def->ncontrollers = 0;
|
||||||
|
for (i = 0; i < ncontrollers; i++) {
|
||||||
|
if (controllers[i] != usb)
|
||||||
|
def->controllers[def->ncontrollers++] = controllers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = virDomainDefFormatInternal(def, flags, buf);
|
ret = virDomainDefFormatInternal(def, flags, buf);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
def->cpu = def_cpu;
|
def->cpu = def_cpu;
|
||||||
virCPUDefFree(cpu);
|
virCPUDefFree(cpu);
|
||||||
|
if (controllers) {
|
||||||
|
VIR_FREE(def->controllers);
|
||||||
|
def->controllers = controllers;
|
||||||
|
def->ncontrollers = ncontrollers;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *qemuDomainDefFormatXML(struct qemud_driver *driver,
|
char *qemuDomainDefFormatXML(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
unsigned int flags)
|
unsigned int flags,
|
||||||
|
bool compatible)
|
||||||
{
|
{
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
if (qemuDomainDefFormatBuf(driver, def, flags, &buf) < 0) {
|
if (qemuDomainDefFormatBuf(driver, def, flags, compatible, &buf) < 0) {
|
||||||
virBufferFreeAndReset(&buf);
|
virBufferFreeAndReset(&buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1279,7 +1325,8 @@ char *qemuDomainDefFormatXML(struct qemud_driver *driver,
|
|||||||
|
|
||||||
char *qemuDomainFormatXML(struct qemud_driver *driver,
|
char *qemuDomainFormatXML(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
unsigned int flags)
|
unsigned int flags,
|
||||||
|
bool compatible)
|
||||||
{
|
{
|
||||||
virDomainDefPtr def;
|
virDomainDefPtr def;
|
||||||
|
|
||||||
@ -1288,20 +1335,21 @@ char *qemuDomainFormatXML(struct qemud_driver *driver,
|
|||||||
else
|
else
|
||||||
def = vm->def;
|
def = vm->def;
|
||||||
|
|
||||||
return qemuDomainDefFormatXML(driver, def, flags);
|
return qemuDomainDefFormatXML(driver, def, flags, compatible);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
qemuDomainDefFormatLive(struct qemud_driver *driver,
|
qemuDomainDefFormatLive(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
bool inactive)
|
bool inactive,
|
||||||
|
bool compatible)
|
||||||
{
|
{
|
||||||
unsigned int flags = QEMU_DOMAIN_FORMAT_LIVE_FLAGS;
|
unsigned int flags = QEMU_DOMAIN_FORMAT_LIVE_FLAGS;
|
||||||
|
|
||||||
if (inactive)
|
if (inactive)
|
||||||
flags |= VIR_DOMAIN_XML_INACTIVE;
|
flags |= VIR_DOMAIN_XML_INACTIVE;
|
||||||
|
|
||||||
return qemuDomainDefFormatXML(driver, def, flags);
|
return qemuDomainDefFormatXML(driver, def, flags, compatible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,19 +252,23 @@ void qemuDomainObjExitRemoteWithDriver(struct qemud_driver *driver,
|
|||||||
int qemuDomainDefFormatBuf(struct qemud_driver *driver,
|
int qemuDomainDefFormatBuf(struct qemud_driver *driver,
|
||||||
virDomainDefPtr vm,
|
virDomainDefPtr vm,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
bool compatible,
|
||||||
virBuffer *buf);
|
virBuffer *buf);
|
||||||
|
|
||||||
char *qemuDomainDefFormatXML(struct qemud_driver *driver,
|
char *qemuDomainDefFormatXML(struct qemud_driver *driver,
|
||||||
virDomainDefPtr vm,
|
virDomainDefPtr vm,
|
||||||
unsigned int flags);
|
unsigned int flags,
|
||||||
|
bool compatible);
|
||||||
|
|
||||||
char *qemuDomainFormatXML(struct qemud_driver *driver,
|
char *qemuDomainFormatXML(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
unsigned int flags);
|
unsigned int flags,
|
||||||
|
bool compatible);
|
||||||
|
|
||||||
char *qemuDomainDefFormatLive(struct qemud_driver *driver,
|
char *qemuDomainDefFormatLive(struct qemud_driver *driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
bool inactive);
|
bool inactive,
|
||||||
|
bool compatible);
|
||||||
|
|
||||||
void qemuDomainObjTaint(struct qemud_driver *driver,
|
void qemuDomainObjTaint(struct qemud_driver *driver,
|
||||||
virDomainObjPtr obj,
|
virDomainObjPtr obj,
|
||||||
|
@ -2630,9 +2630,9 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
|
|||||||
virDomainDefFree(def);
|
virDomainDefFree(def);
|
||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
xml = qemuDomainDefFormatLive(driver, def, true);
|
xml = qemuDomainDefFormatLive(driver, def, true, true);
|
||||||
} else {
|
} else {
|
||||||
xml = qemuDomainDefFormatLive(driver, vm->def, true);
|
xml = qemuDomainDefFormatLive(driver, vm->def, true, true);
|
||||||
}
|
}
|
||||||
if (!xml) {
|
if (!xml) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
@ -4321,7 +4321,7 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = qemuDomainDefFormatXML(driver, def, flags);
|
ret = qemuDomainDefFormatXML(driver, def, flags, false);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virDomainDefFree(def);
|
virDomainDefFree(def);
|
||||||
@ -4363,8 +4363,10 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml = qemuDomainDefFormatXML(driver, def, (VIR_DOMAIN_XML_INACTIVE |
|
xml = qemuDomainDefFormatXML(driver, def,
|
||||||
VIR_DOMAIN_XML_SECURE));
|
VIR_DOMAIN_XML_INACTIVE |
|
||||||
|
VIR_DOMAIN_XML_SECURE,
|
||||||
|
true);
|
||||||
if (!xml)
|
if (!xml)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
len = strlen(xml) + 1;
|
len = strlen(xml) + 1;
|
||||||
@ -4511,7 +4513,7 @@ endjob:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemuDomainFormatXML(driver, vm, flags);
|
ret = qemuDomainFormatXML(driver, vm, flags, false);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (vm)
|
if (vm)
|
||||||
@ -4551,7 +4553,7 @@ static char *qemuDomainXMLFromNative(virConnectPtr conn,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
|
xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE, false);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virDomainDefFree(def);
|
virDomainDefFree(def);
|
||||||
@ -10406,7 +10408,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
|||||||
} else {
|
} else {
|
||||||
/* Easiest way to clone inactive portion of vm->def is via
|
/* Easiest way to clone inactive portion of vm->def is via
|
||||||
* conversion in and back out of xml. */
|
* conversion in and back out of xml. */
|
||||||
if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true)) ||
|
if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)) ||
|
||||||
!(def->dom = virDomainDefParseString(driver->caps, xml,
|
!(def->dom = virDomainDefParseString(driver->caps, xml,
|
||||||
QEMU_EXPECTED_VIRT_TYPES,
|
QEMU_EXPECTED_VIRT_TYPES,
|
||||||
VIR_DOMAIN_XML_INACTIVE)))
|
VIR_DOMAIN_XML_INACTIVE)))
|
||||||
@ -10975,7 +10977,8 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
|
|||||||
if (!(xml = qemuDomainDefFormatXML(driver,
|
if (!(xml = qemuDomainDefFormatXML(driver,
|
||||||
snap->def->dom,
|
snap->def->dom,
|
||||||
VIR_DOMAIN_XML_INACTIVE |
|
VIR_DOMAIN_XML_INACTIVE |
|
||||||
VIR_DOMAIN_XML_SECURE)))
|
VIR_DOMAIN_XML_SECURE,
|
||||||
|
false)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
config = virDomainDefParseString(driver->caps, xml,
|
config = virDomainDefParseString(driver->caps, xml,
|
||||||
QEMU_EXPECTED_VIRT_TYPES,
|
QEMU_EXPECTED_VIRT_TYPES,
|
||||||
|
@ -433,6 +433,7 @@ qemuMigrationCookieXMLFormat(struct qemud_driver *driver,
|
|||||||
mig->persistent,
|
mig->persistent,
|
||||||
VIR_DOMAIN_XML_INACTIVE |
|
VIR_DOMAIN_XML_INACTIVE |
|
||||||
VIR_DOMAIN_XML_SECURE,
|
VIR_DOMAIN_XML_SECURE,
|
||||||
|
true,
|
||||||
buf) < 0)
|
buf) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
virBufferAdjustIndent(buf, -2);
|
virBufferAdjustIndent(buf, -2);
|
||||||
@ -1158,9 +1159,9 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
|
|||||||
if (!virDomainDefCheckABIStability(vm->def, def))
|
if (!virDomainDefCheckABIStability(vm->def, def))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
rv = qemuDomainDefFormatLive(driver, def, false);
|
rv = qemuDomainDefFormatLive(driver, def, false, true);
|
||||||
} else {
|
} else {
|
||||||
rv = qemuDomainDefFormatLive(driver, vm->def, false);
|
rv = qemuDomainDefFormatLive(driver, vm->def, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -1239,7 +1240,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
|
|||||||
int hookret;
|
int hookret;
|
||||||
|
|
||||||
if (!(xml = qemuDomainDefFormatXML(driver, def,
|
if (!(xml = qemuDomainDefFormatXML(driver, def,
|
||||||
VIR_DOMAIN_XML_SECURE)))
|
VIR_DOMAIN_XML_SECURE, false)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
|
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
|
||||||
@ -2187,7 +2188,8 @@ static int doPeer2PeerMigrate2(struct qemud_driver *driver,
|
|||||||
*/
|
*/
|
||||||
if (!(dom_xml = qemuDomainFormatXML(driver, vm,
|
if (!(dom_xml = qemuDomainFormatXML(driver, vm,
|
||||||
VIR_DOMAIN_XML_SECURE |
|
VIR_DOMAIN_XML_SECURE |
|
||||||
VIR_DOMAIN_XML_UPDATE_CPU)))
|
VIR_DOMAIN_XML_UPDATE_CPU,
|
||||||
|
true)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED)
|
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED)
|
||||||
|
@ -3322,7 +3322,7 @@ int qemuProcessStart(virConnectPtr conn,
|
|||||||
|
|
||||||
/* Run an early hook to set-up missing devices */
|
/* Run an early hook to set-up missing devices */
|
||||||
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
||||||
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0);
|
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0, false);
|
||||||
int hookret;
|
int hookret;
|
||||||
|
|
||||||
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
||||||
@ -3516,7 +3516,7 @@ int qemuProcessStart(virConnectPtr conn,
|
|||||||
|
|
||||||
/* now that we know it is about to start call the hook if present */
|
/* now that we know it is about to start call the hook if present */
|
||||||
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
||||||
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0);
|
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0, false);
|
||||||
int hookret;
|
int hookret;
|
||||||
|
|
||||||
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
||||||
@ -3956,7 +3956,7 @@ void qemuProcessStop(struct qemud_driver *driver,
|
|||||||
|
|
||||||
/* now that we know it's stopped call the hook if present */
|
/* now that we know it's stopped call the hook if present */
|
||||||
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
||||||
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0);
|
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0, false);
|
||||||
|
|
||||||
/* we can't stop the operation even if the script raised an error */
|
/* we can't stop the operation even if the script raised an error */
|
||||||
virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
||||||
@ -4049,7 +4049,7 @@ retry:
|
|||||||
|
|
||||||
/* 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)) {
|
||||||
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0);
|
char *xml = qemuDomainDefFormatXML(driver, vm->def, 0, false);
|
||||||
|
|
||||||
/* we can't stop the operation even if the script raised an error */
|
/* we can't stop the operation even if the script raised an error */
|
||||||
virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
|
||||||
|
Loading…
Reference in New Issue
Block a user