Some guests lock the tray and QEMU eject command will simply fail to
eject the media. But the guest OS can handle this attempt to eject the
media and can unlock the tray and open it. In this case, we should try
again to actually eject the media.
If the first attempt fails we will wait for tray to open and try again
to eject the media, but if the second attempt fails, returns with error.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1147471
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
src/qemu/qemu_hotplug.c | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 0628964..0cebaad 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -201,13 +201,17 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
}
if (ret < 0)
- goto error;
+ VIR_DEBUG("tray is probably locked, wait for the guest to unlock "
+ "the tray and open it");
virObjectRef(vm);
/* we don't want to report errors from media tray_open polling */
while (retries) {
- if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)
+ if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN) {
+ ret = 0;
+ virResetLastError();
break;
+ }
retries--;
virObjectUnlock(vm);
@@ -218,10 +222,29 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
virObjectUnref(vm);
if (retries <= 0) {
- virReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("Unable to eject media"));
- ret = -1;
+ /* Report a new error only if the first attempt don't fail and we don't
+ * receive VIR_DOMAIN_DISK_TRAY_OPEN event, otherwise report the error
+ * from first attempt. */
+ if (ret == 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Unable to eject media"));
+ ret = -1;
+ }
goto error;
+ } else {
+ /* QEMU will send eject request to guest, but if the tray is locked,
+ * always returns with error. However the guest can handle the eject
+ * request, unlock the tray and open it. In case this happens, we
+ * should try to eject the media once more. */
+ qemuDomainObjEnterMonitor(driver, vm);
+ ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
+ if (qemuDomainObjExitMonitor(driver, vm) < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (ret < 0)
+ goto error;
}
if (!virStorageSourceIsEmpty(newsrc)) {
--
2.4.4