From 95fef5f407870550e1248a4955058127afbcbae6 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Nov 2012 14:46:18 +0000 Subject: [PATCH] Add support for USB host device passthrough with LXC This adds support for host device passthrough with the LXC driver. Since there is only a single kernel image, it doesn't make sense to pass through PCI devices, but USB devices are fine. For the latter we merely need to make the /dev/bus/usb/NNN/MMM character device exist in the container's /dev Signed-off-by: Daniel P. Berrange --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_cgroup.c | 64 +++++++ src/lxc/lxc_cgroup.h | 12 ++ src/lxc/lxc_conf.h | 3 + src/lxc/lxc_container.c | 125 ++++++++++++- src/lxc/lxc_hostdev.c | 390 ++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_hostdev.h | 43 +++++ src/lxc/lxc_process.c | 11 ++ 9 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 src/lxc/lxc_hostdev.c create mode 100644 src/lxc/lxc_hostdev.h diff --git a/po/POTFILES.in b/po/POTFILES.in index f0cfd7fc5c..6b08cf0618 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -57,6 +57,7 @@ src/locking/lock_manager.c src/locking/sanlock_helper.c src/lxc/lxc_cgroup.c src/lxc/lxc_fuse.c +src/lxc/lxc_hostdev.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index 53ec9dad9e..2cdf16cc6b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -456,6 +456,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_container.c lxc/lxc_container.h \ lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_domain.c lxc/lxc_domain.h \ + lxc/lxc_hostdev.c lxc/lxc_hostdev.h \ lxc/lxc_monitor.c lxc/lxc_monitor.h \ lxc/lxc_process.c lxc/lxc_process.h \ lxc/lxc_fuse.c lxc/lxc_fuse.h \ diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 06368694c3..14c840a0f6 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -291,6 +291,49 @@ struct _virLXCCgroupDevicePolicy { }; +int +virLXCSetupHostUsbDeviceCgroup(usbDevice *dev ATTRIBUTE_UNUSED, + const char *path, + void *opaque) +{ + virCgroupPtr cgroup = opaque; + int rc; + + VIR_DEBUG("Process path '%s' for USB device", path); + rc = virCgroupAllowDevicePath(cgroup, path, + VIR_CGROUP_DEVICE_RW); + if (rc < 0) { + virReportSystemError(-rc, + _("Unable to allow device %s"), + path); + return -1; + } + + return 0; +} + + +int +virLXCTeardownHostUsbDeviceCgroup(usbDevice *dev ATTRIBUTE_UNUSED, + const char *path, + void *opaque) +{ + virCgroupPtr cgroup = opaque; + int rc; + + VIR_DEBUG("Process path '%s' for USB device", path); + rc = virCgroupDenyDevicePath(cgroup, path, + VIR_CGROUP_DEVICE_RW); + if (rc < 0) { + virReportSystemError(-rc, + _("Unable to deny device %s"), + path); + return -1; + } + + return 0; +} + static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, virCgroupPtr cgroup) @@ -367,6 +410,27 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, } } + for (i = 0; i < def->nhostdevs; i++) { + 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; + } + rc = virCgroupAllowDeviceMajor(cgroup, 'c', LXC_DEV_MAJ_PTY, VIR_CGROUP_DEVICE_RWM); if (rc != 0) { diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h index 6961943e14..c1d4551285 100644 --- a/src/lxc/lxc_cgroup.h +++ b/src/lxc/lxc_cgroup.h @@ -24,7 +24,19 @@ # include "domain_conf.h" # include "lxc_fuse.h" +# include "hostusb.h" int virLXCCgroupSetup(virDomainDefPtr def); int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo); + +int +virLXCSetupHostUsbDeviceCgroup(usbDevice *dev, + const char *path, + void *opaque); + +int +virLXCTeardownHostUsbDeviceCgroup(usbDevice *dev, + const char *path, + void *opaque); + #endif /* __VIR_LXC_CGROUP_H__ */ diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index ea345bede2..d66f2844e2 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -35,6 +35,7 @@ # include "cgroup.h" # include "security/security_manager.h" # include "configmake.h" +# include "hostusb.h" # define LXC_DRIVER_NAME "LXC" @@ -65,6 +66,8 @@ struct _virLXCDriver { int log_libvirtd; int have_netns; + usbDeviceList *activeUsbHostdevs; + virDomainEventStatePtr domainEventState; char *securityDriverName; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index be26de9628..6aef143ac0 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -62,6 +62,7 @@ #include "uuid.h" #include "virfile.h" #include "command.h" +#include "hostusb.h" #include "virnetdev.h" #include "virprocess.h" @@ -1311,6 +1312,124 @@ static int lxcContainerSetupAllDisks(virDomainDefPtr vmDef, } +static int lxcContainerSetupHostdevSubsysUSB(virDomainDefPtr vmDef ATTRIBUTE_UNUSED, + virDomainHostdevDefPtr def ATTRIBUTE_UNUSED, + const char *dstprefix ATTRIBUTE_UNUSED, + virSecurityManagerPtr securityDriver ATTRIBUTE_UNUSED) +{ + int ret = -1; + char *src = NULL; + char *dstdir = NULL; + char *dstfile = NULL; + struct stat sb; + mode_t mode; + + if (virAsprintf(&dstdir, USB_DEVFS "/%03d", + def->source.subsys.u.usb.bus) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&dstfile, "%s/%03d", + dstdir, + def->source.subsys.u.usb.device) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&src, "%s/%s", dstprefix, dstfile) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (stat(src, &sb) < 0) { + virReportSystemError(errno, + _("Unable to access %s"), src); + goto cleanup; + } + + if (!S_ISCHR(sb.st_mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("USB source %s was not a character device"), + src); + goto cleanup; + } + + mode = 0700 | S_IFCHR; + + if (virFileMakePath(dstdir) < 0) { + virReportSystemError(errno, + _("Unable to create %s"), dstdir); + goto cleanup; + } + + VIR_DEBUG("Creating dev %s (%d,%d)", + dstfile, major(sb.st_rdev), minor(sb.st_rdev)); + if (mknod(dstfile, mode, sb.st_rdev) < 0) { + virReportSystemError(errno, + _("Unable to create device %s"), + dstfile); + goto cleanup; + } + + if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) + goto cleanup; + + ret = 0; + +cleanup: + VIR_FREE(src); + VIR_FREE(dstfile); + VIR_FREE(dstdir); + return ret; +} + + +static int lxcContainerSetupHostdevSubsys(virDomainDefPtr vmDef, + virDomainHostdevDefPtr def, + const char *dstprefix, + virSecurityManagerPtr securityDriver) +{ + switch (def->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + return lxcContainerSetupHostdevSubsysUSB(vmDef, def, dstprefix, securityDriver); + + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported host device mode %s"), + virDomainHostdevSubsysTypeToString(def->source.subsys.type)); + return -1; + } +} + + +static int lxcContainerSetupAllHostdevs(virDomainDefPtr vmDef, + const char *dstprefix, + virSecurityManagerPtr securityDriver) +{ + size_t i; + VIR_DEBUG("Setting up hostdevs %s", dstprefix); + + for (i = 0 ; i < vmDef->nhostdevs ; i++) { + virDomainHostdevDefPtr def = vmDef->hostdevs[i]; + switch (def->mode) { + case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: + if (lxcContainerSetupHostdevSubsys(vmDef, def, dstprefix, securityDriver) < 0) + return -1; + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported host device mode %s"), + virDomainHostdevModeTypeToString(def->mode)); + return -1; + } + } + + VIR_DEBUG("Setup all hostdevs"); + return 0; +} + + static int lxcContainerGetSubtree(const char *prefix, char ***mountsret, size_t *nmountsret) @@ -1710,7 +1829,11 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef, if (lxcContainerSetupAllDisks(vmDef, "/.oldroot", securityDriver) < 0) goto cleanup; - /* Gets rid of all remaining mounts from host OS, including /.oldroot itself */ + /* Sets up any extra host devices from guest config */ + if (lxcContainerSetupAllHostdevs(vmDef, "/.oldroot", securityDriver) < 0) + goto cleanup; + + /* Gets rid of all remaining mounts from host OS, including /.oldroot itself */ if (lxcContainerUnmountSubtree("/.oldroot", true) < 0) goto cleanup; diff --git a/src/lxc/lxc_hostdev.c b/src/lxc/lxc_hostdev.c new file mode 100644 index 0000000000..c063aa0189 --- /dev/null +++ b/src/lxc/lxc_hostdev.c @@ -0,0 +1,390 @@ +/* + * virLXC_hostdev.c: VIRLXC hostdev management + * + * Copyright (C) 2006-2007, 2009-2012 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#include + +#include "lxc_hostdev.h" +#include "logging.h" +#include "virterror_internal.h" +#include "memory.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +int +virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver, + virDomainDefPtr def) +{ + virDomainHostdevDefPtr hostdev = NULL; + size_t i; + + if (!def->nhostdevs) + return 0; + + for (i = 0; i < def->nhostdevs; i++) { + usbDevice *usb = NULL; + hostdev = def->hostdevs[i]; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) + continue; + + usb = usbGetDevice(hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + NULL); + if (!usb) { + VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + def->name); + continue; + } + + usbDeviceSetUsedBy(usb, def->name); + + if (usbDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) { + usbFreeDevice(usb); + return -1; + } + } + + return 0; +} + + +int +virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver, + const char *name, + usbDeviceList *list) +{ + size_t i, j; + unsigned int count; + usbDevice *tmp; + + count = usbDeviceListCount(list); + + for (i = 0; i < count; i++) { + usbDevice *usb = usbDeviceListGet(list, i); + if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) { + const char *other_name = usbDeviceGetUsedBy(tmp); + + if (other_name) + virReportError(VIR_ERR_OPERATION_INVALID, + _("USB device %s is in use by domain %s"), + usbDeviceGetName(tmp), other_name); + else + virReportError(VIR_ERR_OPERATION_INVALID, + _("USB device %s is already in use"), + usbDeviceGetName(tmp)); + goto error; + } + + usbDeviceSetUsedBy(usb, name); + VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", + usbDeviceGetBus(usb), usbDeviceGetDevno(usb), name); + /* + * The caller is responsible to steal these usb devices + * from the usbDeviceList that passed in on success, + * perform rollback on failure. + */ + if (usbDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) + goto error; + } + return 0; + +error: + for (j = 0; j < i; j++) { + tmp = usbDeviceListGet(list, i); + usbDeviceListSteal(driver->activeUsbHostdevs, tmp); + } + return -1; +} + +int +virLXCFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, + bool mandatory, + usbDevice **usb) +{ + unsigned vendor = hostdev->source.subsys.u.usb.vendor; + unsigned product = hostdev->source.subsys.u.usb.product; + unsigned bus = hostdev->source.subsys.u.usb.bus; + unsigned device = hostdev->source.subsys.u.usb.device; + bool autoAddress = hostdev->source.subsys.u.usb.autoAddress; + int rc; + + *usb = NULL; + + if (vendor && bus) { + rc = usbFindDevice(vendor, product, bus, device, + NULL, + autoAddress ? false : mandatory, + usb); + if (rc < 0) { + return -1; + } else if (!autoAddress) { + goto out; + } else { + VIR_INFO("USB device %x:%x could not be found at previous" + " address (bus:%u device:%u)", + vendor, product, bus, device); + } + } + + /* When vendor is specified, its USB address is either unspecified or the + * device could not be found at the USB device where it had been + * automatically found before. + */ + if (vendor) { + usbDeviceList *devs; + + rc = usbFindDeviceByVendor(vendor, product, + NULL, + mandatory, &devs); + if (rc < 0) + return -1; + + if (rc == 1) { + *usb = usbDeviceListGet(devs, 0); + usbDeviceListSteal(devs, *usb); + } + usbDeviceListFree(devs); + + if (rc == 0) { + goto out; + } else if (rc > 1) { + if (autoAddress) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Multiple USB devices for %x:%x were found," + " but none of them is at bus:%u device:%u"), + vendor, product, bus, device); + } else { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Multiple USB devices for %x:%x, " + "use
to specify one"), + vendor, product); + } + return -1; + } + + hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(*usb); + hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(*usb); + hostdev->source.subsys.u.usb.autoAddress = true; + + if (autoAddress) { + VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved" + " from bus:%u device:%u)", + vendor, product, + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + bus, device); + } + } else if (!vendor && bus) { + if (usbFindDeviceByBus(bus, device, + NULL, + mandatory, usb) < 0) + return -1; + } + +out: + if (!*usb) + hostdev->missing = 1; + return 0; +} + +static int +virLXCPrepareHostUSBDevices(virLXCDriverPtr driver, + virDomainDefPtr def) +{ + size_t i; + int ret = -1; + usbDeviceList *list; + usbDevice *tmp; + virDomainHostdevDefPtr *hostdevs = def->hostdevs; + int nhostdevs = def->nhostdevs; + + /* To prevent situation where USB device is assigned to two domains + * we need to keep a list of currently assigned USB devices. + * This is done in several loops which cannot be joined into one big + * loop. See virLXCPrepareHostdevPCIDevices() + */ + if (!(list = usbDeviceListNew())) + goto cleanup; + + /* Loop 1: build temporary list + */ + for (i = 0 ; i < nhostdevs ; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + bool required = true; + 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->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL) + required = false; + + if (virLXCFindHostdevUSBDevice(hostdev, required, &usb) < 0) + goto cleanup; + + if (usb && usbDeviceListAdd(list, usb) < 0) { + usbFreeDevice(usb); + goto cleanup; + } + } + + /* Mark devices in temporary list as used by @name + * and add them do driver list. However, if something goes + * wrong, perform rollback. + */ + if (virLXCPrepareHostdevUSBDevices(driver, def->name, list) < 0) + goto cleanup; + + /* Loop 2: Temporary list was successfully merged with + * driver list, so steal all items to avoid freeing them + * in cleanup label. + */ + while (usbDeviceListCount(list) > 0) { + tmp = usbDeviceListGet(list, 0); + usbDeviceListSteal(list, tmp); + } + + ret = 0; + +cleanup: + usbDeviceListFree(list); + return ret; +} + + +int virLXCPrepareHostDevices(virLXCDriverPtr driver, + virDomainDefPtr def) +{ + size_t i; + + if (!def->nhostdevs) + return 0; + + /* Sanity check for supported configurations only */ + for (i = 0 ; i < def->nhostdevs ; i++) { + virDomainHostdevDefPtr dev = def->hostdevs[i]; + + switch (dev->mode) { + case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: + switch (dev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported hostdev type %s"), + virDomainHostdevSubsysTypeToString(dev->source.subsys.type)); + break; + } + break; + + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported hostdev mode %s"), + virDomainHostdevModeTypeToString(dev->mode)); + break; + } + } + + if (virLXCPrepareHostUSBDevices(driver, def) < 0) + return -1; + + return 0; +} + + +static void +virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + usbDevice *usb, *tmp; + const char *used_by = NULL; + + 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; + + usb = usbGetDevice(hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + NULL); + + if (!usb) { + VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + name); + continue; + } + + /* Delete only those USB devices which belongs + * to domain @name because virLXCProcessStart() might + * have failed because USB device is already taken. + * Therefore we want to steal only those devices from + * the list which were taken by @name */ + + tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb); + usbFreeDevice(usb); + + if (!tmp) { + VIR_WARN("Unable to find device %03d.%03d " + "in list of active USB devices", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device); + continue; + } + + used_by = usbDeviceGetUsedBy(tmp); + if (STREQ_NULLABLE(used_by, name)) { + VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + name); + + usbDeviceListDel(driver->activeUsbHostdevs, tmp); + } + } +} + +void virLXCDomainReAttachHostDevices(virLXCDriverPtr driver, + virDomainDefPtr def) +{ + if (!def->nhostdevs) + return; + + virLXCDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs, + def->nhostdevs); +} diff --git a/src/lxc/lxc_hostdev.h b/src/lxc/lxc_hostdev.h new file mode 100644 index 0000000000..dd9811289e --- /dev/null +++ b/src/lxc/lxc_hostdev.h @@ -0,0 +1,43 @@ +/* + * virLXC_hostdev.h: VIRLXC hostdev management + * + * Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#ifndef __LXC_HOSTDEV_H__ +# define __LXC_HOSTDEV_H__ + +# include "lxc_conf.h" +# include "domain_conf.h" + +int virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver, + virDomainDefPtr def); +int virLXCFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, + bool mandatory, + usbDevice **usb); +int virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver, + const char *name, + usbDeviceList *list); +int virLXCPrepareHostDevices(virLXCDriverPtr driver, + virDomainDefPtr def); +void virLXCDomainReAttachHostDevices(virLXCDriverPtr driver, + virDomainDefPtr def); + +#endif /* __LXC_HOSTDEV_H__ */ diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 82bc1fcdc6..5c548c2d45 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -44,6 +44,7 @@ #include "logging.h" #include "command.h" #include "hooks.h" +#include "lxc_hostdev.h" #define VIR_FROM_THIS VIR_FROM_LXC @@ -256,6 +257,8 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, if (!driver->nactive && driver->inhibitCallback) driver->inhibitCallback(false, driver->inhibitOpaque); + virLXCDomainReAttachHostDevices(driver, vm->def); + for (i = 0 ; i < vm->def->nnets ; i++) { virDomainNetDefPtr iface = vm->def->nets[i]; vport = virDomainNetGetActualVirtPortProfile(iface); @@ -978,6 +981,11 @@ int virLXCProcessStart(virConnectPtr conn, goto cleanup; } + /* Must be run before security labelling */ + VIR_DEBUG("Preparing host devices"); + if (virLXCPrepareHostDevices(driver, vm->def) < 0) + goto cleanup; + /* Here we open all the PTYs we need on the host OS side. * The LXC controller will open the guest OS side PTYs * and forward I/O between them. @@ -1311,6 +1319,9 @@ virLXCProcessReconnectDomain(void *payload, const void *name ATTRIBUTE_UNUSED, v if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) goto error; + if (virLXCUpdateActiveUsbHostdevs(driver, vm->def) < 0) + goto error; + if (virSecurityManagerReserveLabel(driver->securityManager, vm->def, vm->pid) < 0) goto error;