[libvirt] [PATCH 3/6] Implement virDomainUpdateDeviceFlags API in all drivers with media change

Daniel P. Berrange berrange at redhat.com
Mon Mar 22 19:05:47 UTC 2010


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     |   21 +++++++-
 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  |  114 ++++++++++++++++++++++++++++++++++++++++++++
 src/xen/xm_internal.c    |    1 +
 src/xen/xs_internal.c    |    1 +
 10 files changed, 270 insertions(+), 5 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index caa6442..b9cfae0 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6819,6 +6819,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,
@@ -9644,7 +9759,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 f398041..b02a633 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -4638,7 +4638,7 @@ 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;
@@ -4836,6 +4836,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) {
@@ -4844,7 +4848,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) {
@@ -7030,7 +7045,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 0c00abc..26eec13 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 1ff3e44..4386693 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -1489,6 +1489,21 @@ xenUnifiedDomainDetachDeviceFlags (virDomainPtr dom, const char *xml,
 }
 
 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)
 {
     GET_PRIVATE(dom->conn);
@@ -1875,7 +1890,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 590777c..3e7c1d0 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 4af3dba..552fbf5 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 ee24bc4..8ff3256 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 85ae2a1..116523c 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -4230,6 +4230,119 @@ cleanup:
 }
 
 /**
+ * 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 "
+                           "persisted 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 "
+                           "persisted config"));
+            return -1;
+        }
+        /* Xen only supports modifying both live and persisted 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"));
+            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
  * @xml: pointer to XML description of device
@@ -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 74bf0b6..ddbd2fe 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 3b241c7..613f97a 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 */
-- 
1.6.6.1




More information about the libvir-list mailing list