mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
libvirt/qemu - support persistent modification of devices
This patch adds functions for modify domain's persistent definition. To do error recovery in easy way, we use a copy of vmdef and update it. The whole sequence will be: make a copy of domain definition. if (flags & MODIFY_CONFIG) update copied domain definition if (flags & MODIF_LIVE) do hotplug. if (no error) save copied one to the file and update cached definition. else discard copied definition. This patch is mixuture of Eric Blake's work and mine. From: Eric Blake <eblake@redhat.com> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> (virDomainObjCopyPersistentDef): make a copy of persistent vm definition (qemuDomainAttach/Detach/UpdateDeviceConfig) : callbacks. now empty (qemuDomainModifyDeviceFlags): add support for MODIFY_CONFIG and MODIFY_CURRENT
This commit is contained in:
parent
8a6e30f124
commit
da1eba6bc8
@ -9510,3 +9510,22 @@ cleanup:
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virDomainDefPtr
|
||||||
|
virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainObjPtr dom)
|
||||||
|
{
|
||||||
|
char *xml;
|
||||||
|
virDomainDefPtr cur, ret;
|
||||||
|
|
||||||
|
cur = virDomainObjGetPersistentDef(caps, dom);
|
||||||
|
|
||||||
|
xml = virDomainDefFormat(cur, VIR_DOMAIN_XML_WRITE_FLAGS);
|
||||||
|
if (!xml)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = virDomainDefParseString(caps, xml, VIR_DOMAIN_XML_READ_FLAGS);
|
||||||
|
|
||||||
|
VIR_FREE(xml);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -1288,6 +1288,9 @@ int virDomainObjSetDefTransient(virCapsPtr caps,
|
|||||||
virDomainDefPtr
|
virDomainDefPtr
|
||||||
virDomainObjGetPersistentDef(virCapsPtr caps,
|
virDomainObjGetPersistentDef(virCapsPtr caps,
|
||||||
virDomainObjPtr domain);
|
virDomainObjPtr domain);
|
||||||
|
virDomainDefPtr
|
||||||
|
virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainObjPtr dom);
|
||||||
|
|
||||||
void virDomainRemoveInactive(virDomainObjListPtr doms,
|
void virDomainRemoveInactive(virDomainObjListPtr doms,
|
||||||
virDomainObjPtr dom);
|
virDomainObjPtr dom);
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ virDomainMemballoonModelTypeToString;
|
|||||||
virDomainNetDefFree;
|
virDomainNetDefFree;
|
||||||
virDomainNetTypeToString;
|
virDomainNetTypeToString;
|
||||||
virDomainObjAssignDef;
|
virDomainObjAssignDef;
|
||||||
virDomainObjSetDefTransient;
|
virDomainObjCopyPersistentDef;
|
||||||
virDomainObjGetPersistentDef;
|
virDomainObjGetPersistentDef;
|
||||||
virDomainObjIsDuplicate;
|
virDomainObjIsDuplicate;
|
||||||
virDomainObjListDeinit;
|
virDomainObjListDeinit;
|
||||||
@ -297,6 +297,7 @@ virDomainObjListInit;
|
|||||||
virDomainObjListNumOfDomains;
|
virDomainObjListNumOfDomains;
|
||||||
virDomainObjLock;
|
virDomainObjLock;
|
||||||
virDomainObjRef;
|
virDomainObjRef;
|
||||||
|
virDomainObjSetDefTransient;
|
||||||
virDomainObjUnlock;
|
virDomainObjUnlock;
|
||||||
virDomainObjUnref;
|
virDomainObjUnref;
|
||||||
virDomainRemoveInactive;
|
virDomainRemoveInactive;
|
||||||
|
@ -4076,6 +4076,46 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
|
||||||
|
virDomainDeviceDefPtr dev)
|
||||||
|
{
|
||||||
|
switch (dev->type) {
|
||||||
|
default:
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("persistent attach of device is not supported"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
|
||||||
|
virDomainDeviceDefPtr dev)
|
||||||
|
{
|
||||||
|
switch (dev->type) {
|
||||||
|
default:
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("persistent detach of device is not supported"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
|
||||||
|
virDomainDeviceDefPtr dev)
|
||||||
|
{
|
||||||
|
switch (dev->type) {
|
||||||
|
default:
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("persistent update of device is not supported"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Actions for qemuDomainModifyDeviceFlags */
|
/* Actions for qemuDomainModifyDeviceFlags */
|
||||||
enum {
|
enum {
|
||||||
QEMU_DEVICE_ATTACH,
|
QEMU_DEVICE_ATTACH,
|
||||||
@ -4091,6 +4131,7 @@ qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
|
|||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virBitmapPtr qemuCaps = NULL;
|
virBitmapPtr qemuCaps = NULL;
|
||||||
virDomainObjPtr vm = NULL;
|
virDomainObjPtr vm = NULL;
|
||||||
|
virDomainDefPtr vmdef = NULL;
|
||||||
virDomainDeviceDefPtr dev = NULL;
|
virDomainDeviceDefPtr dev = NULL;
|
||||||
bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
|
bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -4100,12 +4141,6 @@ qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
|
|||||||
(action == QEMU_DEVICE_UPDATE ?
|
(action == QEMU_DEVICE_UPDATE ?
|
||||||
VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);
|
VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);
|
||||||
|
|
||||||
if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
|
|
||||||
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
|
||||||
"%s", _("cannot modify the persistent configuration of a domain"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
if (!vm) {
|
if (!vm) {
|
||||||
@ -4119,12 +4154,27 @@ qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
|
|||||||
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (!virDomainObjIsActive(vm)) {
|
if (virDomainObjIsActive(vm)) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
|
||||||
"%s", _("cannot attach device on inactive domain"));
|
flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
|
||||||
goto endjob;
|
} else {
|
||||||
|
if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
|
||||||
|
flags |= VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
|
||||||
|
/* check consistency between flags and the vm state */
|
||||||
|
if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s",
|
||||||
|
_("cannot do live update a device on "
|
||||||
|
"inactive domain"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) && !vm->persistent) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s", _("cannot modify device on transient domain"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
|
dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
|
||||||
VIR_DOMAIN_XML_INACTIVE);
|
VIR_DOMAIN_XML_INACTIVE);
|
||||||
if (dev == NULL)
|
if (dev == NULL)
|
||||||
@ -4135,35 +4185,68 @@ qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
|
|||||||
&qemuCaps) < 0)
|
&qemuCaps) < 0)
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
switch (action) {
|
if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
|
||||||
case QEMU_DEVICE_ATTACH:
|
/* Make a copy for updated domain. */
|
||||||
ret = qemuDomainAttachDeviceLive(vm, dev, dom, qemuCaps);
|
vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
|
||||||
break;
|
if (!vmdef)
|
||||||
case QEMU_DEVICE_DETACH:
|
goto endjob;
|
||||||
ret = qemuDomainDetachDeviceLive(vm, dev, dom, qemuCaps);
|
switch (action) {
|
||||||
break;
|
case QEMU_DEVICE_ATTACH:
|
||||||
case QEMU_DEVICE_UPDATE:
|
ret = qemuDomainAttachDeviceConfig(vmdef, dev);
|
||||||
ret = qemuDomainUpdateDeviceLive(vm, dev, dom, qemuCaps, force);
|
break;
|
||||||
break;
|
case QEMU_DEVICE_DETACH:
|
||||||
default:
|
ret = qemuDomainDetachDeviceConfig(vmdef, dev);
|
||||||
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
break;
|
||||||
_("unknown domain modify action %d"), action);
|
case QEMU_DEVICE_UPDATE:
|
||||||
break;
|
ret = qemuDomainUpdateDeviceConfig(vmdef, dev);
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unknown domain modify action %d"), action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
/*
|
if (!ret && (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
|
||||||
* update domain status forcibly because the domain status may be changed
|
switch (action) {
|
||||||
* even if we attach the device failed. For example, a new controller may
|
case QEMU_DEVICE_ATTACH:
|
||||||
* be created.
|
ret = qemuDomainAttachDeviceLive(vm, dev, dom, qemuCaps);
|
||||||
*/
|
break;
|
||||||
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
|
case QEMU_DEVICE_DETACH:
|
||||||
ret = -1;
|
ret = qemuDomainDetachDeviceLive(vm, dev, dom, qemuCaps);
|
||||||
|
break;
|
||||||
|
case QEMU_DEVICE_UPDATE:
|
||||||
|
ret = qemuDomainUpdateDeviceLive(vm, dev, dom, qemuCaps, force);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unknown domain modify action %d"), action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* update domain status forcibly because the domain status may be
|
||||||
|
* changed even if we attach the device failed. For example, a
|
||||||
|
* For example, a new controller may be created.
|
||||||
|
*/
|
||||||
|
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
/* Finally, if no error until here, we can save config. */
|
||||||
|
if (!ret && (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
|
||||||
|
ret = virDomainSaveConfig(driver->configDir, vmdef);
|
||||||
|
if (!ret) {
|
||||||
|
virDomainObjAssignDef(vm, vmdef, false);
|
||||||
|
vmdef = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
if (qemuDomainObjEndJob(vm) == 0)
|
if (qemuDomainObjEndJob(vm) == 0)
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
virDomainDefFree(vmdef);
|
||||||
virDomainDeviceDefFree(dev);
|
virDomainDeviceDefFree(dev);
|
||||||
if (vm)
|
if (vm)
|
||||||
virDomainObjUnlock(vm);
|
virDomainObjUnlock(vm);
|
||||||
|
Loading…
Reference in New Issue
Block a user