]> git.ipfire.org Git - thirdparty/qemu.git/commit
mirror: Fix coroutine reentrance
authorKevin Wolf <kwolf@redhat.com>
Thu, 13 Aug 2015 08:41:50 +0000 (10:41 +0200)
committerMichael Roth <mdroth@linux.vnet.ibm.com>
Sat, 17 Oct 2015 23:13:21 +0000 (18:13 -0500)
commit0de7d2b793f2e3cfeedfc822429a6bce6e48bda3
tree293d53d2b264d38929bb627b2872487d6af14f85
parentf399ea092ea46c82b819ba1fdbcb082eb8019a32
mirror: Fix coroutine reentrance

This fixes a regression introduced by commit dcfb3beb ("mirror: Do zero
write on target if sectors not allocated"), which was reported to cause
aborts with the message "Co-routine re-entered recursively".

The cause for this bug is the following code in mirror_iteration_done():

    if (s->common.busy) {
        qemu_coroutine_enter(s->common.co, NULL);
    }

This has always been ugly because - unlike most places that reenter - it
doesn't have a specific yield that it pairs with, but is more
uncontrolled.  What we really mean here is "reenter the coroutine if
it's in one of the four explicit yields in mirror.c".

This used to be equivalent with s->common.busy because neither
mirror_run() nor mirror_iteration() call any function that could yield.
However since commit dcfb3beb this doesn't hold true any more:
bdrv_get_block_status_above() can yield.

So what happens is that bdrv_get_block_status_above() wants to take a
lock that is already held, so it adds itself to the queue of waiting
coroutines and yields. Instead of being woken up by the unlock function,
however, it gets woken up by mirror_iteration_done(), which is obviously
wrong.

In most cases the code actually happens to cope fairly well with such
cases, but in this specific case, the unlock must already have scheduled
the coroutine for wakeup when mirror_iteration_done() reentered it. And
then the coroutine happened to process the scheduled restarts and tried
to reenter itself recursively.

This patch fixes the problem by pairing the reenter in
mirror_iteration_done() with specific yields instead of abusing
s->common.busy.

Cc: qemu-stable@nongnu.org
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Message-id: 1439455310-11263-1-git-send-email-kwolf@redhat.com
Signed-off-by: Jeff Cody <jcody@redhat.com>
(cherry picked from commit e424aff5f307227b1c2512bbb8ece891bb895cef)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
block/mirror.c