diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 3c7c1d3dc6..75ee98b874 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7045,6 +7045,121 @@ static int qemudDomainAttachDeviceFlags(virDomainPtr dom, return qemudDomainAttachDevice(dom, xml); } + +static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, + const char *xml, + unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + virDomainDeviceDefPtr dev = NULL; + unsigned long long qemuCmdFlags; + virCgroupPtr cgroup = NULL; + int ret = -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); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot attach device on inactive domain")); + goto endjob; + } + + dev = virDomainDeviceDefParse(driver->caps, vm->def, xml, + VIR_DOMAIN_XML_INACTIVE); + if (dev == NULL) + goto endjob; + + if (qemudExtractVersionInfo(vm->def->emulator, + NULL, + &qemuCmdFlags) < 0) + goto endjob; + + switch (dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { + if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to find cgroup for %s\n"), + vm->def->name); + goto endjob; + } + if (dev->data.disk->src != NULL && + dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK && + virCgroupAllowDevicePath(cgroup, + dev->data.disk->src) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to allow device %s"), + dev->data.disk->src); + goto endjob; + } + } + + switch (dev->data.disk->device) { + case VIR_DOMAIN_DISK_DEVICE_CDROM: + case VIR_DOMAIN_DISK_DEVICE_FLOPPY: + ret = qemudDomainChangeEjectableMedia(driver, vm, dev->data.disk); + if (ret == 0) + dev->data.disk = NULL; + break; + + + default: + qemuReportError(VIR_ERR_NO_SUPPORT, + _("disk bus '%s' cannot be updated."), + virDomainDiskBusTypeToString(dev->data.disk->bus)); + break; + } + + if (ret != 0 && cgroup) { + virCgroupDenyDevicePath(cgroup, + dev->data.disk->src); + } + break; + + default: + qemuReportError(VIR_ERR_NO_SUPPORT, + _("disk device type '%s' cannot be updated"), + virDomainDiskDeviceTypeToString(dev->data.disk->device)); + break; + } + + if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) + ret = -1; + +endjob: + if (qemuDomainObjEndJob(vm) == 0) + vm = NULL; + +cleanup: + if (cgroup) + virCgroupFree(&cgroup); + + virDomainDeviceDefFree(dev); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + + static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver, virDomainObjPtr vm, virDomainDeviceDefPtr dev, @@ -9914,7 +10029,7 @@ static virDriver qemuDriver = { qemudDomainAttachDeviceFlags, /* domainAttachDeviceFlags */ qemudDomainDetachDevice, /* domainDetachDevice */ qemudDomainDetachDeviceFlags, /* domainDetachDeviceFlags */ - NULL, /* domainUpdateDeviceFlags */ + qemuDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */ qemudDomainGetAutostart, /* domainGetAutostart */ qemudDomainSetAutostart, /* domainSetAutostart */ qemuGetSchedulerType, /* domainGetSchedulerType */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 599ee90cd3..f7a9b9fee3 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -4642,7 +4642,9 @@ cleanup: return ret; } -static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) { +static int vboxDomainAttachDeviceImpl(virDomainPtr dom, + const char *xml, + int mediaChangeOnly ATTRIBUTE_UNUSED) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID *iid = NULL; @@ -4842,6 +4844,10 @@ cleanup: return ret; } +static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) { + return vboxDomainAttachDeviceImpl(dom, xml, 0); +} + static int vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) { @@ -4850,7 +4856,18 @@ static int vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml, return -1; } - return vboxDomainAttachDevice(dom, xml); + return vboxDomainAttachDeviceImpl(dom, xml, 0); +} + +static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, + unsigned int flags) { + if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) { + vboxError(dom->conn, VIR_ERR_OPERATION_INVALID, "%s", + _("cannot modify the persistent configuration of a domain")); + return -1; + } + + return vboxDomainAttachDeviceImpl(dom, xml, 1); } static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) { @@ -7126,7 +7143,7 @@ virDriver NAME(Driver) = { vboxDomainAttachDeviceFlags, /* domainAttachDeviceFlags */ vboxDomainDetachDevice, /* domainDetachDevice */ vboxDomainDetachDeviceFlags, /* domainDetachDeviceFlags */ - NULL, /* domainUpdateDeviceFlags */ + vboxDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */ diff --git a/src/xen/proxy_internal.c b/src/xen/proxy_internal.c index 0c00abca95..26eec13abb 100644 --- a/src/xen/proxy_internal.c +++ b/src/xen/proxy_internal.c @@ -78,6 +78,7 @@ struct xenUnifiedDriver xenProxyDriver = { NULL, /* domainUndefine */ NULL, /* domainAttachDeviceFlags */ NULL, /* domainDetachDeviceFlags */ + NULL, /* domainUpdateDeviceFlags */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 0f0912cc6d..ebdc6009e6 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1488,6 +1488,21 @@ xenUnifiedDomainDetachDeviceFlags (virDomainPtr dom, const char *xml, return -1; } +static int +xenUnifiedDomainUpdateDeviceFlags (virDomainPtr dom, const char *xml, + unsigned int flags) +{ + GET_PRIVATE(dom->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && drivers[i]->domainUpdateDeviceFlags && + drivers[i]->domainUpdateDeviceFlags(dom, xml, flags) == 0) + return 0; + + return -1; +} + static int xenUnifiedDomainGetAutostart (virDomainPtr dom, int *autostart) { @@ -1930,7 +1945,7 @@ static virDriver xenUnifiedDriver = { xenUnifiedDomainAttachDeviceFlags, /* domainAttachDeviceFlags */ xenUnifiedDomainDetachDevice, /* domainDetachDevice */ xenUnifiedDomainDetachDeviceFlags, /* domainDetachDeviceFlags */ - NULL, /* domainUpdateDeviceFlags */ + xenUnifiedDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */ xenUnifiedDomainGetAutostart, /* domainGetAutostart */ xenUnifiedDomainSetAutostart, /* domainSetAutostart */ xenUnifiedDomainGetSchedulerType, /* domainGetSchedulerType */ diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h index 590777ce67..3e7c1d0bff 100644 --- a/src/xen/xen_driver.h +++ b/src/xen/xen_driver.h @@ -95,6 +95,7 @@ struct xenUnifiedDriver { virDrvDomainUndefine domainUndefine; virDrvDomainAttachDeviceFlags domainAttachDeviceFlags; virDrvDomainDetachDeviceFlags domainDetachDeviceFlags; + virDrvDomainUpdateDeviceFlags domainUpdateDeviceFlags; virDrvDomainGetAutostart domainGetAutostart; virDrvDomainSetAutostart domainSetAutostart; virDrvDomainGetSchedulerType domainGetSchedulerType; diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 4af3dba3a1..552fbf51d6 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -795,6 +795,7 @@ struct xenUnifiedDriver xenHypervisorDriver = { NULL, /* domainUndefine */ NULL, /* domainAttachDeviceFlags */ NULL, /* domainDetachDeviceFlags */ + NULL, /* domainUpdateDeviceFlags */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ xenHypervisorGetSchedulerType, /* domainGetSchedulerType */ diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index ee24bc4aee..8ff32563b4 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -82,6 +82,7 @@ struct xenUnifiedDriver xenInotifyDriver = { NULL, /* domainUndefine */ NULL, /* domainAttachDeviceFlags */ NULL, /* domainDetachDeviceFlags */ + NULL, /* domainUpdateDeviceFlags */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */ diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 85ae2a173f..87c26e59a9 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -4128,7 +4128,7 @@ xenDaemonAttachDeviceFlags(virDomainPtr domain, const char *xml, if (priv->xendConfigVersion < 3) { virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", _("Xend version does not support modifying " - "persisted config")); + "persistent config")); return -1; } /* Cannot modify live config if domain is inactive */ @@ -4144,17 +4144,17 @@ xenDaemonAttachDeviceFlags(virDomainPtr domain, const char *xml, flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) { virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", _("Xend version does not support modifying " - "persisted config")); + "persistent config")); return -1; } - /* Xen only supports modifying both live and persisted config if + /* Xen only supports modifying both live and persistent config if * xendConfigVersion >= 3 */ if (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE | VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) { virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", _("Xend only supports modifying both live and " - "persisted config")); + "persistent config")); return -1; } } @@ -4229,6 +4229,119 @@ cleanup: return ret; } +/** + * xenDaemonUpdateDeviceFlags: + * @domain: pointer to domain object + * @xml: pointer to XML description of device + * @flags: an OR'ed set of virDomainDeviceModifyFlags + * + * Create a virtual device attachment to backend. + * XML description is translated into S-expression. + * + * Returns 0 in case of success, -1 in case of failure. + */ +static int +xenDaemonUpdateDeviceFlags(virDomainPtr domain, const char *xml, + unsigned int flags) +{ + xenUnifiedPrivatePtr priv; + char *sexpr = NULL; + int ret = -1; + virDomainDeviceDefPtr dev = NULL; + virDomainDefPtr def = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + char class[8], ref[80]; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return -1; + } + + priv = (xenUnifiedPrivatePtr) domain->conn->privateData; + + if (domain->id < 0) { + /* If xendConfigVersion < 3 only live config can be changed */ + if (priv->xendConfigVersion < 3) { + virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", + _("Xend version does not support modifying " + "persistent config")); + return -1; + } + /* Cannot modify live config if domain is inactive */ + if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) { + virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", + _("Cannot modify live config if domain is inactive")); + return -1; + } + } else { + /* Only live config can be changed if xendConfigVersion < 3 */ + if (priv->xendConfigVersion < 3 && + (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT || + flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) { + virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", + _("Xend version does not support modifying " + "persistent config")); + return -1; + } + /* Xen only supports modifying both live and persistent config if + * xendConfigVersion >= 3 + */ + if (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE | + VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) { + virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", + _("Xend only supports modifying both live and " + "persistent config")); + return -1; + } + } + + if (!(def = xenDaemonDomainFetch(domain->conn, + domain->id, + domain->name, + NULL))) + goto cleanup; + + if (!(dev = virDomainDeviceDefParse(priv->caps, + def, xml, VIR_DOMAIN_XML_INACTIVE))) + goto cleanup; + + + switch (dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + if (xenDaemonFormatSxprDisk(domain->conn, + dev->data.disk, + &buf, + STREQ(def->os.type, "hvm") ? 1 : 0, + priv->xendConfigVersion, 1) < 0) + goto cleanup; + break; + + default: + virXendError(domain->conn, VIR_ERR_NO_SUPPORT, "%s", + _("unsupported device type")); + goto cleanup; + } + + sexpr = virBufferContentAndReset(&buf); + + if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) { + virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", + _("requested device does not exist")); + goto cleanup; + } else { + /* device exists, attempt to modify it */ + ret = xend_op(domain->conn, domain->name, "op", "device_configure", + "config", sexpr, "dev", ref, NULL); + } + +cleanup: + VIR_FREE(sexpr); + virDomainDefFree(def); + virDomainDeviceDefFree(dev); + return ret; +} + /** * xenDaemonDetachDeviceFlags: * @domain: pointer to domain object @@ -4264,7 +4377,7 @@ xenDaemonDetachDeviceFlags(virDomainPtr domain, const char *xml, if (priv->xendConfigVersion < 3) { virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", _("Xend version does not support modifying " - "persisted config")); + "persistent config")); return -1; } /* Cannot modify live config if domain is inactive */ @@ -4280,17 +4393,17 @@ xenDaemonDetachDeviceFlags(virDomainPtr domain, const char *xml, flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) { virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", _("Xend version does not support modifying " - "persisted config")); + "persistent config")); return -1; } - /* Xen only supports modifying both live and persisted config if + /* Xen only supports modifying both live and persistent config if * xendConfigVersion >= 3 */ if (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE | VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) { virXendError(domain->conn, VIR_ERR_OPERATION_INVALID, "%s", _("Xend only supports modifying both live and " - "persisted config")); + "persistent config")); return -1; } } @@ -5224,6 +5337,7 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonDomainUndefine, /* domainUndefine */ xenDaemonAttachDeviceFlags, /* domainAttachDeviceFlags */ xenDaemonDetachDeviceFlags, /* domainDetachDeviceFlags */ + xenDaemonUpdateDeviceFlags, /* domainUpdateDeviceFlags */ xenDaemonDomainGetAutostart, /* domainGetAutostart */ xenDaemonDomainSetAutostart, /* domainSetAutostart */ xenDaemonGetSchedulerType, /* domainGetSchedulerType */ diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 74bf0b6d5b..ddbd2fe241 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -113,6 +113,7 @@ struct xenUnifiedDriver xenXMDriver = { xenXMDomainUndefine, /* domainUndefine */ xenXMDomainAttachDeviceFlags, /* domainAttachDeviceFlags */ xenXMDomainDetachDeviceFlags, /* domainDetachDeviceFlags */ + NULL, /* domainUpdateDeviceFlags */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */ diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index 3b241c7f41..613f97a7da 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -78,6 +78,7 @@ struct xenUnifiedDriver xenStoreDriver = { NULL, /* domainUndefine */ NULL, /* domainAttachDeviceFlags */ NULL, /* domainDetachDeviceFlags */ + NULL, /* domainUpdateDeviceFlags */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */