[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH for-2.9 4/5] block: Drain BH in bdrv_drained_begin
From: |
Fam Zheng |
Subject: |
[Qemu-devel] [PATCH for-2.9 4/5] block: Drain BH in bdrv_drained_begin |
Date: |
Thu, 6 Apr 2017 22:25:26 +0800 |
During block job completion, nothing is preventing
block_job_defer_to_main_loop_bh from being called in a nested
aio_poll(), which is a trouble, such as in this code path:
qmp_block_commit
commit_active_start
bdrv_reopen
bdrv_reopen_multiple
bdrv_reopen_prepare
bdrv_flush
aio_poll
aio_bh_poll
aio_bh_call
block_job_defer_to_main_loop_bh
stream_complete
bdrv_reopen
block_job_defer_to_main_loop_bh is the last step of the stream job,
which should have been "paused" by the bdrv_drained_begin/end in
bdrv_reopen_multiple, but it is not done because it's in the form of a
main loop BH.
Similar to why block jobs should be paused between drained_begin and
drained_end, BHs they schedule must be excluded as well. To achieve
this, this patch forces draining the BH before leaving bdrv_drained_begin().
Signed-off-by: Fam Zheng <address@hidden>
---
block/io.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/block/io.c b/block/io.c
index 2709a70..b9cfd18 100644
--- a/block/io.c
+++ b/block/io.c
@@ -228,7 +228,12 @@ void bdrv_drained_begin(BlockDriverState *bs)
bdrv_parent_drained_begin(bs);
}
- bdrv_drain_recurse(bs);
+ while (true) {
+ if (!bdrv_drain_recurse(bs) &&
+ !aio_poll(bdrv_get_aio_context(bs), false)) {
+ break;
+ }
+ }
}
void bdrv_drained_end(BlockDriverState *bs)
--
2.9.3