From: Peter Krempa Date: Thu, 13 May 2021 11:05:27 +0000 (+0200) Subject: qemuDomainAttachDiskGeneric: Implement hotplug of disk X-Git-Tag: v7.4.0-rc1~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e94002d2ace4e4a6dbfc13a84fdab28f22c5c4a;p=thirdparty%2Flibvirt.git qemuDomainAttachDiskGeneric: Implement hotplug of disk Add code which creates the transient overlay after hotplugging the disk backend before attaching the disk frontend. The state of the topmost image is modified to be already read-only to prevent the need to open the image in read-write mode. Signed-off-by: Peter Krempa Reviewed-by: Ján Tomko Reviewed-by: Pavel Hrdina --- diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index d1908fbce6..8aba079a7d 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -34,6 +34,7 @@ #include "qemu_process.h" #include "qemu_security.h" #include "qemu_block.h" +#include "qemu_snapshot.h" #include "domain_audit.h" #include "netdev_bandwidth_conf.h" #include "domain_nwfilter.h" @@ -685,6 +686,25 @@ qemuDomainChangeEjectableMedia(virQEMUDriver *driver, } +static qemuSnapshotDiskContext * +qemuDomainAttachDiskGenericTransient(virDomainObj *vm, + virDomainDiskDef *disk, + GHashTable *blockNamedNodeData) +{ + g_autoptr(qemuSnapshotDiskContext) snapctxt = NULL; + g_autoptr(virDomainSnapshotDiskDef) snapdiskdef = NULL; + + snapdiskdef = qemuSnapshotGetTransientDiskDef(disk, vm->def->name); + snapctxt = qemuSnapshotDiskContextNew(1, vm, QEMU_ASYNC_JOB_NONE); + + if (qemuSnapshotDiskPrepareOne(snapctxt, disk, snapdiskdef, + blockNamedNodeData, false, false) < 0) + return NULL; + + return g_steal_pointer(&snapctxt); +} + + /** * qemuDomainAttachDiskGeneric: * @@ -701,6 +721,11 @@ qemuDomainAttachDiskGeneric(virQEMUDriver *driver, bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV); bool extensionDeviceAttached = false; int rc; + g_autoptr(qemuSnapshotDiskContext) transientDiskSnapshotCtxt = NULL; + bool origReadonly = disk->src->readonly; + + if (disk->transient) + disk->src->readonly = true; if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) { if (!(data = qemuBuildStorageSourceChainAttachPrepareChardev(disk))) @@ -723,6 +748,8 @@ qemuDomainAttachDiskGeneric(virQEMUDriver *driver, return -1; } + disk->src->readonly = origReadonly; + qemuDomainObjEnterMonitor(driver, vm); rc = qemuBlockStorageSourceChainAttach(priv->mon, data); @@ -733,6 +760,25 @@ qemuDomainAttachDiskGeneric(virQEMUDriver *driver, if (rc < 0) goto rollback; + if (disk->transient) { + g_autoptr(qemuBlockStorageSourceAttachData) backend = NULL; + g_autoptr(GHashTable) blockNamedNodeData = NULL; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE))) + goto rollback; + + if (!(transientDiskSnapshotCtxt = qemuDomainAttachDiskGenericTransient(vm, disk, blockNamedNodeData))) + goto rollback; + + + if (qemuSnapshotDiskCreate(transientDiskSnapshotCtxt) < 0) + goto rollback; + + QEMU_DOMAIN_DISK_PRIVATE(disk)->transientOverlayCreated = true; + backend = qemuBlockStorageSourceDetachPrepare(disk->src, NULL); + ignore_value(VIR_INSERT_ELEMENT(data->srcdata, 0, data->nsrcdata, backend)); + } + if (!(devstr = qemuBuildDiskDeviceStr(vm->def, disk, priv->qemuCaps))) goto rollback; @@ -937,12 +983,6 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriver *driver, return -1; } - if (disk->transient) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("transient disk hotplug isn't supported")); - return -1; - } - if (virDomainDiskTranslateSourcePool(disk) < 0) goto cleanup;