From 75871da0ecb8b552f9e304d0f83e216839bbf82d Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 18 May 2021 11:15:50 +0200 Subject: [PATCH] qemu: Allow disks with images shared accross VMs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement this behaviour by skipping the disks on traditional commandline and hotplug them before resuming CPUs. That allows to use the support for hotplugging of transient disks which inherently allows sharing of the backing image as we open it read-only. This commit implements the validation code to allow it only with buses supporting hotplug and the hotplug code while starting up the VM. When we have such disk we need to issue a system-reset so that firmware tables are regenerated to allow booting from such device. Signed-off-by: Peter Krempa Reviewed-by: Ján Tomko Reviewed-by: Pavel Hrdina --- src/qemu/qemu_command.c | 6 ++++++ src/qemu/qemu_process.c | 45 +++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_validate.c | 24 +++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f197d7c7de..4ed82ed570 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2164,6 +2164,12 @@ qemuBuildDisksCommandLine(virCommand *cmd, for (i = 0; i < def->ndisks; i++) { virDomainDiskDef *disk = def->disks[i]; + /* transient disks with shared backing image will be hotplugged after + * the VM is started */ + if (disk->transient && + disk->transientShareBacking == VIR_TRISTATE_BOOL_YES) + continue; + if (qemuBuildDiskCommandLine(cmd, def, disk, qemuCaps) < 0) return -1; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1b22bd1256..9b069fe7ce 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -7016,7 +7016,8 @@ qemuProcessSetupDisksTransientSnapshot(virDomainObj *vm, virDomainDiskDef *domdisk = vm->def->disks[i]; g_autoptr(virDomainSnapshotDiskDef) snapdisk = NULL; - if (!domdisk->transient) + if (!domdisk->transient || + domdisk->transientShareBacking == VIR_TRISTATE_BOOL_YES) continue; /* validation code makes sure that we do this only for local disks @@ -7048,6 +7049,45 @@ qemuProcessSetupDisksTransientSnapshot(virDomainObj *vm, } +static int +qemuProcessSetupDisksTransientHotplug(virDomainObj *vm, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivate *priv = vm->privateData; + bool hasHotpluggedDisk = false; + size_t i; + + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDef *domdisk = vm->def->disks[i]; + + if (!domdisk->transient || + domdisk->transientShareBacking != VIR_TRISTATE_BOOL_YES) + continue; + + if (qemuDomainAttachDiskGeneric(priv->driver, vm, domdisk, asyncJob) < 0) + return -1; + + hasHotpluggedDisk = true; + } + + /* in order to allow booting from such disks we need to issue a system-reset + * so that the firmware tables recording bootable devices are regerated */ + if (hasHotpluggedDisk) { + int rc; + + if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0) + return -1; + + rc = qemuMonitorSystemReset(priv->mon); + + if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0) + return -1; + } + + return 0; +} + + static int qemuProcessSetupDisksTransient(virDomainObj *vm, qemuDomainAsyncJob asyncJob) @@ -7060,6 +7100,9 @@ qemuProcessSetupDisksTransient(virDomainObj *vm, if (qemuProcessSetupDisksTransientSnapshot(vm, asyncJob) < 0) return -1; + if (qemuProcessSetupDisksTransientHotplug(vm, asyncJob) < 0) + return -1; + return 0; } diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index fb8af31cc4..669c45b3c5 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -2980,6 +2980,30 @@ qemuValidateDomainDeviceDefDiskTransient(const virDomainDiskDef *disk, return -1; } + if (disk->transientShareBacking == VIR_TRISTATE_BOOL_YES) { + /* sharing the backing file requires hotplug of the disk in the qemu driver */ + switch (disk->bus) { + case VIR_DOMAIN_DISK_BUS_USB: + case VIR_DOMAIN_DISK_BUS_VIRTIO: + case VIR_DOMAIN_DISK_BUS_SCSI: + break; + + case VIR_DOMAIN_DISK_BUS_IDE: + case VIR_DOMAIN_DISK_BUS_FDC: + case VIR_DOMAIN_DISK_BUS_XEN: + case VIR_DOMAIN_DISK_BUS_UML: + case VIR_DOMAIN_DISK_BUS_SATA: + case VIR_DOMAIN_DISK_BUS_SD: + case VIR_DOMAIN_DISK_BUS_NONE: + case VIR_DOMAIN_DISK_BUS_LAST: + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk bus '%s' doesn't support transiend disk backing image sharing"), + virDomainDiskBusTypeToString(disk->bus)); + return -1; + } + } + return 0; }