[libvirt] [PATCH 2/2] qemu_hotplug: Rework media changing process

Michal Privoznik mprivozn at redhat.com
Fri Jan 25 12:20:43 UTC 2013


https://bugzilla.redhat.com/show_bug.cgi?id=892289

It seems like with new udev within guest OS, the tray is locked,
so we need to:
- 'eject'
- wait shortly
- 'change'

However, the 'wait shortly' step is better to be substituted with
active polling on tray_open attribute on the device. Moreover,
even when doing bare 'eject', we should check for 'tray_open' as
guest may have locked the tray.
---
 src/qemu/qemu_hotplug.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 8103183..f373c44 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -48,6 +48,7 @@
 #include "virstoragefile.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
+#define CHANGE_MEDIA_RETRIES 10
 
 int qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
                                    virDomainObjPtr vm,
@@ -59,6 +60,10 @@ int qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
     int ret;
     char *driveAlias = NULL;
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    virHashTablePtr table = NULL;
+    struct qemuDomainDiskInfo *info = NULL;
+    int retries = CHANGE_MEDIA_RETRIES;
+    virErrorPtr origError = NULL;
 
     for (i = 0 ; i < vm->def->ndisks ; i++) {
         if (vm->def->disks[i]->bus == disk->bus &&
@@ -86,7 +91,7 @@ int qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
         origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Removable media not supported for %s device"),
-                        virDomainDiskDeviceTypeToString(disk->device));
+                       virDomainDiskDeviceTypeToString(disk->device));
         return -1;
     }
 
@@ -105,8 +110,45 @@ int qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
         goto error;
 
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
+    ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
+
+    /* we don't want to report errors from media tray_open polling */
+    origError = virSaveLastError();
+    while (retries--) {
+        virHashFree(table);
+        table = qemuMonitorGetBlockInfo(priv->mon);
+        if (!table)
+            goto exit_monitor;
+
+        info = qemuMonitorBlockInfoLookup(table, origdisk->info.alias);
+        if (!info) {
+            virHashFree(table);
+            goto exit_monitor;
+        }
+
+        if (info->tray_open)
+            break;
+
+        usleep(200 * 1000); /* sleep 200ms */
+    }
+    virHashFree(table);
+
     if (disk->src) {
+        /* deliberately don't depend on 'ret' as 'eject' may have failed for the
+         * fist time and we are gonna check the drive state anyway */
         const char *format = NULL;
+
+        /* We haven't succeeded yet */
+        ret = -1;
+
+        if (retries <= 0) {
+            virFreeError(origError);
+            origError = NULL;
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("Unable to eject media before changing it"));
+            goto exit_monitor;
+        }
+
         if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
             if (disk->format > 0)
                 format = virStorageFileFormatTypeToString(disk->format);
@@ -116,8 +158,11 @@ int qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
         ret = qemuMonitorChangeMedia(priv->mon,
                                      driveAlias,
                                      disk->src, format);
-    } else {
-        ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
+    }
+exit_monitor:
+    if (origError) {
+        virSetError(origError);
+        virFreeError(origError);
     }
     qemuDomainObjExitMonitorWithDriver(driver, vm);
 
-- 
1.8.0.2




More information about the libvir-list mailing list