1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-28 11:21:44 +03:00

qemu: Forcibly mknod() even if it exists

Another weird bug appeared concerning qemu namespaces. Basically
the problem is as follows:

1) Issue an API that causes libvirt to create a node in domain's
   namespace, say /dev/nvme0n1 with 8:0 as major:minor (the API can
   be attach-disk for instance). Or simply create the node from a
   console by hand.

2) Detach the disk from qemu.

3) Do something that makes /dev/nvme0n1 change it's minor number.

4) Try to attach the disk again.

The problem is, in a few cases - like disk-detach - we don't
remove the corresponding /dev node from the mount namespace
(because it may be used by some other disk's backing chain). But
this creates a problem, because if the node changes its MAJ:MIN
numbers we don't propagate the change into the domain's
namespace. We do plain mknod() and ignore EEXIST which obviously
is not enough because it doesn't guarantee that the node has
updated MAJ:MIN pair.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1752978

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Michal Privoznik 2019-11-08 09:41:35 +01:00
parent 73197f9803
commit cdd8a6690e

View File

@ -13203,16 +13203,14 @@ qemuDomainCreateDeviceRecursive(const char *device,
allow_noent, ttl - 1) < 0) allow_noent, ttl - 1) < 0)
goto cleanup; goto cleanup;
} else if (isDev) { } else if (isDev) {
if (create && if (create) {
mknod(devicePath, sb.st_mode, sb.st_rdev) < 0) { unlink(devicePath);
if (errno == EEXIST) { if (mknod(devicePath, sb.st_mode, sb.st_rdev) < 0) {
ret = 0;
} else {
virReportSystemError(errno, virReportSystemError(errno,
_("Failed to make device %s"), _("Failed to make device %s"),
devicePath); devicePath);
goto cleanup;
} }
goto cleanup;
} }
} else if (isReg) { } else if (isReg) {
if (create && if (create &&
@ -13996,17 +13994,12 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED,
} else if (isDev) { } else if (isDev) {
VIR_DEBUG("Creating dev %s (%d,%d)", VIR_DEBUG("Creating dev %s (%d,%d)",
data->file, major(data->sb.st_rdev), minor(data->sb.st_rdev)); data->file, major(data->sb.st_rdev), minor(data->sb.st_rdev));
unlink(data->file);
if (mknod(data->file, data->sb.st_mode, data->sb.st_rdev) < 0) { if (mknod(data->file, data->sb.st_mode, data->sb.st_rdev) < 0) {
/* Because we are not removing devices on hotunplug, or virReportSystemError(errno,
* we might be creating part of backing chain that _("Unable to create device %s"),
* already exist due to a different disk plugged to data->file);
* domain, accept EEXIST. */ goto cleanup;
if (errno != EEXIST) {
virReportSystemError(errno,
_("Unable to create device %s"),
data->file);
goto cleanup;
}
} else { } else {
delDevice = true; delDevice = true;
} }