From: "Daniel P. Berrange" <berrange(a)redhat.com>
This extends support for host device passthrough with LXC to
cover storage devices. In this case all we need todo is a
mknod in the container's /dev and whitelist the device in
cgroups
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/lxc/lxc_cgroup.c | 46 ++++++++++++++++++----------
src/lxc/lxc_container.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 111 insertions(+), 15 deletions(-)
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index 14c840a..0c3d5dd 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -414,21 +414,37 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
usbDevice *usb;
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
- continue;
- if (hostdev->missing)
- continue;
-
- if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- NULL)) == NULL)
- goto cleanup;
-
- if (usbDeviceFileIterate(usb, virLXCSetupHostUsbDeviceCgroup,
- cgroup) < 0)
- goto cleanup;
+ switch (hostdev->mode) {
+ case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
+ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
+ continue;
+ if (hostdev->missing)
+ continue;
+
+ if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
+ hostdev->source.subsys.u.usb.device,
+ NULL)) == NULL)
+ goto cleanup;
+
+ if (usbDeviceFileIterate(usb, virLXCSetupHostUsbDeviceCgroup,
+ cgroup) < 0)
+ goto cleanup;
+ break;
+ case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
+ switch (hostdev->source.caps.type) {
+ case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
+ if (virCgroupAllowDevicePath(cgroup,
+ hostdev->source.caps.u.storage.block,
+ VIR_CGROUP_DEVICE_RW |
+ VIR_CGROUP_DEVICE_MKNOD) < 0)
+ goto cleanup;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
}
rc = virCgroupAllowDeviceMajor(cgroup, 'c', LXC_DEV_MAJ_PTY,
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 0a407bf..19c5702 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -1384,6 +1384,64 @@ cleanup:
}
+static int lxcContainerSetupHostdevCapsStorage(virDomainDefPtr vmDef ATTRIBUTE_UNUSED,
+ virDomainHostdevDefPtr def
ATTRIBUTE_UNUSED,
+ const char *dstprefix ATTRIBUTE_UNUSED,
+ virSecurityManagerPtr securityDriver
ATTRIBUTE_UNUSED)
+{
+ char *src = NULL;
+ int ret = -1;
+ struct stat sb;
+ mode_t mode;
+
+ if (def->source.caps.u.storage.block == NULL) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Missing storage host block path"));
+ goto cleanup;
+ }
+
+ if (virAsprintf(&src, "%s/%s", dstprefix,
def->source.caps.u.storage.block) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (stat(src, &sb) < 0) {
+ virReportSystemError(errno,
+ _("Unable to access %s"),
+ src);
+ goto cleanup;
+ }
+
+ if (!S_ISBLK(sb.st_mode)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Storage source %s must be a block device"),
+ def->source.caps.u.storage.block);
+ 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(def->source.caps.u.storage.block, mode, sb.st_rdev) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create device %s"),
+ def->source.caps.u.storage.block);
+ goto cleanup;
+ }
+
+ if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(src);
+ return ret;
+}
+
+
static int lxcContainerSetupHostdevSubsys(virDomainDefPtr vmDef,
virDomainHostdevDefPtr def,
const char *dstprefix,
@@ -1402,6 +1460,24 @@ static int lxcContainerSetupHostdevSubsys(virDomainDefPtr vmDef,
}
+static int lxcContainerSetupHostdevCaps(virDomainDefPtr vmDef,
+ virDomainHostdevDefPtr def,
+ const char *dstprefix,
+ virSecurityManagerPtr securityDriver)
+{
+ switch (def->source.subsys.type) {
+ case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
+ return lxcContainerSetupHostdevCapsStorage(vmDef, def, dstprefix,
securityDriver);
+
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unsupported host device mode %s"),
+ virDomainHostdevCapsTypeToString(def->source.subsys.type));
+ return -1;
+ }
+}
+
+
static int lxcContainerSetupAllHostdevs(virDomainDefPtr vmDef,
const char *dstprefix,
virSecurityManagerPtr securityDriver)
@@ -1416,6 +1492,10 @@ static int lxcContainerSetupAllHostdevs(virDomainDefPtr vmDef,
if (lxcContainerSetupHostdevSubsys(vmDef, def, dstprefix, securityDriver)
< 0)
return -1;
break;
+ case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
+ if (lxcContainerSetupHostdevCaps(vmDef, def, dstprefix, securityDriver) <
0)
+ return -1;
+ break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported host device mode %s"),
--
1.8.0.1