[libvirt] [PATCH] qemu: Fix race between async and query jobs

Jiri Denemark jdenemar at redhat.com
Thu Dec 15 10:56:23 UTC 2011


On Wed, Dec 14, 2011 at 10:05:03 -0700, Eric Blake wrote:
> On 12/14/2011 03:29 AM, Jiri Denemark wrote:
> > If an async job run on a domain will stop the domain at the end of the
> > job, a concurrently run query job can hang in qemu monitor nothing can
> > be done with that domain from this point on. An attempt to start such
> > domain results in "Timed out during operation: cannot acquire state
> > change lock" error.
...
> >  src/qemu/qemu_monitor.c |   14 ++++++++++++++
> >  1 files changed, 14 insertions(+), 0 deletions(-)
> > 
> > diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> > index 4141fb7..35648ae 100644
> > --- a/src/qemu/qemu_monitor.c
> > +++ b/src/qemu/qemu_monitor.c
> > @@ -750,6 +750,20 @@ void qemuMonitorClose(qemuMonitorPtr mon)
> >          VIR_FORCE_CLOSE(mon->fd);
> >      }
> >  
> > +    /* In case another thread is waiting for its monitor command to be
> > +     * processed, we need to wake it up with appropriate error set.
> > +     */
> > +    if (mon->msg) {
> > +        if (mon->lastError.code == VIR_ERR_OK) {
> > +            qemuReportError(VIR_ERR_OPERATION_FAILED,
> > +                            _("Qemu monitor was closed"));
> > +            virCopyLastError(&mon->lastError);
> > +            virResetLastError();
> > +        }
> > +        mon->msg->finished = 1;
> > +        virCondSignal(&mon->notify);
> > +    }
> 
> ACK.

Thanks, although I figured that qemuMonitorClose could likely be called in
error paths and this code could thus end up resetting any error we already
had. So I squashed the following patch in:

    diff --git i/src/qemu/qemu_monitor.c w/src/qemu/qemu_monitor.c
    index 35648ae..ad7e2a5 100644
    --- i/src/qemu/qemu_monitor.c
    +++ w/src/qemu/qemu_monitor.c
    @@ -755,10 +755,17 @@ void qemuMonitorClose(qemuMonitorPtr mon)
          */
         if (mon->msg) {
             if (mon->lastError.code == VIR_ERR_OK) {
    +            virErrorPtr err = virSaveLastError();
    +
                 qemuReportError(VIR_ERR_OPERATION_FAILED,
                                 _("Qemu monitor was closed"));
                 virCopyLastError(&mon->lastError);
    -            virResetLastError();
    +            if (err) {
    +                virSetError(err);
    +                virFreeError(err);
    +            } else {
    +                virResetLastError();
    +            }
             }
             mon->msg->finished = 1;
             virCondSignal(&mon->notify);

And pushed.

Jirka




More information about the libvir-list mailing list