render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
7a3408
From cc6d958b1ba9efb26ca5b28c575369e335b1e7a0 Mon Sep 17 00:00:00 2001
7a3408
Message-Id: <cc6d958b1ba9efb26ca5b28c575369e335b1e7a0@dist-git>
7a3408
From: Pavel Hrdina <phrdina@redhat.com>
7a3408
Date: Fri, 10 Jul 2015 12:39:32 +0200
7a3408
Subject: [PATCH] qemu_hotplug: try harder to eject media
7a3408
7a3408
Some guests lock the tray and QEMU eject command will simply fail to
7a3408
eject the media.  But the guest OS can handle this attempt to eject the
7a3408
media and can unlock the tray and open it. In this case, we should try
7a3408
again to actually eject the media.
7a3408
7a3408
If the first attempt fails to detect a tray_open we will fail with
7a3408
error, from monitor.  If we receive that event, we know, that the guest
7a3408
properly reacted to the eject request, unlocked the tray and opened it.
7a3408
In this case, we need to run the command again to actually eject the
7a3408
media from the device.  The reason to call it again is, that QEMU
7a3408
doesn't wait for the guest to react and report an error, that the tray
7a3408
is locked.
7a3408
7a3408
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1147471
7a3408
7a3408
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
7a3408
(cherry picked from commit 28554080ecbcd1e57266b29734feb76799c2ee48)
7a3408
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
7a3408
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
7a3408
---
7a3408
 src/qemu/qemu_hotplug.c | 73 +++++++++++++++++++++++--------------------------
7a3408
 src/qemu/qemu_process.c |  2 ++
7a3408
 2 files changed, 36 insertions(+), 39 deletions(-)
7a3408
7a3408
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
7a3408
index 79338cf..1ea397f 100644
7a3408
--- a/src/qemu/qemu_hotplug.c
7a3408
+++ b/src/qemu/qemu_hotplug.c
7a3408
@@ -59,7 +59,7 @@
7a3408
 
7a3408
 VIR_LOG_INIT("qemu.qemu_hotplug");
7a3408
 
7a3408
-#define CHANGE_MEDIA_RETRIES 10
7a3408
+#define CHANGE_MEDIA_TIMEOUT 5000
7a3408
 
7a3408
 /* Wait up to 5 seconds for device removal to finish. */
7a3408
 unsigned long long qemuDomainRemoveDeviceWaitTime = 1000ull * 5;
7a3408
@@ -166,12 +166,13 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
7a3408
                                virStorageSourcePtr newsrc,
7a3408
                                bool force)
