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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list