diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/commit.c | 8 | ||||
-rw-r--r-- | block/io.c | 164 | ||||
-rw-r--r-- | block/qcow2.c | 51 | ||||
-rw-r--r-- | block/qcow2.h | 3 | ||||
-rw-r--r-- | block/replication.c | 6 |
5 files changed, 132 insertions, 100 deletions
diff --git a/block/commit.c b/block/commit.c index c532755..bb6c904 100644 --- a/block/commit.c +++ b/block/commit.c @@ -277,7 +277,6 @@ void commit_start(const char *job_id, BlockDriverState *bs, const char *filter_node_name, Error **errp) { CommitBlockJob *s; - BlockReopenQueue *reopen_queue = NULL; int orig_base_flags; BlockDriverState *iter; BlockDriverState *commit_top_bs = NULL; @@ -299,12 +298,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, /* convert base to r/w, if necessary */ orig_base_flags = bdrv_get_flags(base); if (!(orig_base_flags & BDRV_O_RDWR)) { - reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL, - orig_base_flags | BDRV_O_RDWR); - } - - if (reopen_queue) { - bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err); + bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); goto fail; @@ -40,22 +40,28 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, BdrvRequestFlags flags); -void bdrv_parent_drained_begin(BlockDriverState *bs) +void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c, *next; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { + if (c == ignore) { + continue; + } if (c->role->drained_begin) { c->role->drained_begin(c); } } } -void bdrv_parent_drained_end(BlockDriverState *bs) +void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c, *next; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { + if (c == ignore) { + continue; + } if (c->role->drained_end) { c->role->drained_end(c); } @@ -134,29 +140,13 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) assert(old >= 1); } -/* Check if any requests are in-flight (including throttled requests) */ -bool bdrv_requests_pending(BlockDriverState *bs) -{ - BdrvChild *child; - - if (atomic_read(&bs->in_flight)) { - return true; - } - - QLIST_FOREACH(child, &bs->children, next) { - if (bdrv_requests_pending(child->bs)) { - return true; - } - } - - return false; -} - typedef struct { Coroutine *co; BlockDriverState *bs; bool done; bool begin; + bool recursive; + BdrvChild *parent; } BdrvCoDrainData; static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) @@ -175,8 +165,10 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) bdrv_wakeup(bs); } -static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) +/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ +static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive) { + BdrvChild *child, *tmp; BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || @@ -187,16 +179,19 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data); bdrv_coroutine_enter(bs, data.co); BDRV_POLL_WHILE(bs, !data.done); + + if (recursive) { + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { + bdrv_drain_invoke(child->bs, begin, true); + } + } } -static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) +static bool bdrv_drain_recurse(BlockDriverState *bs) { BdrvChild *child, *tmp; bool waited; - /* Ensure any pending metadata writes are submitted to bs->file. */ - bdrv_drain_invoke(bs, begin); - /* Wait for drained requests to finish */ waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0); @@ -215,7 +210,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) */ bdrv_ref(bs); } - waited |= bdrv_drain_recurse(bs, begin); + waited |= bdrv_drain_recurse(bs); if (in_main_loop) { bdrv_unref(bs); } @@ -224,6 +219,11 @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) return waited; } +static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + BdrvChild *parent); +static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + BdrvChild *parent); + static void bdrv_co_drain_bh_cb(void *opaque) { BdrvCoDrainData *data = opaque; @@ -232,9 +232,9 @@ static void bdrv_co_drain_bh_cb(void *opaque) bdrv_dec_in_flight(bs); if (data->begin) { - bdrv_drained_begin(bs); + bdrv_do_drained_begin(bs, data->recursive, data->parent); } else { - bdrv_drained_end(bs); + bdrv_do_drained_end(bs, data->recursive, data->parent); } data->done = true; @@ -242,7 +242,8 @@ static void bdrv_co_drain_bh_cb(void *opaque) } static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, - bool begin) + bool begin, bool recursive, + BdrvChild *parent) { BdrvCoDrainData data; @@ -256,6 +257,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, .bs = bs, .done = false, .begin = begin, + .recursive = recursive, + .parent = parent, }; bdrv_inc_in_flight(bs); aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), @@ -267,35 +270,97 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, assert(data.done); } -void bdrv_drained_begin(BlockDriverState *bs) +void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + BdrvChild *parent) { + BdrvChild *child, *next; + if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, true); + bdrv_co_yield_to_drain(bs, true, recursive, parent); return; } + /* Stop things in parent-to-child order */ if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { aio_disable_external(bdrv_get_aio_context(bs)); - bdrv_parent_drained_begin(bs); } - bdrv_drain_recurse(bs, true); + bdrv_parent_drained_begin(bs, parent); + bdrv_drain_invoke(bs, true, false); + bdrv_drain_recurse(bs); + + if (recursive) { + bs->recursive_quiesce_counter++; + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { + bdrv_do_drained_begin(child->bs, true, child); + } + } } -void bdrv_drained_end(BlockDriverState *bs) +void bdrv_drained_begin(BlockDriverState *bs) { + bdrv_do_drained_begin(bs, false, NULL); +} + +void bdrv_subtree_drained_begin(BlockDriverState *bs) +{ + bdrv_do_drained_begin(bs, true, NULL); +} + +void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + BdrvChild *parent) +{ + BdrvChild *child, *next; + int old_quiesce_counter; + if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, false); + bdrv_co_yield_to_drain(bs, false, recursive, parent); return; } assert(bs->quiesce_counter > 0); - if (atomic_fetch_dec(&bs->quiesce_counter) > 1) { - return; + old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter); + + /* Re-enable things in child-to-parent order */ + bdrv_drain_invoke(bs, false, false); + bdrv_parent_drained_end(bs, parent); + if (old_quiesce_counter == 1) { + aio_enable_external(bdrv_get_aio_context(bs)); } - bdrv_parent_drained_end(bs); - bdrv_drain_recurse(bs, false); - aio_enable_external(bdrv_get_aio_context(bs)); + if (recursive) { + bs->recursive_quiesce_counter--; + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { + bdrv_do_drained_end(child->bs, true, child); + } + } +} + +void bdrv_drained_end(BlockDriverState *bs) +{ + bdrv_do_drained_end(bs, false, NULL); +} + +void bdrv_subtree_drained_end(BlockDriverState *bs) +{ + bdrv_do_drained_end(bs, true, NULL); +} + +void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) +{ + int i; + + for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { + bdrv_do_drained_begin(child->bs, true, child); + } +} + +void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) +{ + int i; + + for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { + bdrv_do_drained_end(child->bs, true, child); + } } /* @@ -342,14 +407,20 @@ void bdrv_drain_all_begin(void) BdrvNextIterator it; GSList *aio_ctxs = NULL, *ctx; - block_job_pause_all(); + /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread + * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on + * nodes in several different AioContexts, so make sure we're in the main + * context. */ + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); + /* Stop things in parent-to-child order */ aio_context_acquire(aio_context); - bdrv_parent_drained_begin(bs); aio_disable_external(aio_context); + bdrv_parent_drained_begin(bs, NULL); + bdrv_drain_invoke(bs, true, true); aio_context_release(aio_context); if (!g_slist_find(aio_ctxs, aio_context)) { @@ -372,7 +443,7 @@ void bdrv_drain_all_begin(void) aio_context_acquire(aio_context); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { if (aio_context == bdrv_get_aio_context(bs)) { - waited |= bdrv_drain_recurse(bs, true); + waited |= bdrv_drain_recurse(bs); } } aio_context_release(aio_context); @@ -390,14 +461,13 @@ void bdrv_drain_all_end(void) for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); + /* Re-enable things in child-to-parent order */ aio_context_acquire(aio_context); + bdrv_drain_invoke(bs, false, true); + bdrv_parent_drained_end(bs, NULL); aio_enable_external(aio_context); - bdrv_parent_drained_end(bs); - bdrv_drain_recurse(bs, false); aio_context_release(aio_context); } - - block_job_resume_all(); } void bdrv_drain_all(void) diff --git a/block/qcow2.c b/block/qcow2.c index 1914a94..4348b2c 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1672,34 +1672,12 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, return status; } -/* handle reading after the end of the backing file */ -int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t offset, int bytes) -{ - uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE; - int n1; - - if ((offset + bytes) <= bs_size) { - return bytes; - } - - if (offset >= bs_size) { - n1 = 0; - } else { - n1 = bs_size - offset; - } - - qemu_iovec_memset(qiov, n1, 0, bytes - n1); - - return n1; -} - static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { BDRVQcow2State *s = bs->opaque; - int offset_in_cluster, n1; + int offset_in_cluster; int ret; unsigned int cur_bytes; /* number of bytes in current iteration */ uint64_t cluster_offset = 0; @@ -1734,26 +1712,13 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, case QCOW2_CLUSTER_UNALLOCATED: if (bs->backing) { - /* read from the base image */ - n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov, - offset, cur_bytes); - if (n1 > 0) { - QEMUIOVector local_qiov; - - qemu_iovec_init(&local_qiov, hd_qiov.niov); - qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1); - - BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); - qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_preadv(bs->backing, offset, n1, - &local_qiov, 0); - qemu_co_mutex_lock(&s->lock); - - qemu_iovec_destroy(&local_qiov); - - if (ret < 0) { - goto fail; - } + BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_preadv(bs->backing, offset, cur_bytes, + &hd_qiov, 0); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + goto fail; } } else { /* Note: in this case, no need to wait */ diff --git a/block/qcow2.h b/block/qcow2.h index 6f0ff15..46c8cf4 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -528,9 +528,6 @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset) } /* qcow2.c functions */ -int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t sector_num, int nb_sectors); - int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size, int refcount_order, bool generous_increase, uint64_t *refblock_count); diff --git a/block/replication.c b/block/replication.c index e41e293..b1ea3ca 100644 --- a/block/replication.c +++ b/block/replication.c @@ -394,6 +394,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, new_secondary_flags = s->orig_secondary_flags; } + bdrv_subtree_drained_begin(s->hidden_disk->bs); + bdrv_subtree_drained_begin(s->secondary_disk->bs); + if (orig_hidden_flags != new_hidden_flags) { reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL, new_hidden_flags); @@ -409,6 +412,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, reopen_queue, &local_err); error_propagate(errp, local_err); } + + bdrv_subtree_drained_end(s->hidden_disk->bs); + bdrv_subtree_drained_end(s->secondary_disk->bs); } static void backup_job_cleanup(BlockDriverState *bs) |