[libvirt] [PATCH 3/3] Add disk attach/detach support to libxl driver

Markus Groß gross at univention.de
Wed May 18 08:06:38 UTC 2011


Based on the device attach/detach code from the QEMU driver.
---
 src/libxl/libxl_driver.c |  519 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 519 insertions(+), 0 deletions(-)

diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index a14ace1..a056be9 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -2219,6 +2219,520 @@ libxlDomainUndefine(virDomainPtr dom)
     return ret;
 }
 
+static int
+libxlDomainChangeEjectableMedia(libxlDomainObjPrivatePtr priv,
+                                virDomainObjPtr vm, virDomainDiskDefPtr disk)
+{
+    virDomainDiskDefPtr origdisk = NULL;
+    libxl_device_disk x_disk;
+    int i;
+    int ret = -1;
+
+    for (i = 0 ; i < vm->def->ndisks ; i++) {
+        if (vm->def->disks[i]->bus == disk->bus &&
+            STREQ(vm->def->disks[i]->dst, disk->dst)) {
+            origdisk = vm->def->disks[i];
+            break;
+        }
+    }
+
+    if (!origdisk) {
+        libxlError(VIR_ERR_INTERNAL_ERROR,
+                   _("No device with bus '%s' and target '%s'"),
+                   virDomainDiskBusTypeToString(disk->bus), disk->dst);
+        goto cleanup;
+    }
+
+    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
+        libxlError(VIR_ERR_INTERNAL_ERROR,
+                   _("Removable media not supported for %s device"),
+                   virDomainDiskDeviceTypeToString(disk->device));
+        return -1;
+    }
+
+    if (libxlMakeDisk(disk, &x_disk) < 0)
+        goto cleanup;
+
+    if ((ret = libxl_cdrom_insert(&priv->ctx, vm->def->id, &x_disk)) < 0) {
+        libxlError(VIR_ERR_INTERNAL_ERROR,
+                   _("libxenlight failed to change media for disk '%s'"),
+                   disk->dst);
+        goto cleanup;
+    }
+
+    VIR_FREE(origdisk->src);
+    origdisk->src = disk->src;
+    disk->src = NULL;
+    origdisk->type = disk->type;
+
+
+    virDomainDiskDefFree(disk);
+
+    ret = 0;
+
+cleanup:
+    return ret;
+}
+
+static int
+libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
+                                virDomainObjPtr vm, virDomainDeviceDefPtr dev)
+{
+    virDomainDiskDefPtr l_disk = dev->data.disk;
+    libxl_device_disk x_disk;
+    int ret = -1;
+
+    switch (l_disk->device)  {
+        case VIR_DOMAIN_DISK_DEVICE_CDROM:
+            ret = libxlDomainChangeEjectableMedia(priv, vm, l_disk);
+            break;
+        case VIR_DOMAIN_DISK_DEVICE_DISK:
+            if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
+                if (virDomainDiskIndexByName(vm->def, l_disk->dst) >= 0) {
+                    libxlError(VIR_ERR_OPERATION_FAILED,
+                            _("target %s already exists"), l_disk->dst);
+                    goto cleanup;
+                }
+
+                if (!l_disk->src) {
+                    libxlError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("disk source path is missing"));
+                    goto cleanup;
+                }
+
+                if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+
+                if (libxlMakeDisk(l_disk, &x_disk) < 0)
+                    goto cleanup;
+
+                if ((ret = libxl_device_disk_add(&priv->ctx, vm->def->id,
+                                                &x_disk)) < 0) {
+                    libxlError(VIR_ERR_INTERNAL_ERROR,
+                            _("libxenlight failed to attach disk '%s'"),
+                            l_disk->dst);
+                    goto cleanup;
+                }
+
+                virDomainDiskInsertPreAlloced(vm->def, l_disk);
+
+            } else {
+                libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("disk bus '%s' cannot be hotplugged."),
+                        virDomainDiskBusTypeToString(l_disk->bus));
+            }
+            break;
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                    _("disk device type '%s' cannot be hotplugged"),
+                    virDomainDiskDeviceTypeToString(l_disk->device));
+            break;
+    }
+
+cleanup:
+    return ret;
+}
+
+static int
+libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
+                                virDomainObjPtr vm, virDomainDeviceDefPtr dev)
+{
+    virDomainDiskDefPtr l_disk = NULL;
+    libxl_device_disk x_disk;
+    int i;
+    int wait_secs = 2;
+    int ret = -1;
+
+    switch (dev->data.disk->device)  {
+        case VIR_DOMAIN_DISK_DEVICE_DISK:
+            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
+
+                if ((i = virDomainDiskIndexByName(vm->def,
+                                                  dev->data.disk->dst)) < 0) {
+                    libxlError(VIR_ERR_OPERATION_FAILED,
+                               _("disk %s not found"), dev->data.disk->dst);
+                    goto cleanup;
+                }
+
+                l_disk = vm->def->disks[i];
+
+                if (libxlMakeDisk(l_disk, &x_disk) < 0)
+                    goto cleanup;
+
+                if ((ret = libxl_device_disk_del(&priv->ctx, &x_disk,
+                                                 wait_secs)) < 0) {
+                    libxlError(VIR_ERR_INTERNAL_ERROR,
+                               _("libxenlight failed to detach disk '%s'"),
+                               l_disk->dst);
+                    goto cleanup;
+                }
+
+                virDomainDiskRemove(vm->def, i);
+                virDomainDiskDefFree(l_disk);
+
+            } else {
+                libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("disk bus '%s' cannot be hot unplugged."),
+                        virDomainDiskBusTypeToString(l_disk->bus));
+            }
+            break;
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("device type '%s' cannot hot unplugged"),
+                       virDomainDiskDeviceTypeToString(dev->data.disk->device));
+            break;
+    }
+
+cleanup:
+    return ret;
+}
+
+static int
+libxlDomainAttachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
+                            virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_DEVICE_DISK:
+            ret = libxlDomainAttachDeviceDiskLive(priv, vm, dev);
+            if (!ret)
+                dev->data.disk = NULL;
+            break;
+
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("device type '%s' cannot be attached"),
+                       virDomainDeviceTypeToString(dev->type));
+            break;
+    }
+
+    return ret;
+}
+
+static int
+libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
+{
+    virDomainDiskDefPtr disk;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_DEVICE_DISK:
+            disk = dev->data.disk;
+            if (virDomainDiskIndexByName(vmdef, disk->dst) >= 0) {
+                libxlError(VIR_ERR_INVALID_ARG,
+                        _("target %s already exists."), disk->dst);
+                return -1;
+            }
+            if (virDomainDiskInsert(vmdef, disk)) {
+                virReportOOMError();
+                return -1;
+            }
+            /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
+            dev->data.disk = NULL;
+            break;
+
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("persistent attach of device is not supported"));
+            return -1;
+    }
+    return 0;
+}
+
+static int
+libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
+                            virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_DEVICE_DISK:
+            ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev);
+            break;
+
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("device type '%s' cannot be detached"),
+                       virDomainDeviceTypeToString(dev->type));
+            break;
+    }
+
+    return ret;
+}
+
+static int
+libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
+{
+    virDomainDiskDefPtr disk;
+    int ret = -1;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_DEVICE_DISK:
+            disk = dev->data.disk;
+            if (virDomainDiskRemoveByName(vmdef, disk->dst)) {
+                libxlError(VIR_ERR_INVALID_ARG,
+                            _("no target device %s"), disk->dst);
+                break;
+            }
+            ret = 0;
+            break;
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("persistent detach of device is not supported"));
+            break;
+    }
+
+    return ret;
+}
+
+static int
+libxlDomainUpdateDeviceLive(libxlDomainObjPrivatePtr priv,
+                            virDomainObjPtr vm, virDomainDeviceDefPtr dev)
+{
+    virDomainDiskDefPtr disk;
+    int ret = -1;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_DEVICE_DISK:
+            disk = dev->data.disk;
+            switch (disk->device) {
+                case VIR_DOMAIN_DISK_DEVICE_CDROM:
+                    ret = libxlDomainChangeEjectableMedia(priv, vm, disk);
+                    if (ret == 0)
+                        dev->data.disk = NULL;
+                    break;
+                default:
+                    libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("disk bus '%s' cannot be updated."),
+                               virDomainDiskBusTypeToString(disk->bus));
+                    break;
+            }
+            break;
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("device type '%s' cannot be updated"),
+                       virDomainDeviceTypeToString(dev->type));
+            break;
+    }
+
+    return ret;
+}
+
+static int
+libxlDomainUpdateDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
+{
+    virDomainDiskDefPtr orig;
+    virDomainDiskDefPtr disk;
+    int i;
+    int ret = -1;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_DEVICE_DISK:
+            disk = dev->data.disk;
+            if ((i = virDomainDiskIndexByName(vmdef, disk->dst)) < 0) {
+                libxlError(VIR_ERR_INVALID_ARG,
+                           _("target %s doesn't exists."), disk->dst);
+                goto cleanup;
+            }
+            orig = vmdef->disks[i];
+            if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM)) {
+                libxlError(VIR_ERR_INVALID_ARG,
+                           _("this disk doesn't support update"));
+                goto cleanup;
+            }
+
+            VIR_FREE(orig->src);
+            orig->src = disk->src;
+            orig->type = disk->type;
+            if (disk->driverName) {
+                VIR_FREE(orig->driverName);
+                orig->driverName = disk->driverName;
+                disk->driverName = NULL;
+            }
+            if (disk->driverType) {
+                VIR_FREE(orig->driverType);
+                orig->driverType = disk->driverType;
+                disk->driverType = NULL;
+            }
+            disk->src = NULL;
+            break;
+        default:
+            libxlError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("persistent update of device is not supported"));
+            goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    return ret;
+}
+
+/* Actions for libxlDomainModifyDeviceFlags */
+enum {
+    LIBXL_DEVICE_ATTACH,
+    LIBXL_DEVICE_DETACH,
+    LIBXL_DEVICE_UPDATE,
+};
+
+static int
+libxlDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
+                             unsigned int flags, int action)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virDomainDefPtr vmdef = NULL;
+    virDomainDeviceDefPtr dev = NULL;
+    libxlDomainObjPrivatePtr priv;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
+                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);
+
+    libxlDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+    if (!vm) {
+        libxlError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid"));
+        goto cleanup;
+    }
+
+    if (virDomainObjIsActive(vm)) {
+        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
+            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
+    } 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) {
+            libxlError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("Domain is not running"));
+            goto cleanup;
+        }
+    }
+
+    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) && !vm->persistent) {
+         libxlError(VIR_ERR_OPERATION_INVALID,
+                    "%s", _("cannot modify device on transient domain"));
+         goto cleanup;
+    }
+
+    if (!(dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
+                                  VIR_DOMAIN_XML_INACTIVE)))
+        goto cleanup;
+
+    priv = vm->privateData;
+
+    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
+        if (!(dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
+                                            VIR_DOMAIN_XML_INACTIVE)))
+            goto cleanup;
+
+        /* Make a copy for updated domain. */
+        if (!(vmdef = virDomainObjCopyPersistentDef(driver->caps, vm)))
+            goto cleanup;
+
+        switch (action) {
+            case LIBXL_DEVICE_ATTACH:
+                ret = libxlDomainAttachDeviceConfig(vmdef, dev);
+                break;
+            case LIBXL_DEVICE_DETACH:
+                ret = libxlDomainDetachDeviceConfig(vmdef, dev);
+                break;
+            case LIBXL_DEVICE_UPDATE:
+                ret = libxlDomainUpdateDeviceConfig(vmdef, dev);
+            default:
+                libxlError(VIR_ERR_INTERNAL_ERROR,
+                           _("unknown domain modify action %d"), action);
+                break;
+        }
+    } else
+        ret = 0;
+
+    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
+        /* If dev exists it was created to modify the domain config. Free it, */
+        virDomainDeviceDefFree(dev);
+        if (!(dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
+                                            VIR_DOMAIN_XML_INACTIVE)))
+            goto cleanup;
+
+        switch (action) {
+            case LIBXL_DEVICE_ATTACH:
+                ret = libxlDomainAttachDeviceLive(priv, vm, dev);
+                break;
+            case LIBXL_DEVICE_DETACH:
+                ret = libxlDomainDetachDeviceLive(priv, vm, dev);
+                break;
+            case LIBXL_DEVICE_UPDATE:
+                ret = libxlDomainUpdateDeviceLive(priv, vm, dev);
+            default:
+                libxlError(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.
+         */
+        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;
+        }
+    }
+
+cleanup:
+    virDomainDefFree(vmdef);
+    virDomainDeviceDefFree(dev);
+    if (vm)
+        virDomainObjUnlock(vm);
+    libxlDriverUnlock(driver);
+    return ret;
+}
+
+static int
+libxlDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
+                             unsigned int flags)
+{
+    return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_ATTACH);
+}
+
+static int
+libxlDomainAttachDevice(virDomainPtr dom, const char *xml)
+{
+    return libxlDomainAttachDeviceFlags(dom, xml,
+                                        VIR_DOMAIN_DEVICE_MODIFY_LIVE);
+}
+
+static int
+libxlDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
+                             unsigned int flags)
+{
+    return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_DETACH);
+}
+
+static int
+libxlDomainDetachDevice(virDomainPtr dom, const char *xml)
+{
+    return libxlDomainDetachDeviceFlags(dom, xml,
+                                        VIR_DOMAIN_DEVICE_MODIFY_LIVE);
+}
+
+static int
+libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
+                             unsigned int flags)
+{
+    return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_UPDATE);
+}
+
 static unsigned long long
 libxlNodeGetFreeMemory(virConnectPtr conn)
 {
@@ -2736,6 +3250,11 @@ static virDriver libxlDriver = {
     .domainCreateWithFlags = libxlDomainCreateWithFlags, /* 0.9.0 */
     .domainDefineXML = libxlDomainDefineXML, /* 0.9.0 */
     .domainUndefine = libxlDomainUndefine, /* 0.9.0 */
+    .domainAttachDevice = libxlDomainAttachDevice, /* 0.9.2 */
+    .domainAttachDeviceFlags = libxlDomainAttachDeviceFlags, /* 0.9.2 */
+    .domainDetachDevice = libxlDomainDetachDevice,    /* 0.9.2 */
+    .domainDetachDeviceFlags = libxlDomainDetachDeviceFlags, /* 0.9.2 */
+    .domainUpdateDeviceFlags = libxlDomainUpdateDeviceFlags, /* 0.9.2 */
     .domainGetAutostart = libxlDomainGetAutostart, /* 0.9.0 */
     .domainSetAutostart = libxlDomainSetAutostart, /* 0.9.0 */
     .domainGetSchedulerType = libxlDomainGetSchedulerType, /* 0.9.0 */
-- 
1.7.5.1




More information about the libvir-list mailing list