qemu: Allow <transient> disks with images shared accross VMs

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 <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
Peter Krempa 2021-05-18 11:15:50 +02:00
parent be63e8703c
commit 75871da0ec
3 changed files with 74 additions and 1 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}