diff options
-rw-r--r-- | block.c | 8 | ||||
-rw-r--r-- | block/mirror.c | 39 | ||||
-rw-r--r-- | blockdev.c | 15 | ||||
-rw-r--r-- | include/block/block_int.h | 18 |
4 files changed, 57 insertions, 23 deletions
@@ -2291,14 +2291,6 @@ void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new) change_parent_backing_link(old, new); - /* Change backing files if a previously independent node is added to the - * chain. For active commit, we replace top by its own (indirect) backing - * file and don't do anything here so we don't build a loop. */ - if (new->backing == NULL && !bdrv_chain_contains(backing_bs(old), new)) { - bdrv_set_backing_hd(new, backing_bs(old)); - bdrv_set_backing_hd(old, NULL); - } - bdrv_unref(old); } diff --git a/block/mirror.c b/block/mirror.c index 41848b2..075384a 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -44,6 +44,7 @@ typedef struct MirrorBlockJob { /* Used to block operations on the drive-mirror-replace target */ Error *replace_blocker; bool is_none_mode; + BlockMirrorBackingMode backing_mode; BlockdevOnError on_source_error, on_target_error; bool synced; bool should_complete; @@ -742,20 +743,26 @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp) static void mirror_complete(BlockJob *job, Error **errp) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); - Error *local_err = NULL; - int ret; + BlockDriverState *src, *target; + + src = blk_bs(job->blk); + target = blk_bs(s->target); - ret = bdrv_open_backing_file(blk_bs(s->target), NULL, "backing", - &local_err); - if (ret < 0) { - error_propagate(errp, local_err); - return; - } if (!s->synced) { error_setg(errp, QERR_BLOCK_JOB_NOT_READY, job->id); return; } + if (s->backing_mode == MIRROR_OPEN_BACKING_CHAIN) { + int ret; + + assert(!target->backing); + ret = bdrv_open_backing_file(target, NULL, "backing", errp); + if (ret < 0) { + return; + } + } + /* check the target bs is not blocked and block all operations on it */ if (s->replaces) { AioContext *replace_aio_context; @@ -777,6 +784,13 @@ static void mirror_complete(BlockJob *job, Error **errp) aio_context_release(replace_aio_context); } + if (s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { + BlockDriverState *backing = s->is_none_mode ? src : s->base; + if (backing_bs(target) != backing) { + bdrv_set_backing_hd(target, backing); + } + } + s->should_complete = true; block_job_enter(&s->common); } @@ -799,6 +813,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, const char *replaces, int64_t speed, uint32_t granularity, int64_t buf_size, + BlockMirrorBackingMode backing_mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, @@ -836,6 +851,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, s->on_source_error = on_source_error; s->on_target_error = on_target_error; s->is_none_mode = is_none_mode; + s->backing_mode = backing_mode; s->base = base; s->granularity = granularity; s->buf_size = ROUND_UP(buf_size, granularity); @@ -859,7 +875,8 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, void mirror_start(BlockDriverState *bs, BlockDriverState *target, const char *replaces, int64_t speed, uint32_t granularity, int64_t buf_size, - MirrorSyncMode mode, BlockdevOnError on_source_error, + MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, + BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, BlockCompletionFunc *cb, @@ -875,7 +892,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, is_none_mode = mode == MIRROR_SYNC_MODE_NONE; base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; mirror_start_job(bs, target, replaces, - speed, granularity, buf_size, + speed, granularity, buf_size, backing_mode, on_source_error, on_target_error, unmap, cb, opaque, errp, &mirror_job_driver, is_none_mode, base); } @@ -922,7 +939,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, } } - mirror_start_job(bs, base, NULL, speed, 0, 0, + mirror_start_job(bs, base, NULL, speed, 0, 0, MIRROR_LEAVE_BACKING_CHAIN, on_error, on_error, false, cb, opaque, &local_err, &commit_active_job_driver, false, base); if (local_err) { @@ -3426,6 +3426,7 @@ static void blockdev_mirror_common(BlockDriverState *bs, BlockDriverState *target, bool has_replaces, const char *replaces, enum MirrorSyncMode sync, + BlockMirrorBackingMode backing_mode, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, bool has_buf_size, int64_t buf_size, @@ -3483,7 +3484,7 @@ static void blockdev_mirror_common(BlockDriverState *bs, */ mirror_start(bs, target, has_replaces ? replaces : NULL, - speed, granularity, buf_size, sync, + speed, granularity, buf_size, sync, backing_mode, on_source_error, on_target_error, unmap, block_job_cb, bs, errp); } @@ -3506,6 +3507,7 @@ void qmp_drive_mirror(const char *device, const char *target, BlockBackend *blk; BlockDriverState *source, *target_bs; AioContext *aio_context; + BlockMirrorBackingMode backing_mode; Error *local_err = NULL; QDict *options = NULL; int flags; @@ -3579,6 +3581,12 @@ void qmp_drive_mirror(const char *device, const char *target, } } + if (mode == NEW_IMAGE_MODE_ABSOLUTE_PATHS) { + backing_mode = MIRROR_SOURCE_BACKING_CHAIN; + } else { + backing_mode = MIRROR_OPEN_BACKING_CHAIN; + } + if ((sync == MIRROR_SYNC_MODE_FULL || !source) && mode != NEW_IMAGE_MODE_EXISTING) { @@ -3627,7 +3635,7 @@ void qmp_drive_mirror(const char *device, const char *target, bdrv_set_aio_context(target_bs, aio_context); blockdev_mirror_common(bs, target_bs, - has_replaces, replaces, sync, + has_replaces, replaces, sync, backing_mode, has_speed, speed, has_granularity, granularity, has_buf_size, buf_size, @@ -3659,6 +3667,7 @@ void qmp_blockdev_mirror(const char *device, const char *target, BlockBackend *blk; BlockDriverState *target_bs; AioContext *aio_context; + BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; Error *local_err = NULL; blk = blk_by_name(device); @@ -3684,7 +3693,7 @@ void qmp_blockdev_mirror(const char *device, const char *target, bdrv_set_aio_context(target_bs, aio_context); blockdev_mirror_common(bs, target_bs, - has_replaces, replaces, sync, + has_replaces, replaces, sync, backing_mode, has_speed, speed, has_granularity, granularity, has_buf_size, buf_size, diff --git a/include/block/block_int.h b/include/block/block_int.h index 16c43e2..688c6be 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -509,6 +509,20 @@ struct BlockBackendRootState { BlockdevDetectZeroesOptions detect_zeroes; }; +typedef enum BlockMirrorBackingMode { + /* Reuse the existing backing chain from the source for the target. + * - sync=full: Set backing BDS to NULL. + * - sync=top: Use source's backing BDS. + * - sync=none: Use source as the backing BDS. */ + MIRROR_SOURCE_BACKING_CHAIN, + + /* Open the target's backing chain completely anew */ + MIRROR_OPEN_BACKING_CHAIN, + + /* Do not change the target's backing BDS after job completion */ + MIRROR_LEAVE_BACKING_CHAIN, +} BlockMirrorBackingMode; + static inline BlockDriverState *backing_bs(BlockDriverState *bs) { return bs->backing ? bs->backing->bs : NULL; @@ -671,6 +685,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, * @granularity: The chosen granularity for the dirty bitmap. * @buf_size: The amount of data that can be in flight at one time. * @mode: Whether to collapse all images in the chain to the target. + * @backing_mode: How to establish the target's backing chain after completion. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. * @unmap: Whether to unmap target where source sectors only contain zeroes. @@ -686,7 +701,8 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, void mirror_start(BlockDriverState *bs, BlockDriverState *target, const char *replaces, int64_t speed, uint32_t granularity, int64_t buf_size, - MirrorSyncMode mode, BlockdevOnError on_source_error, + MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, + BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, BlockCompletionFunc *cb, |