[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 20/23] Add support for hotplug/unplug of host storage devices in LXC



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

Wire up the attach/detach device drivers in LXC to support the
hotplug/unplug of host storage devices.

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

diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 50050cf..27ee3d7 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -3224,6 +3224,12 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
     usbDevice *usb = NULL;
     virCgroupPtr group = NULL;
 
+    if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("host USB device already exists"));
+        return -1;
+    }
+
     if (virAsprintf(&vroot, "/proc/%llu/root",
                     (unsigned long long)priv->initpid) < 0) {
         virReportOOMError();
@@ -3351,6 +3357,123 @@ cleanup:
 
 
 static int
+lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver,
+                                        virDomainObjPtr vm,
+                                        virDomainDeviceDefPtr dev)
+{
+    virLXCDomainObjPrivatePtr priv = vm->privateData;
+    virDomainHostdevDefPtr def = dev->data.hostdev;
+    virCgroupPtr group = NULL;
+    int ret = -1;
+    char *dst;
+    char *vroot;
+    struct stat sb;
+    bool created = false;
+    mode_t mode = 0;
+
+    if (!priv->initpid) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("Cannot attach disk until init PID is known"));
+        goto cleanup;
+    }
+
+    if (!def->source.caps.u.storage.block) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Missing storage block path"));
+        goto cleanup;
+    }
+
+    if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("host device already exists"));
+        return -1;
+    }
+
+    if (stat(def->source.caps.u.storage.block, &sb) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to access %s"),
+                             def->source.caps.u.storage.block);
+        goto cleanup;
+    }
+
+    if (!S_ISBLK(sb.st_mode)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Hostdev source %s must be a block device"),
+                       def->source.caps.u.storage.block);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&vroot, "/proc/%llu/root",
+                    (unsigned long long)priv->initpid) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virAsprintf(&dst, "%s/%s",
+                    vroot,
+                    def->source.caps.u.storage.block) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    mode = 0700 | S_IFBLK;
+
+    VIR_DEBUG("Creating dev %s (%d,%d)",
+              def->source.caps.u.storage.block,
+              major(sb.st_rdev), minor(sb.st_rdev));
+    if (mknod(dst, mode, sb.st_rdev) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to create device %s"),
+                             dst);
+        goto cleanup;
+    }
+    created = true;
+
+    if (virSecurityManagerSetHostdevLabel(driver->securityManager,
+                                          vm->def, def, vroot) < 0)
+        goto cleanup;
+
+    if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("devices cgroup isn't mounted"));
+        goto cleanup;
+    }
+
+    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot find cgroup for domain %s"), vm->def->name);
+        goto cleanup;
+    }
+
+    if (virCgroupAllowDevicePath(group, def->source.caps.u.storage.block,
+                                 VIR_CGROUP_DEVICE_RW |
+                                 VIR_CGROUP_DEVICE_MKNOD) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot allow device %s for domain %s"),
+                       def->source.caps.u.storage.block, vm->def->name);
+        goto cleanup;
+    }
+
+    vm->def->hostdevs[vm->def->nhostdevs++] = def;
+
+    ret = 0;
+
+cleanup:
+    virDomainAuditHostdev(vm, def, "attach", ret == 0);
+    if (group)
+        virCgroupFree(&group);
+    if (dst && created && ret < 0)
+        unlink(dst);
+    return ret;
+}
+
+
+static int
 lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
                                        virDomainObjPtr vm,
                                        virDomainDeviceDefPtr dev)
@@ -3369,6 +3492,24 @@ lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
 
 
 static int
+lxcDomainAttachDeviceHostdevCapsLive(virLXCDriverPtr driver,
+                                     virDomainObjPtr vm,
+                                     virDomainDeviceDefPtr dev)
+{
+    switch (dev->data.hostdev->source.caps.type) {
+    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
+        return lxcDomainAttachDeviceHostdevStorageLive(driver, vm, dev);
+
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Unsupported host device type %s"),
+                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
+        return -1;
+    }
+}
+
+
+static int
 lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver,
                                  virDomainObjPtr vm,
                                  virDomainDeviceDefPtr dev)
@@ -3385,6 +3526,9 @@ lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver,
     case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
         return lxcDomainAttachDeviceHostdevSubsysLive(driver, vm, dev);
 
+    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
+        return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);
+
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Unsupported host device mode %s"),
@@ -3658,6 +3802,78 @@ cleanup:
     return ret;
 }
 
+
+static int
+lxcDomainDetachDeviceHostdevStorageLive(virLXCDriverPtr driver,
+                                        virDomainObjPtr vm,
+                                        virDomainDeviceDefPtr dev)
+{
+    virLXCDomainObjPrivatePtr priv = vm->privateData;
+    virDomainHostdevDefPtr def = NULL;
+    virCgroupPtr group = NULL;
+    int i, ret = -1;
+    char *dst = NULL;
+
+    if (!priv->initpid) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("Cannot attach disk until init PID is known"));
+        goto cleanup;
+    }
+
+    if ((i = virDomainHostdevFind(vm->def,
+                                  dev->data.hostdev,
+                                  &def)) < 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("hostdev %s not found"),
+                       dev->data.hostdev->source.caps.u.storage.block);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&dst, "/proc/%llu/root/%s",
+                    (unsigned long long)priv->initpid,
+                    def->source.caps.u.storage.block) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("devices cgroup isn't mounted"));
+        goto cleanup;
+    }
+
+    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot find cgroup for domain %s"), vm->def->name);
+        goto cleanup;
+    }
+
+    VIR_DEBUG("Unlinking %s", dst);
+    if (unlink(dst) < 0 && errno != ENOENT) {
+        virDomainAuditHostdev(vm, def, "detach", false);
+        virReportSystemError(errno,
+                             _("Unable to remove device %s"), dst);
+        goto cleanup;
+    }
+    virDomainAuditHostdev(vm, def, "detach", true);
+
+    if (virCgroupDenyDevicePath(group, def->source.caps.u.storage.block, VIR_CGROUP_DEVICE_RWM) != 0)
+        VIR_WARN("cannot deny device %s for domain %s",
+                 def->source.caps.u.storage.block, vm->def->name);
+
+    virDomainHostdevRemove(vm->def, i);
+    virDomainHostdevDefFree(def);
+
+    ret = 0;
+
+cleanup:
+    VIR_FREE(dst);
+    if (group)
+        virCgroupFree(&group);
+    return ret;
+}
+
+
 static int
 lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
                                        virDomainObjPtr vm,
@@ -3677,6 +3893,24 @@ lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
 
 
 static int
+lxcDomainDetachDeviceHostdevCapsLive(virLXCDriverPtr driver,
+                                       virDomainObjPtr vm,
+                                       virDomainDeviceDefPtr dev)
+{
+    switch (dev->data.hostdev->source.caps.type) {
+    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
+        return lxcDomainDetachDeviceHostdevStorageLive(driver, vm, dev);
+
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Unsupported host device type %s"),
+                       virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
+        return -1;
+    }
+}
+
+
+static int
 lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
                                  virDomainObjPtr vm,
                                  virDomainDeviceDefPtr dev)
@@ -3693,6 +3927,9 @@ lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
     case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
         return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev);
 
+    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
+        return lxcDomainDetachDeviceHostdevCapsLive(driver, vm, dev);
+
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Unsupported host device mode %s"),
-- 
1.8.0.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]