[libvirt] [PATCH v2 4/4] qemu_hotplug: try harder to eject media
Pavel Hrdina
phrdina at redhat.com
Fri Jul 3 13:51:20 UTC 2015
On Wed, Jul 01, 2015 at 05:39:49PM -0400, John Ferlan wrote:
>
>
> On 06/29/2015 11:17 AM, Pavel Hrdina wrote:
> > 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 to detect a tray_open we will fail with
> > error, from monitor. If we receive that event, we know, that the guest
> > properly reacted to the eject request, unlocked the tray and opened it.
> > In this case, we need to run the command again to actually eject the
> > media from the device. The reason to call it again is, that QEMU don't
> > wait for the guest to react and report an error, that the tray is
> > locked.
> >
> > Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1147471
> >
> > Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
> > ---
> > src/qemu/qemu_hotplug.c | 73 +++++++++++++++++++++++--------------------------
> > src/qemu/qemu_process.c | 2 ++
> > 2 files changed, 36 insertions(+), 39 deletions(-)
> >
> > diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> > index 0628964..17595b7 100644
> > --- a/src/qemu/qemu_hotplug.c
> > +++ b/src/qemu/qemu_hotplug.c
> > @@ -59,7 +59,7 @@
> >
> > VIR_LOG_INIT("qemu.qemu_hotplug");
> >
> > -#define CHANGE_MEDIA_RETRIES 10
> > +#define CHANGE_MEDIA_TIMEOUT 5000
> >
> > /* Wait up to 5 seconds for device removal to finish. */
> > unsigned long long qemuDomainRemoveDeviceWaitTime = 1000ull * 5;
> > @@ -166,12 +166,13 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
> > virStorageSourcePtr newsrc,
> > bool force)
> > {
> > - int ret = -1;
> > + int ret = -1, rc;
> > char *driveAlias = NULL;
> > qemuDomainObjPrivatePtr priv = vm->privateData;
> > - int retries = CHANGE_MEDIA_RETRIES;
> > const char *format = NULL;
> > char *sourcestr = NULL;
> > + bool ejectRetry = false;
> > + unsigned long long now;
> >
> > if (!disk->info.alias) {
> > virReportError(VIR_ERR_INTERNAL_ERROR,
> > @@ -193,36 +194,31 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
> > if (!(driveAlias = qemuDeviceDriveHostAlias(disk, priv->qemuCaps)))
> > goto error;
> >
> > - qemuDomainObjEnterMonitor(driver, vm);
> > - ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
> > - if (qemuDomainObjExitMonitor(driver, vm) < 0) {
> > - ret = -1;
> > - goto cleanup;
> > - }
> > -
> > - if (ret < 0)
> > - goto error;
> > + do {
> > + qemuDomainObjEnterMonitor(driver, vm);
> > + rc = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
> > + if (qemuDomainObjExitMonitor(driver, vm) < 0)
> > + goto cleanup;
> >
> > - 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)
> > - break;
> > + if (rc == -2) {
> > + /* we've already tried, error out */
> > + if (ejectRetry)
> > + goto error;
> > + VIR_DEBUG("tray is locked, wait for the guest to unlock "
> > + "the tray and try to eject it again");
> > + ejectRetry = true;
> > + } else if (rc < 0) {
> > + goto error;
> > + }
> >
> > - retries--;
> > - virObjectUnlock(vm);
> > - VIR_DEBUG("Waiting 500ms for tray to open. Retries left %d", retries);
> > - usleep(500 * 1000); /* sleep 500ms */
> > - virObjectLock(vm);
> > - }
> > - virObjectUnref(vm);
> > + if (virTimeMillisNow(&now) < 0)
> > + goto error;
> >
> > - if (retries <= 0) {
> > - virReportError(VIR_ERR_OPERATION_FAILED, "%s",
> > - _("Unable to eject media"));
> > - ret = -1;
> > - goto error;
> > - }
> > + while (disk->tray_status != VIR_DOMAIN_DISK_TRAY_OPEN) {
> > + if (virDomainObjWaitUntil(vm, now + CHANGE_MEDIA_TIMEOUT) != 0)
> > + goto error;
> > + }
>
> Seems this should be
>
> if (rc == -2) wait for TRAY_MOVED (need a new event)
> else wait for TRAY_OPEN
>
There is no event TRAY_OPEN or TRAY_CLOSE. QEMU has only one event,
DEVICE_TRAY_MOVED. This event is handled by qemuMonitorJSONHandleTrayChange,
which will set the reason to OPEN/CLOSE and emit a qemu monitor event. For this
qemu monitor event there is a handler called qemuProcessHandleTrayChange, where
the tray_status is set to VIR_DOMAIN_DISK_TRAY_OPEN or
VIR_DOMAIN_DISK_TRAY_CLOSED. This handler also wakes up that condition we are
waiting in this code. There is no need for a new event. We are already using
everything, that is available.
Pavel
>
> > + } while (ejectRetry && rc != 0);
> >
> > if (!virStorageSourceIsEmpty(newsrc)) {
> > if (qemuGetDriveSourceString(newsrc, conn, &sourcestr) < 0)
> > @@ -237,19 +233,17 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
> > }
> > }
> > qemuDomainObjEnterMonitor(driver, vm);
> > - ret = qemuMonitorChangeMedia(priv->mon,
> > - driveAlias,
> > - sourcestr,
> > - format);
> > - if (qemuDomainObjExitMonitor(driver, vm) < 0) {
> > - ret = -1;
> > + rc = qemuMonitorChangeMedia(priv->mon,
> > + driveAlias,
> > + sourcestr,
> > + format);
> > + if (qemuDomainObjExitMonitor(driver, vm) < 0)
> > goto cleanup;
> > - }
> > }
> >
> > - virDomainAuditDisk(vm, disk->src, newsrc, "update", ret >= 0);
> > + virDomainAuditDisk(vm, disk->src, newsrc, "update", rc >= 0);
> >
> > - if (ret < 0)
> > + if (rc < 0)
> > goto error;
> >
> > /* remove the old source from shared device list */
> > @@ -259,6 +253,7 @@ qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
> > virStorageSourceFree(disk->src);
> > disk->src = newsrc;
> > newsrc = NULL;
> > + ret = 0;
> >
> > cleanup:
> > VIR_FREE(driveAlias);
> > diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> > index a688feb..648ba00 100644
> > --- a/src/qemu/qemu_process.c
> > +++ b/src/qemu/qemu_process.c
> > @@ -1152,6 +1152,8 @@ qemuProcessHandleTrayChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> > VIR_WARN("Unable to save status on vm %s after tray moved event",
> > vm->def->name);
> > }
>
> Seems there should be some sort of DEVICE_TRAY_MOVED event... as well as
> OPEN and CLOSE
>
> John
>
> > +
> > + virDomainObjBroadcast(vm);
> > }
> >
> > virObjectUnlock(vm);
> >
More information about the libvir-list
mailing list