From 6bb4986b0b9e9cf209a69b317be52a7093a70eee Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 22 Mar 2010 13:13:53 +0000 Subject: [PATCH] Implement virDomainUpdateDeviceFlags API in all drivers with media change To allow the new virDomainUpdateDeviceFlags() API to be universally used with all drivers, this patch adds an impl to all the current drivers which support CDROM or Floppy disk media change via the current virDomainAttachDeviceFlags API * src/qemu/qemu_driver.c, src/vbox/vbox_tmpl.c, src/xen/proxy_internal.c, src/xen/xen_driver.c, src/xen/xend_internal.c: Implement media change via the virDomainUpdateDeviceFlags API * src/xen/xen_driver.h, src/xen/xen_hypervisor.c, src/xen/xen_inotify.c, src/xen/xm_internal.c, src/xen/xs_internal.c: Stubs for Xen driver entry points --- src/qemu/qemu_driver.c | 117 ++++++++++++++++++++++++++++++++++- src/vbox/vbox_tmpl.c | 23 ++++++- src/xen/proxy_internal.c | 1 + src/xen/xen_driver.c | 17 ++++- src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 130 ++++++++++++++++++++++++++++++++++++--- src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + 10 files changed, 280 insertions(+), 13 deletions(-) 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 */ -- GitLab