[libvirt] [PATCH 13/23] Add basic driver API framework for device attach/detach support in LXC

Daniel P. Berrange berrange at redhat.com
Fri Nov 30 20:26:27 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

This wires up the LXC driver to support the domain device attach/
detach/update APIs, following the same code design as used in
the QEMU driver. No actual changes are possible with this commit,
it is only providing the framework

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/lxc/lxc_driver.c | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 290 insertions(+)

diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 1c6ec8c..38d5d87 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -2768,6 +2768,291 @@ lxcListAllDomains(virConnectPtr conn,
     return ret;
 }
 
+
+static int
+lxcDomainAttachDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
+                            virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+    default:
+         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("persistent attach of device is not supported"));
+         break;
+    }
+
+    return ret;
+}
+
+
+static int
+lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef ATTRIBUTE_UNUSED,
+                            virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("persistent update of device is not supported"));
+        break;
+    }
+
+    return ret;
+}
+
+
+static int
+lxcDomainDetachDeviceConfig(virDomainDefPtr vmDef ATTRIBUTE_UNUSED,
+                            virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("persistent detach of device is not supported"));
+        break;
+    }
+
+    return ret;
+}
+
+
+static int
+lxcDomainAttachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
+                          virDomainObjPtr vm ATTRIBUTE_UNUSED,
+                          virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("device type '%s' cannot be attached"),
+                       virDomainDeviceTypeToString(dev->type));
+        break;
+    }
+
+    return ret;
+}
+
+
+static int
+lxcDomainDetachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
+                          virDomainObjPtr vm ATTRIBUTE_UNUSED,
+                          virDomainDeviceDefPtr dev)
+{
+    int ret = -1;
+
+    switch (dev->type) {
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("device type '%s' cannot be detached"),
+                       virDomainDeviceTypeToString(dev->type));
+        break;
+    }
+
+    return ret;
+}
+
+
+/* Actions for lxcDomainModifyDeviceFlags */
+enum {
+    LXC_DEVICE_ATTACH,
+    LXC_DEVICE_UPDATE,
+    LXC_DEVICE_DETACH,
+};
+
+
+static int
+lxcDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
+                           unsigned int flags, int action)
+{
+    virLXCDriverPtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virDomainDefPtr vmdef = NULL;
+    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
+    int ret = -1;
+    unsigned int affect;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG |
+                  (action == LXC_DEVICE_UPDATE ?
+                   VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);
+
+    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);
+
+    lxcDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_DOMAIN,
+                       _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    if (virDomainObjIsActive(vm)) {
+        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
+            flags |= VIR_DOMAIN_AFFECT_LIVE;
+    } else {
+        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
+            flags |= VIR_DOMAIN_AFFECT_CONFIG;
+        /* check consistency between flags and the vm state */
+        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("cannot do live update a device on "
+                             "inactive domain"));
+            goto cleanup;
+        }
+    }
+
+    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
+         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                        _("cannot modify device on transient domain"));
+         goto cleanup;
+    }
+
+    dev = dev_copy = virDomainDeviceDefParse(driver->caps, vm->def, xml,
+                                             VIR_DOMAIN_XML_INACTIVE);
+    if (dev == NULL)
+        goto cleanup;
+
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
+        flags & VIR_DOMAIN_AFFECT_LIVE) {
+        /* If we are affecting both CONFIG and LIVE
+         * create a deep copy of device as adding
+         * to CONFIG takes one instance.
+         */
+        dev_copy = virDomainDeviceDefCopy(driver->caps, vm->def, dev);
+        if (!dev_copy)
+            goto cleanup;
+    }
+
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
+            goto cleanup;
+
+        /* Make a copy for updated domain. */
+        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
+        if (!vmdef)
+            goto cleanup;
+        switch (action) {
+        case LXC_DEVICE_ATTACH:
+            ret = lxcDomainAttachDeviceConfig(vmdef, dev);
+            break;
+        case LXC_DEVICE_DETACH:
+            ret = lxcDomainDetachDeviceConfig(vmdef, dev);
+            break;
+        case LXC_DEVICE_UPDATE:
+            ret = lxcDomainUpdateDeviceConfig(vmdef, dev);
+            break;
+        default:
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unknown domain modify action %d"), action);
+            break;
+        }
+
+        if (ret == -1)
+            goto cleanup;
+    }
+
+    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
+            goto cleanup;
+
+        switch (action) {
+        case LXC_DEVICE_ATTACH:
+            ret = lxcDomainAttachDeviceLive(driver, vm, dev_copy);
+            break;
+        case LXC_DEVICE_DETACH:
+            ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy);
+            break;
+        default:
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unknown domain modify action %d"), action);
+            ret = -1;
+            break;
+        }
+
+        if (ret == -1)
+            goto cleanup;
+        /*
+         * update domain status forcibly because the domain status may be
+         * changed even if we failed to attach the device. For example,
+         * a new controller may be created.
+         */
+        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
+            ret = -1;
+            goto cleanup;
+        }
+    }
+
+    /* Finally, if no error until here, we can save config. */
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+        ret = virDomainSaveConfig(driver->configDir, vmdef);
+        if (!ret) {
+            virDomainObjAssignDef(vm, vmdef, false);
+            vmdef = NULL;
+        }
+    }
+
+cleanup:
+    virDomainDefFree(vmdef);
+    if (dev != dev_copy)
+        virDomainDeviceDefFree(dev_copy);
+    virDomainDeviceDefFree(dev);
+    if (vm)
+        virDomainObjUnlock(vm);
+    lxcDriverUnlock(driver);
+    return ret;
+}
+
+
+static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
+                                      const char *xml,
+                                      unsigned int flags)
+{
+    return lxcDomainModifyDeviceFlags(dom, xml, flags,
+                                       LXC_DEVICE_ATTACH);
+}
+
+
+static int lxcDomainAttachDevice(virDomainPtr dom,
+                                 const char *xml)
+{
+    return lxcDomainAttachDeviceFlags(dom, xml,
+                                       VIR_DOMAIN_AFFECT_LIVE);
+}
+
+
+static int lxcDomainUpdateDeviceFlags(virDomainPtr dom,
+                                      const char *xml,
+                                      unsigned int flags)
+{
+    return lxcDomainModifyDeviceFlags(dom, xml, flags,
+                                       LXC_DEVICE_UPDATE);
+}
+
+
+static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
+                                      const char *xml,
+                                      unsigned int flags)
+{
+    return lxcDomainModifyDeviceFlags(dom, xml, flags,
+                                      LXC_DEVICE_DETACH);
+}
+
+
+static int lxcDomainDetachDevice(virDomainPtr dom,
+                                 const char *xml)
+{
+    return lxcDomainDetachDeviceFlags(dom, xml,
+                                      VIR_DOMAIN_AFFECT_LIVE);
+}
+
 /* Function Tables */
 static virDriver lxcDriver = {
     .no = VIR_DRV_LXC,
@@ -2809,6 +3094,11 @@ static virDriver lxcDriver = {
     .domainDefineXML = lxcDomainDefine, /* 0.4.2 */
     .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
     .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
+    .domainAttachDevice = lxcDomainAttachDevice, /* 1.0.1 */
+    .domainAttachDeviceFlags = lxcDomainAttachDeviceFlags, /* 1.0.1 */
+    .domainDetachDevice = lxcDomainDetachDevice, /* 1.0.1 */
+    .domainDetachDeviceFlags = lxcDomainDetachDeviceFlags, /* 1.0.1 */
+    .domainUpdateDeviceFlags = lxcDomainUpdateDeviceFlags, /* 1.0.1 */
     .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
     .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
     .domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
-- 
1.8.0.1




More information about the libvir-list mailing list