]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Implement virDomainUpdateDeviceFlags API in all drivers with media change
authorDaniel P. Berrange <berrange@redhat.com>
Mon, 22 Mar 2010 13:13:53 +0000 (13:13 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 26 Mar 2010 14:17:34 +0000 (14:17 +0000)
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
src/vbox/vbox_tmpl.c
src/xen/proxy_internal.c
src/xen/xen_driver.c
src/xen/xen_driver.h
src/xen/xen_hypervisor.c
src/xen/xen_inotify.c
src/xen/xend_internal.c
src/xen/xm_internal.c
src/xen/xs_internal.c

index 3c7c1d3dc60968930a693825b00037759cb50645..75ee98b8747a4f81911a47b75b92462ed9892f6c 100644 (file)
@@ -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 */
index 599ee90cd39d2c35d1554361ffddc2a5a2449948..f7a9b9fee30886a4922503e07be2cee1e92dd6a1 100644 (file)
@@ -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 */
index 0c00abca9533d180925f5f4f98657210e39f2115..26eec13abb356733e4f318b3e64c46ec8a7a81d2 100644 (file)
@@ -78,6 +78,7 @@ struct xenUnifiedDriver xenProxyDriver = {
     NULL, /* domainUndefine */
     NULL, /* domainAttachDeviceFlags */
     NULL, /* domainDetachDeviceFlags */
+    NULL, /* domainUpdateDeviceFlags */
     NULL, /* domainGetAutostart */
     NULL, /* domainSetAutostart */
     NULL, /* domainGetSchedulerType */
index 0f0912cc6dbbe40d7ed822734ed617e64ff6aad1..ebdc6009e66de61cf00f0d1a12670bc3b2508f8b 100644 (file)
@@ -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 */
index 590777ce6765468463cc23fe00d2a1fbc9e8e335..3e7c1d0bff4edb3af80e4ecea263592926bfd7de 100644 (file)
@@ -95,6 +95,7 @@ struct xenUnifiedDriver {
         virDrvDomainUndefine            domainUndefine;
         virDrvDomainAttachDeviceFlags  domainAttachDeviceFlags;
         virDrvDomainDetachDeviceFlags  domainDetachDeviceFlags;
+        virDrvDomainUpdateDeviceFlags  domainUpdateDeviceFlags;
         virDrvDomainGetAutostart       domainGetAutostart;
         virDrvDomainSetAutostart       domainSetAutostart;
         virDrvDomainGetSchedulerType   domainGetSchedulerType;
index 4af3dba3a104d8b2f62e1f8446ff5dda627a7f17..552fbf51d673e0c598ec5d00b713db18ae88f97a 100644 (file)
@@ -795,6 +795,7 @@ struct xenUnifiedDriver xenHypervisorDriver = {
     NULL, /* domainUndefine */
     NULL, /* domainAttachDeviceFlags */
     NULL, /* domainDetachDeviceFlags */
+    NULL, /* domainUpdateDeviceFlags */
     NULL, /* domainGetAutostart */
     NULL, /* domainSetAutostart */
     xenHypervisorGetSchedulerType, /* domainGetSchedulerType */
index ee24bc4aeed9f4f6d95ab08d4543da167d06ca68..8ff32563b4c045fba51ab735a9f93f3c8ae49989 100644 (file)
@@ -82,6 +82,7 @@ struct xenUnifiedDriver xenInotifyDriver = {
     NULL, /* domainUndefine */
     NULL, /* domainAttachDeviceFlags */
     NULL, /* domainDetachDeviceFlags */
+    NULL, /* domainUpdateDeviceFlags */
     NULL, /* domainGetAutostart */
     NULL, /* domainSetAutostart */
     NULL, /* domainGetSchedulerType */
index 85ae2a173fdc60716f91ea044f9c2e4e333be2eb..87c26e59a94233c17104d4dcfef68af8bc844556 100644 (file)
@@ -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 */
index 74bf0b6d5bd5f79d6e290c92740be45840f5d15e..ddbd2fe241248a96854cd896e6ee791823ecc36f 100644 (file)
@@ -113,6 +113,7 @@ struct xenUnifiedDriver xenXMDriver = {
     xenXMDomainUndefine, /* domainUndefine */
     xenXMDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
     xenXMDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
+    NULL, /* domainUpdateDeviceFlags */
     NULL, /* domainGetAutostart */
     NULL, /* domainSetAutostart */
     NULL, /* domainGetSchedulerType */
index 3b241c7f41a5d4bb2f9b264947174b6a67711709..613f97a7da598d02d69ef2b6d8787e594e072ba1 100644 (file)
@@ -78,6 +78,7 @@ struct xenUnifiedDriver xenStoreDriver = {
     NULL, /* domainUndefine */
     NULL, /* domainAttachDeviceFlags */
     NULL, /* domainDetachDeviceFlags */
+    NULL, /* domainUpdateDeviceFlags */
     NULL, /* domainGetAutostart */
     NULL, /* domainSetAutostart */
     NULL, /* domainGetSchedulerType */