mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-26 03:21:44 +03:00
qemu: Manage /dev entry on disk hotplug
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@redhat.com>
This commit is contained in:
parent
eadaa97548
commit
81df21507b
@ -53,6 +53,11 @@
|
|||||||
|
|
||||||
#include "storage/storage_driver.h"
|
#include "storage/storage_driver.h"
|
||||||
|
|
||||||
|
#ifdef MAJOR_IN_MKDEV
|
||||||
|
# include <sys/mkdev.h>
|
||||||
|
#elif MAJOR_IN_SYSMACROS
|
||||||
|
# include <sys/sysmacros.h>
|
||||||
|
#endif
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#if defined(HAVE_SYS_MOUNT_H)
|
#if defined(HAVE_SYS_MOUNT_H)
|
||||||
@ -7460,3 +7465,212 @@ qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
|
|||||||
virStringListFreeCount(devMountsPath, ndevMountsPath);
|
virStringListFreeCount(devMountsPath, ndevMountsPath);
|
||||||
VIR_FREE(devPath);
|
VIR_FREE(devPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct qemuDomainAttachDeviceMknodData {
|
||||||
|
virQEMUDriverPtr driver;
|
||||||
|
virDomainObjPtr vm;
|
||||||
|
virDomainDeviceDefPtr devDef;
|
||||||
|
const char *file;
|
||||||
|
struct stat sb;
|
||||||
|
void *acl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
struct qemuDomainAttachDeviceMknodData *data = opaque;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
virSecurityManagerPostFork(data->driver->securityManager);
|
||||||
|
|
||||||
|
if (virFileMakeParentPath(data->file) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to create %s"), data->file);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_DEBUG("Creating dev %s (%d,%d)",
|
||||||
|
data->file, major(data->sb.st_rdev), minor(data->sb.st_rdev));
|
||||||
|
if (mknod(data->file, data->sb.st_mode, data->sb.st_rdev) < 0) {
|
||||||
|
/* Because we are not removing devices on hotunplug, or
|
||||||
|
* we might be creating part of backing chain that
|
||||||
|
* already exist due to a different disk plugged to
|
||||||
|
* domain, accept EEXIST. */
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to create device %s"),
|
||||||
|
data->file);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virFileSetACLs(data->file, data->acl) < 0 &&
|
||||||
|
errno != ENOTSUP) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to set ACLs on %s"), data->file);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((virDomainDeviceType) data->devDef->type) {
|
||||||
|
case VIR_DOMAIN_DEVICE_DISK: {
|
||||||
|
virDomainDiskDefPtr def = data->devDef->data.disk;
|
||||||
|
char *tmpsrc = def->src->path;
|
||||||
|
def->src->path = (char *) data->file;
|
||||||
|
if (virSecurityManagerSetDiskLabel(data->driver->securityManager,
|
||||||
|
data->vm->def, def) < 0) {
|
||||||
|
def->src->path = tmpsrc;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
def->src->path = tmpsrc;
|
||||||
|
} 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_HOSTDEV:
|
||||||
|
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"),
|
||||||
|
data->devDef->type);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
if (ret < 0)
|
||||||
|
unlink(data->file);
|
||||||
|
virFileFreeACLs(&data->acl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDeviceDefPtr devDef,
|
||||||
|
const char *file)
|
||||||
|
{
|
||||||
|
struct qemuDomainAttachDeviceMknodData data;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
|
||||||
|
data.driver = driver;
|
||||||
|
data.vm = vm;
|
||||||
|
data.devDef = devDef;
|
||||||
|
data.file = file;
|
||||||
|
|
||||||
|
if (stat(file, &data.sb) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to access %s"), file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virFileGetACLs(file, &data.acl) < 0 &&
|
||||||
|
errno != ENOTSUP) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to get ACLs on %s"), file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virSecurityManagerPreFork(driver->securityManager) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virProcessRunInMountNamespace(vm->pid,
|
||||||
|
qemuDomainAttachDeviceMknodHelper,
|
||||||
|
&data) < 0) {
|
||||||
|
virSecurityManagerPostFork(driver->securityManager);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
virSecurityManagerPostFork(driver->securityManager);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
virFileFreeACLs(&data.acl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuDomainNamespaceSetupDisk(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk)
|
||||||
|
{
|
||||||
|
virDomainDeviceDef dev = {.type = VIR_DOMAIN_DEVICE_DISK, .data.disk = disk};
|
||||||
|
virStorageSourcePtr next;
|
||||||
|
const char *src = NULL;
|
||||||
|
struct stat sb;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (next = disk->src; next; next = next->backingStore) {
|
||||||
|
if (!next->path || !virStorageSourceIsBlockLocal(disk->src) ||
|
||||||
|
!STRPREFIX(next->path, "/dev")) {
|
||||||
|
/* Not creating device. Just continue. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(next->path, &sb) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to access %s"), src);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISBLK(sb.st_mode)) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("Disk source %s must be a block device"),
|
||||||
|
src);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainAttachDeviceMknod(driver,
|
||||||
|
vm,
|
||||||
|
&dev,
|
||||||
|
next->path) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuDomainNamespaceTeardownDisk(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
|
||||||
|
virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
||||||
|
virDomainDiskDefPtr disk ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
/* While in hotplug case we create the whole backing chain,
|
||||||
|
* here we must limit ourselves. The disk we want to remove
|
||||||
|
* might be a part of backing chain of another disk.
|
||||||
|
* If you are reading these lines and have some spare time
|
||||||
|
* you can come up with and algorithm that checks for that.
|
||||||
|
* I don't, therefore: */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -805,4 +805,12 @@ int qemuDomainCreateNamespace(virQEMUDriverPtr driver,
|
|||||||
|
|
||||||
void qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
|
void qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
|
|
||||||
|
int qemuDomainNamespaceSetupDisk(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk);
|
||||||
|
|
||||||
|
int qemuDomainNamespaceTeardownDisk(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk);
|
||||||
#endif /* __QEMU_DOMAIN_H__ */
|
#endif /* __QEMU_DOMAIN_H__ */
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#include "qemu_process.h"
|
#include "qemu_process.h"
|
||||||
#include "qemu_migration.h"
|
#include "qemu_migration.h"
|
||||||
#include "qemu_blockjob.h"
|
#include "qemu_blockjob.h"
|
||||||
|
#include "qemu_security.h"
|
||||||
|
|
||||||
#include "virerror.h"
|
#include "virerror.h"
|
||||||
#include "virlog.h"
|
#include "virlog.h"
|
||||||
@ -16146,9 +16147,9 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
|
|||||||
disk->mirror->format != VIR_STORAGE_FILE_RAW &&
|
disk->mirror->format != VIR_STORAGE_FILE_RAW &&
|
||||||
(virDomainLockDiskAttach(driver->lockManager, cfg->uri, vm,
|
(virDomainLockDiskAttach(driver->lockManager, cfg->uri, vm,
|
||||||
disk) < 0 ||
|
disk) < 0 ||
|
||||||
|
qemuDomainNamespaceSetupDisk(driver, vm, disk) < 0 ||
|
||||||
qemuSetupDiskCgroup(vm, disk) < 0 ||
|
qemuSetupDiskCgroup(vm, disk) < 0 ||
|
||||||
virSecurityManagerSetDiskLabel(driver->securityManager, vm->def,
|
qemuSecuritySetDiskLabel(driver, vm, disk) < 0))
|
||||||
disk) < 0))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
disk->src = oldsrc;
|
disk->src = oldsrc;
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "qemu_hostdev.h"
|
#include "qemu_hostdev.h"
|
||||||
#include "qemu_interface.h"
|
#include "qemu_interface.h"
|
||||||
#include "qemu_process.h"
|
#include "qemu_process.h"
|
||||||
|
#include "qemu_security.h"
|
||||||
#include "domain_audit.h"
|
#include "domain_audit.h"
|
||||||
#include "netdev_bandwidth_conf.h"
|
#include "netdev_bandwidth_conf.h"
|
||||||
#include "domain_nwfilter.h"
|
#include "domain_nwfilter.h"
|
||||||
@ -109,13 +110,15 @@ qemuDomainPrepareDisk(virQEMUDriverPtr driver,
|
|||||||
vm, disk) < 0)
|
vm, disk) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (virSecurityManagerSetDiskLabel(driver->securityManager,
|
if (qemuSecuritySetDiskLabel(driver, vm, disk) < 0)
|
||||||
vm->def, disk) < 0)
|
|
||||||
goto rollback_lock;
|
goto rollback_lock;
|
||||||
|
|
||||||
if (qemuSetupDiskCgroup(vm, disk) < 0)
|
if (qemuDomainNamespaceSetupDisk(driver, vm, disk) < 0)
|
||||||
goto rollback_label;
|
goto rollback_label;
|
||||||
|
|
||||||
|
if (qemuSetupDiskCgroup(vm, disk) < 0)
|
||||||
|
goto rollback_namespace;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -123,10 +126,13 @@ qemuDomainPrepareDisk(virQEMUDriverPtr driver,
|
|||||||
if (qemuTeardownDiskCgroup(vm, disk) < 0)
|
if (qemuTeardownDiskCgroup(vm, disk) < 0)
|
||||||
VIR_WARN("Unable to tear down cgroup access on %s",
|
VIR_WARN("Unable to tear down cgroup access on %s",
|
||||||
virDomainDiskGetSource(disk));
|
virDomainDiskGetSource(disk));
|
||||||
|
rollback_namespace:
|
||||||
|
if (qemuDomainNamespaceTeardownDisk(driver, vm, disk) < 0)
|
||||||
|
VIR_WARN("Unable to remove /dev entry for %s",
|
||||||
|
virDomainDiskGetSource(disk));
|
||||||
|
|
||||||
rollback_label:
|
rollback_label:
|
||||||
if (virSecurityManagerRestoreDiskLabel(driver->securityManager,
|
if (qemuSecurityRestoreDiskLabel(driver, vm, disk) < 0)
|
||||||
vm->def, disk) < 0)
|
|
||||||
VIR_WARN("Unable to restore security label on %s",
|
VIR_WARN("Unable to restore security label on %s",
|
||||||
virDomainDiskGetSource(disk));
|
virDomainDiskGetSource(disk));
|
||||||
|
|
||||||
@ -3588,8 +3594,7 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
|
|||||||
|
|
||||||
qemuDomainReleaseDeviceAddress(vm, &disk->info, src);
|
qemuDomainReleaseDeviceAddress(vm, &disk->info, src);
|
||||||
|
|
||||||
if (virSecurityManagerRestoreDiskLabel(driver->securityManager,
|
if (qemuSecurityRestoreDiskLabel(driver, vm, disk) < 0)
|
||||||
vm->def, disk) < 0)
|
|
||||||
VIR_WARN("Unable to restore security label on %s", src);
|
VIR_WARN("Unable to restore security label on %s", src);
|
||||||
|
|
||||||
if (qemuTeardownDiskCgroup(vm, disk) < 0)
|
if (qemuTeardownDiskCgroup(vm, disk) < 0)
|
||||||
@ -3598,6 +3603,9 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
|
|||||||
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
||||||
VIR_WARN("Unable to release lock on %s", src);
|
VIR_WARN("Unable to release lock on %s", src);
|
||||||
|
|
||||||
|
if (qemuDomainNamespaceTeardownDisk(driver, vm, disk) < 0)
|
||||||
|
VIR_WARN("Unable to remove /dev entry for %s", src);
|
||||||
|
|
||||||
dev.type = VIR_DOMAIN_DEVICE_DISK;
|
dev.type = VIR_DOMAIN_DEVICE_DISK;
|
||||||
dev.data.disk = disk;
|
dev.data.disk = disk;
|
||||||
ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));
|
ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));
|
||||||
|
@ -130,3 +130,35 @@ qemuSecurityRestoreAllLabel(virQEMUDriverPtr driver,
|
|||||||
migrated);
|
migrated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuSecuritySetDiskLabel(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk)
|
||||||
|
{
|
||||||
|
if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT)) {
|
||||||
|
/* Already handled by namespace code. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virSecurityManagerSetDiskLabel(driver->securityManager,
|
||||||
|
vm->def,
|
||||||
|
disk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuSecurityRestoreDiskLabel(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk)
|
||||||
|
{
|
||||||
|
if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT)) {
|
||||||
|
/* Already handled by namespace code. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virSecurityManagerRestoreDiskLabel(driver->securityManager,
|
||||||
|
vm->def,
|
||||||
|
disk);
|
||||||
|
}
|
||||||
|
@ -36,4 +36,12 @@ int qemuSecuritySetAllLabel(virQEMUDriverPtr driver,
|
|||||||
void qemuSecurityRestoreAllLabel(virQEMUDriverPtr driver,
|
void qemuSecurityRestoreAllLabel(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
bool migrated);
|
bool migrated);
|
||||||
|
|
||||||
|
int qemuSecuritySetDiskLabel(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk);
|
||||||
|
|
||||||
|
int qemuSecurityRestoreDiskLabel(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk);
|
||||||
#endif /* __QEMU_SECURITY_H__ */
|
#endif /* __QEMU_SECURITY_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user