aboutsummaryrefslogtreecommitdiff
path: root/include/block
diff options
context:
space:
mode:
authorGreg Kurz <groug@kaod.org>2020-10-23 17:01:10 +0200
committerKevin Wolf <kwolf@redhat.com>2020-10-27 15:26:20 +0100
commit1a6d3bd229d429879a85a9105fb84cae049d083c (patch)
treeffb7af4fb4561e489dfd196a0312a9b8d782d960 /include/block
parent46cd1e8a4752379b1b9d24d43d7be7d5aba03e76 (diff)
downloadqemu-1a6d3bd229d429879a85a9105fb84cae049d083c.zip
qemu-1a6d3bd229d429879a85a9105fb84cae049d083c.tar.gz
qemu-1a6d3bd229d429879a85a9105fb84cae049d083c.tar.bz2
block: End quiescent sections when a BDS is deleted
If a BDS gets deleted during blk_drain_all(), it might miss a call to bdrv_do_drained_end(). This means missing a call to aio_enable_external() and the AIO context remains disabled for ever. This can cause a device to become irresponsive and to disrupt the guest execution, ie. hang, loop forever or worse. This scenario is quite easy to encounter with virtio-scsi on POWER when punching multiple blockdev-create QMP commands while the guest is booting and it is still running the SLOF firmware. This happens because SLOF disables/re-enables PCI devices multiple times via IO/MEM/MASTER bits of PCI_COMMAND register after the initial probe/feature negotiation, as it tends to work with a single device at a time at various stages like probing and running block/network bootloaders without doing a full reset in-between. This naturally generates many dataplane stops and starts, and thus many drain sections that can race with blockdev_create_run(). In the end, SLOF bails out. It is somehow reproducible on x86 but it requires to generate articial dataplane start/stop activity with stop/cont QMP commands. In this case, seabios ends up looping for ever, waiting for the virtio-scsi device to send a response to a command it never received. Add a helper that pairs all previously called bdrv_do_drained_begin() with a bdrv_do_drained_end() and call it from bdrv_close(). While at it, update the "/bdrv-drain/graph-change/drain_all" test in test-bdrv-drain so that it can catch the issue. BugId: https://bugzilla.redhat.com/show_bug.cgi?id=1874441 Signed-off-by: Greg Kurz <groug@kaod.org> Message-Id: <160346526998.272601.9045392804399803158.stgit@bahia.lan> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'include/block')
-rw-r--r--include/block/block.h6
1 files changed, 6 insertions, 0 deletions
diff --git a/include/block/block.h b/include/block/block.h
index c9d7c58..4bfe3b5 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -782,6 +782,12 @@ void bdrv_drained_end(BlockDriverState *bs);
void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter);
/**
+ * End all quiescent sections started by bdrv_drain_all_begin(). This is
+ * only needed when deleting a BDS before bdrv_drain_all_end() is called.
+ */
+void bdrv_drain_all_end_quiesce(BlockDriverState *bs);
+
+/**
* End a quiescent section started by bdrv_subtree_drained_begin().
*/
void bdrv_subtree_drained_end(BlockDriverState *bs);