Skip to content
  • Sergio Lopez's avatar
    util/async: use qemu_aio_coroutine_enter in co_schedule_bh_cb · 6808ae04
    Sergio Lopez authored
    
    
    AIO Coroutines shouldn't by managed by an AioContext different than the
    one assigned when they are created. aio_co_enter avoids entering a
    coroutine from a different AioContext, calling aio_co_schedule instead.
    
    Scheduled coroutines are then entered by co_schedule_bh_cb using
    qemu_coroutine_enter, which just calls qemu_aio_coroutine_enter with the
    current AioContext obtained with qemu_get_current_aio_context.
    Eventually, co->ctx will be set to the AioContext passed as an argument
    to qemu_aio_coroutine_enter.
    
    This means that, if an IO Thread's AioConext is being processed by the
    Main Thread (due to aio_poll being called with a BDS AioContext, as it
    happens in AIO_WAIT_WHILE among other places), the AioContext from some
    coroutines may be wrongly replaced with the one from the Main Thread.
    
    This is the root cause behind some crashes, mainly triggered by the
    drain code at block/io.c. The most common are these abort and failed
    assertion:
    
    util/async.c:aio_co_schedule
    456     if (scheduled) {
    457         fprintf(stderr,
    458                 "%s: Co-routine was already scheduled in '%s'\n",
    459                 __func__, scheduled);
    460         abort();
    461     }
    
    util/qemu-coroutine-lock.c:
    286     assert(mutex->holder == self);
    
    But it's also known to cause random errors at different locations, and
    even SIGSEGV with broken coroutine backtraces.
    
    By using qemu_aio_coroutine_enter directly in co_schedule_bh_cb, we can
    pass the correct AioContext as an argument, making sure co->ctx is not
    wrongly altered.
    
    Signed-off-by: default avatarSergio Lopez <slp@redhat.com>
    Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
    6808ae04