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