Use the new APIs which allow to manipulate the tray and media separately
and also allow using a nodename to refer to a media to implement media
changing.
With the new approach we don't have to call eject twice as the media is
removed by calling qemuMonitorBlockdevMediumRemove.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/qemu/qemu_hotplug.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 3eddb0043e..97a486f2ea 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -618,6 +618,93 @@ qemuHotplugDiskSourceRemove(qemuMonitorPtr mon,
}
+/**
+ * qemuDomainChangeMediaBlockdev:
+ * @driver: qemu driver structure
+ * @vm: domain definition
+ * @disk: disk definition to change the source of
+ * @newsrc: new disk source to change to
+ * @force: force the change of media
+ *
+ * Change the media in an ejectable device to the one described by
+ * @newsrc. This function also removes the old source from the
+ * shared device table if appropriate. Note that newsrc is consumed
+ * on success and the old source is freed on success.
+ *
+ * Returns 0 on success, -1 on error and reports libvirt error
+ */
+static int
+qemuDomainChangeMediaBlockdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDiskDefPtr disk,
+ virStorageSourcePtr newsrc,
+ bool force)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+ qemuHotplugDiskSourceDataPtr newbackend = NULL;
+ qemuHotplugDiskSourceDataPtr oldbackend = NULL;
+ virStorageSourcePtr oldsrc = disk->src;
+ char *nodename = NULL;
+ int rc;
+ int ret = -1;
+
+ if (!virStorageSourceIsEmpty(disk->src) &&
+ !(oldbackend = qemuHotplugDiskSourceRemovePrepare(disk, priv->qemuCaps)))
+ goto cleanup;
+
+ disk->src = newsrc;
+ if (!virStorageSourceIsEmpty(disk->src)) {
+ if (!(newbackend = qemuHotplugDiskSourceAttachPrepare(disk,
+ priv->qemuCaps)))
+ goto cleanup;
+
+ if (qemuDomainDiskGetBackendAlias(disk, priv->qemuCaps, &nodename) <
0)
+ goto cleanup;
+ }
+
+ if (diskPriv->tray && disk->tray_status != VIR_DOMAIN_DISK_TRAY_OPEN)
{
+ qemuDomainObjEnterMonitor(driver, vm);
+ rc = qemuMonitorBlockdevTrayOpen(priv->mon, diskPriv->backendQomName,
force);
+ if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+ goto cleanup;
+
+ if (!force && qemuHotplugWaitForTrayEject(vm, disk) < 0)
+ goto cleanup;
+ }
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ rc = qemuMonitorBlockdevMediumRemove(priv->mon, diskPriv->backendQomName);
+
+ if (rc == 0 && oldbackend)
+ qemuHotplugDiskSourceRemove(priv->mon, oldbackend);
+
+ if (newbackend && nodename) {
+ if (rc == 0)
+ rc = qemuHotplugDiskSourceAttach(priv->mon, newbackend);
+
+ if (rc == 0)
+ rc = qemuMonitorBlockdevMediumInsert(priv->mon,
+ diskPriv->backendQomName,
+ nodename);
+ }
+
+ if (rc == 0)
+ rc = qemuMonitorBlockdevTrayClose(priv->mon, diskPriv->backendQomName);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+ goto cleanup;
+
+ cleanup:
+ qemuHotplugDiskSourceDataFree(newbackend);
+ qemuHotplugDiskSourceDataFree(oldbackend);
+ /* caller handles correct exchange of sources */
+ disk->src = oldsrc;
+ return ret;
+}
+
+
/**
* qemuDomainChangeEjectableMedia:
* @driver: qemu driver structure
@@ -640,6 +727,7 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
virStorageSourcePtr newsrc,
bool force)
{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1;
int rc;
@@ -649,7 +737,10 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
if (qemuHotplugAttachManagedPR(driver, vm, newsrc, QEMU_ASYNC_JOB_NONE) < 0)
goto cleanup;
- rc = qemuDomainChangeMediaLegacy(driver, vm, disk, newsrc, force);
+ if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
+ rc = qemuDomainChangeMediaBlockdev(driver, vm, disk, newsrc, force);
+ else
+ rc = qemuDomainChangeMediaLegacy(driver, vm, disk, newsrc, force);
virDomainAuditDisk(vm, disk->src, newsrc, "update", rc >= 0);
--
2.16.2