]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: hotplug: Implement removable media change for -blockdev
authorPeter Krempa <pkrempa@redhat.com>
Fri, 13 Jul 2018 16:06:09 +0000 (18:06 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 21 Aug 2018 13:46:06 +0000 (15:46 +0200)
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@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/qemu/qemu_hotplug.c

index 93139b0d1509fd5b3ae9dabb448ef6eb348f070e..bd1942efe7dac066e31b1b01883081c0bfc21a73 100644 (file)
@@ -618,6 +618,94 @@ 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->qomName, 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->qomName);
+
+    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->qomName,
+                                                 nodename);
+    }
+
+    if (rc == 0)
+        rc = qemuMonitorBlockdevTrayClose(priv->mon, diskPriv->qomName);
+
+    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    qemuHotplugDiskSourceDataFree(newbackend);
+    qemuHotplugDiskSourceDataFree(oldbackend);
+    /* caller handles correct exchange of sources */
+    disk->src = oldsrc;
+    return ret;
+}
+
+
 /**
  * qemuDomainChangeEjectableMedia:
  * @driver: qemu driver structure
@@ -640,6 +728,7 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
                                virStorageSourcePtr newsrc,
                                bool force)
 {
+    qemuDomainObjPrivatePtr priv = vm->privateData;
     int ret = -1;
     int rc;
 
@@ -649,7 +738,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);