7a3408
 {
7a3408
-    int ret = -1;
7a3408
+    int ret = -1, rc;
7a3408
     char *driveAlias = NULL;
7a3408
     qemuDomainObjPrivatePtr priv = vm->privateData;
7a3408
-    int retries = CHANGE_MEDIA_RETRIES;
7a3408
     const char *format = NULL;
7a3408
     char *sourcestr = NULL;
7a3408
+    bool ejectRetry = false;
7a3408
+    unsigned long long now;
7a3408
 
7a3408
     if (!disk->info.alias) {
7a3408
         virReportError(VIR_ERR_INTERNAL_ERROR,
7a3408
@@ -193,36 +194,31 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
7a3408
     if (!(driveAlias = qemuDeviceDriveHostAlias(disk, priv->qemuCaps)))
7a3408
         goto error;
7a3408
 
7a3408
-    qemuDomainObjEnterMonitor(driver, vm);
7a3408
-    ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
7a3408
-    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
7a3408
-        ret = -1;
7a3408
-        goto cleanup;
7a3408
-    }
7a3408
+    do {
7a3408
+        qemuDomainObjEnterMonitor(driver, vm);
7a3408
+        rc = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
7a3408
+        if (qemuDomainObjExitMonitor(driver, vm) < 0)
7a3408
+            goto cleanup;
7a3408
 
7a3408
-    if (ret < 0)
7a3408
-        goto error;
7a3408
+        if (rc == -2) {
7a3408
+            /* we've already tried, error out */
7a3408
+            if (ejectRetry)
7a3408
+                goto error;
7a3408
+            VIR_DEBUG("tray is locked, wait for the guest to unlock "
7a3408
+                      "the tray and try to eject it again");
7a3408
+            ejectRetry = true;
7a3408
+        } else if (rc < 0) {
7a3408
+            goto error;
7a3408
+        }
7a3408
 
7a3408
-    virObjectRef(vm);
7a3408
-    /* we don't want to report errors from media tray_open polling */
7a3408
-    while (retries) {
7a3408
-        if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)
7a3408
-            break;
7a3408
+        if (virTimeMillisNow(&now) < 0)
7a3408
+            goto error;
7a3408
 
7a3408
-        retries--;
7a3408
-        virObjectUnlock(vm);
7a3408
-        VIR_DEBUG("Waiting 500ms for tray to open. Retries left %d", retries);
7a3408
-        usleep(500 * 1000); /* sleep 500ms */
7a3408
-        virObjectLock(vm);
7a3408
-    }
7a3408
-    virObjectUnref(vm);
7a3408
-
7a3408
-    if (retries <= 0) {
7a3408
-        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
7a3408
-                       _("Unable to eject media"));
7a3408
-        ret = -1;
7a3408
-        goto error;
7a3408
-    }
7a3408
+        while (disk->tray_status != VIR_DOMAIN_DISK_TRAY_OPEN) {
7a3408
+            if (virDomainObjWaitUntil(vm, now + CHANGE_MEDIA_TIMEOUT) != 0)
7a3408
+                goto error;
7a3408
+        }
7a3408
+    } while (ejectRetry && rc != 0);
7a3408
 
7a3408
     if (!virStorageSourceIsEmpty(newsrc)) {
7a3408
         if (qemuGetDriveSourceString(newsrc, conn, &sourcestr) < 0)
7a3408
@@ -237,19 +233,17 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
7a3408
             }
7a3408
         }
7a3408
         qemuDomainObjEnterMonitor(driver, vm);
7a3408
-        ret = qemuMonitorChangeMedia(priv->mon,
7a3408
-                                     driveAlias,
7a3408
-                                     sourcestr,
7a3408
-                                     format);
7a3408
-        if (qemuDomainObjExitMonitor(driver, vm) < 0) {
7a3408
-            ret = -1;
7a3408
+        rc = qemuMonitorChangeMedia(priv->mon,
7a3408
+                                    driveAlias,
7a3408
+                                    sourcestr,
7a3408
+                                    format);
7a3408
+        if (qemuDomainObjExitMonitor(driver, vm) < 0)
7a3408
             goto cleanup;
7a3408
-        }
7a3408
     }
7a3408
 
7a3408
-    virDomainAuditDisk(vm, disk->src, newsrc, "update", ret >= 0);
7a3408
+    virDomainAuditDisk(vm, disk->src, newsrc, "update", rc >= 0);
7a3408
 
7a3408
-    if (ret < 0)
7a3408
+    if (rc < 0)
7a3408
         goto error;
7a3408
 
7a3408
     /* remove the old source from shared device list */
7a3408
@@ -259,6 +253,7 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
7a3408
     virStorageSourceFree(disk->src);
7a3408
     disk->src = newsrc;
7a3408
     newsrc = NULL;
7a3408
+    ret = 0;
7a3408
 
7a3408
  cleanup:
7a3408
     VIR_FREE(driveAlias);
7a3408
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
7a3408
index 9f1ae5a..c5f467b 100644
7a3408
--- a/src/qemu/qemu_process.c
7a3408
+++ b/src/qemu/qemu_process.c
7a3408
@@ -1155,6 +1155,8 @@ qemuProcessHandleTrayChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
7a3408
             VIR_WARN("Unable to save status on vm %s after tray moved event",
7a3408
                      vm->def->name);
7a3408
         }
7a3408
+
7a3408
+        virDomainObjBroadcast(vm);
7a3408
     }
7a3408
 
7a3408
     virObjectUnlock(vm);
7a3408
-- 
7a3408
2.4.5
7a3408