When attaching a device to a domain that's using separate mount
namespace we must maintain /dev entries in order for qemu process
to see them.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_domain.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_domain.h | 8 +++
src/qemu/qemu_hotplug.c | 48 +++++++++-----
src/qemu/qemu_security.c | 38 +++++++++++
src/qemu/qemu_security.h | 8 +++
5 files changed, 246 insertions(+), 15 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index a1edde9..ac09b2c 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -7364,6 +7364,13 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
def->src->path = tmpsrc;
} break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV: {
+ virDomainHostdevDefPtr def = data->devDef->data.hostdev;
+ if (virSecurityManagerSetHostdevLabel(data->driver->securityManager,
+ data->vm->def, def, NULL) < 0)
+ goto cleanup;
+ } break;
+
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
@@ -7371,7 +7378,6 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_VIDEO:
- case VIR_DOMAIN_DEVICE_HOSTDEV:
case VIR_DOMAIN_DEVICE_WATCHDOG:
case VIR_DOMAIN_DEVICE_CONTROLLER:
case VIR_DOMAIN_DEVICE_GRAPHICS:
@@ -7451,6 +7457,91 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
}
+static int
+qemuDomainDetachDeviceUnlinkHelper(pid_t pid ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ const char *path = opaque;
+
+ VIR_DEBUG("Unlinking %s", path);
+ if (unlink(path) < 0 && errno != ENOENT) {
+ virReportSystemError(errno,
+ _("Unable to remove device %s"), path);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDetachDeviceUnlink(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev,
+ const char *file)
+{
+ /* Technically, this is not needed. Yet. But in the future
+ * security managers might do some reference counting over
+ * Set/Restore label and thus for every SetLabel() there
+ * should be corresponding RestoreLabel(). */
+ switch ((virDomainDeviceType) dev->type) {
+ case VIR_DOMAIN_DEVICE_DISK: {
+ virDomainDiskDefPtr def = dev->data.disk;
+ char *tmpsrc = def->src->path;
+ def->src->path = (char *) file;
+ if (virSecurityManagerRestoreDiskLabel(driver->securityManager,
+ vm->def, def) < 0) {
+ def->src->path = tmpsrc;
+ return -1;
+ }
+ def->src->path = tmpsrc;
+ } break;
+
+ case VIR_DOMAIN_DEVICE_HOSTDEV: {
+ virDomainHostdevDefPtr def = dev->data.hostdev;
+ if (virSecurityManagerRestoreHostdevLabel(driver->securityManager,
+ vm->def, def, NULL) < 0)
+ return -1;
+ } break;
+
+ case VIR_DOMAIN_DEVICE_NONE:
+ case VIR_DOMAIN_DEVICE_LEASE:
+ case VIR_DOMAIN_DEVICE_FS:
+ case VIR_DOMAIN_DEVICE_NET:
+ case VIR_DOMAIN_DEVICE_INPUT:
+ case VIR_DOMAIN_DEVICE_SOUND:
+ case VIR_DOMAIN_DEVICE_VIDEO:
+ case VIR_DOMAIN_DEVICE_WATCHDOG:
+ case VIR_DOMAIN_DEVICE_CONTROLLER:
+ case VIR_DOMAIN_DEVICE_GRAPHICS:
+ case VIR_DOMAIN_DEVICE_HUB:
+ case VIR_DOMAIN_DEVICE_REDIRDEV:
+ case VIR_DOMAIN_DEVICE_SMARTCARD:
+ case VIR_DOMAIN_DEVICE_CHR:
+ case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
+ case VIR_DOMAIN_DEVICE_RNG:
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ case VIR_DOMAIN_DEVICE_TPM:
+ case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ case VIR_DOMAIN_DEVICE_IOMMU:
+ case VIR_DOMAIN_DEVICE_LAST:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected device type %d"),
+ dev->type);
+ return -1;
+ }
+
+ if (virProcessRunInMountNamespace(vm->pid,
+ qemuDomainDetachDeviceUnlinkHelper,
+ (void *)file) < 0)
+ return -1;
+
+ return 0;
+}
+
+
int
qemuDomainNamespaceSetupDisk(virQEMUDriverPtr driver,
virDomainObjPtr vm,
@@ -7512,3 +7603,69 @@ qemuDomainNamespaceTeardownDisk(virQEMUDriverPtr driver
ATTRIBUTE_UNUSED,
* I don't, therefore: */
return 0;
}
+
+
+int
+qemuDomainNamespaceSetupHostdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainDeviceDef dev = {.type = VIR_DOMAIN_DEVICE_HOSTDEV, .data.hostdev =
hostdev};
+ int ret = -1;
+ char *path = NULL;
+
+ if (!priv->containerized)
+ return 0;
+
+ if (qemuDomainGetHostdevPath(hostdev, &path) < 0)
+ goto cleanup;
+
+ if (!path) {
+ /* There's no /dev device that we need to create. Claim success. */
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (qemuDomainAttachDeviceMknod(driver,
+ vm,
+ &dev,
+ path) < 0)
+ goto cleanup;
+ ret = 0;
+ cleanup:
+ VIR_FREE(path);
+ return ret;
+}
+
+
+int
+qemuDomainNamespaceTeardownHostdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainDeviceDef dev = {.type = VIR_DOMAIN_DEVICE_HOSTDEV, .data.hostdev =
hostdev};
+ int ret = -1;
+ char *path = NULL;
+
+ if (!priv->containerized)
+ return 0;
+
+ if (qemuDomainGetHostdevPath(hostdev, &path) < 0)
+ goto cleanup;
+
+ if (!path) {
+ /* There's no /dev device that we need to create. Claim success. */
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (qemuDomainDetachDeviceUnlink(driver, vm, &dev, path) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(path);
+ return ret;
+}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 045d1ba..ef85ae4 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -803,4 +803,12 @@ int qemuDomainNamespaceSetupDisk(virQEMUDriverPtr driver,
int qemuDomainNamespaceTeardownDisk(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk);
+
+int qemuDomainNamespaceSetupHostdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev);
+
+int qemuDomainNamespaceTeardownHostdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev);
#endif /* __QEMU_DOMAIN_H__ */
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 9b47b5f..58b2439 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1384,6 +1384,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
bool releaseaddr = false;
bool teardowncgroup = false;
bool teardownlabel = false;
+ bool teardowndevice = false;
int backend;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
unsigned int flags = 0;
@@ -1435,12 +1436,15 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
}
vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;
+ if (qemuDomainNamespaceSetupHostdev(driver, vm, hostdev) < 0)
+ goto error;
+ teardowndevice = true;
+
if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
goto error;
teardowncgroup = true;
- if (virSecurityManagerSetHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
goto error;
if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
teardownlabel = true;
@@ -1493,9 +1497,11 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
if (teardownlabel &&
- virSecurityManagerRestoreHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug fail");
+ if (teardowndevice &&
+ qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
+ VIR_WARN("Unable to remove host device from /dev");
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
@@ -2275,6 +2281,7 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
bool added = false;
bool teardowncgroup = false;
bool teardownlabel = false;
+ bool teardowndevice = false;
int ret = -1;
if (priv->usbaddrs) {
@@ -2288,12 +2295,15 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
added = true;
+ if (qemuDomainNamespaceSetupHostdev(driver, vm, hostdev) < 0)
+ goto cleanup;
+ teardowndevice = true;
+
if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
goto cleanup;
teardowncgroup = true;
- if (virSecurityManagerSetHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
goto cleanup;
teardownlabel = true;
@@ -2323,9 +2333,11 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug
fail");
if (teardownlabel &&
- virSecurityManagerRestoreHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug
fail");
+ if (teardowndevice &&
+ qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
+ VIR_WARN("Unable to remove host device from /dev");
if (added)
qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
if (releaseaddr)
@@ -2351,6 +2363,7 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
char *drivealias = NULL;
bool teardowncgroup = false;
bool teardownlabel = false;
+ bool teardowndevice = false;
bool driveAdded = false;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
@@ -2389,12 +2402,15 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
return -1;
}
+ if (qemuDomainNamespaceSetupHostdev(driver, vm, hostdev) < 0)
+ goto cleanup;
+ teardowndevice = true;
+
if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
goto cleanup;
teardowncgroup = true;
- if (virSecurityManagerSetHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
goto cleanup;
teardownlabel = true;
@@ -2441,9 +2457,11 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug
fail");
if (teardownlabel &&
- virSecurityManagerRestoreHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug
fail");
+ if (teardowndevice &&
+ qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
+ VIR_WARN("Unable to remove host device from /dev");
}
VIR_FREE(drivealias);
VIR_FREE(drvstr);
@@ -3651,13 +3669,15 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
virDomainAuditHostdev(vm, hostdev, "detach", true);
if (!is_vfio &&
- virSecurityManagerRestoreHostdevLabel(driver->securityManager,
- vm->def, hostdev, NULL) < 0)
+ qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
VIR_WARN("Failed to restore host device labelling");
if (qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Failed to remove host device cgroup ACL");
+ if (qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
+ VIR_WARN("Unable to remove host device from /dev");
+
switch ((virDomainHostdevSubsysType) hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c
index f800d9b..de616e8 100644
--- a/src/qemu/qemu_security.c
+++ b/src/qemu/qemu_security.c
@@ -168,3 +168,41 @@ qemuSecurityRestoreDiskLabel(virQEMUDriverPtr driver,
vm->def,
disk);
}
+
+
+int
+qemuSecuritySetHostdevLabel(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ if (priv->containerized) {
+ /* Already handled by namespace code. */
+ return 0;
+ }
+
+ return virSecurityManagerSetHostdevLabel(driver->securityManager,
+ vm->def,
+ hostdev,
+ NULL);
+}
+
+
+int
+qemuSecurityRestoreHostdevLabel(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ if (priv->containerized) {
+ /* Already handled by namespace code. */
+ return 0;
+ }
+
+ return virSecurityManagerRestoreHostdevLabel(driver->securityManager,
+ vm->def,
+ hostdev,
+ NULL);
+}
diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h
index e3324ca..cc373b3 100644
--- a/src/qemu/qemu_security.h
+++ b/src/qemu/qemu_security.h
@@ -44,4 +44,12 @@ int qemuSecuritySetDiskLabel(virQEMUDriverPtr driver,
int qemuSecurityRestoreDiskLabel(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk);
+
+int qemuSecuritySetHostdevLabel(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev);
+
+int qemuSecurityRestoreHostdevLabel(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev);
#endif /* __QEMU_SECURITY_H__ */
--
2.8.4