We are on the way to implement internal-backup with fleecing scheme, which includes backup job copying from fleecing block driver node (which is target of copy-before-write filter) to final target of backup. This job doesn't need own filter, as fleecing block driver node is a kind of snapshot, it's immutable from reader point of view.
Let's add a parameter for backup to not insert filter but instead unshare writes on source. This way backup job becomes a simple copying process. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com> --- qapi/block-core.json | 12 +++++++- include/block/block_int.h | 1 + block/backup.c | 61 +++++++++++++++++++++++++++++++++++---- block/replication.c | 2 +- blockdev.c | 1 + 5 files changed, 70 insertions(+), 7 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 8a333136f5..995ca16a5e 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1391,6 +1391,15 @@ # above node specified by @drive. If this option is not given, # a node name is autogenerated. (Since: 4.2) # +# @immutable-source: If true, assume source is immutable and don't insert filter +# as no copy-before-write operations are needed. It will +# fail if there are existing writers on source node, as well, +# any attempt to add writer to source node during backup will +# fail. @filter-node-name must not be set. +# If false, insert copy-before-write filter above source node +# (see also @filter-node-name parameter). +# Default is false. (Since 6.2) +# # @x-perf: Performance options. (Since 6.0) # # Note: @on-source-error and @on-target-error only affect background @@ -1407,7 +1416,8 @@ '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError', '*auto-finalize': 'bool', '*auto-dismiss': 'bool', - '*filter-node-name': 'str', '*x-perf': 'BackupPerf' } } + '*filter-node-name': 'str', '*immutable-source': 'bool', + '*x-perf': 'BackupPerf' } } ## # @DriveBackup: diff --git a/include/block/block_int.h b/include/block/block_int.h index f1a54db0f8..6571dad061 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1284,6 +1284,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BitmapSyncMode bitmap_mode, bool compress, const char *filter_node_name, + bool immutable_source, BackupPerf *perf, BlockdevOnError on_source_error, BlockdevOnError on_target_error, diff --git a/block/backup.c b/block/backup.c index 687d2882bc..a7f4d0d663 100644 --- a/block/backup.c +++ b/block/backup.c @@ -34,6 +34,14 @@ typedef struct BackupBlockJob { BlockDriverState *cbw; BlockDriverState *source_bs; BlockDriverState *target_bs; + BlockBackend *source_blk; + BlockBackend *target_blk; + /* + * Note that if backup runs with filter (immutable-source parameter is + * false), @cbw is set but @source_blk and @target_blk are NULL. + * Otherwise if backup runs without filter (immutable-source paramter is + * true), @cbw is NULL but @source_blk and @target_blk are set. + */ BdrvDirtyBitmap *sync_bitmap; @@ -102,7 +110,17 @@ static void backup_clean(Job *job) { BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); block_job_remove_all_bdrv(&s->common); - bdrv_cbw_drop(s->cbw); + if (s->cbw) { + assert(!s->source_blk && !s->target_blk); + bdrv_cbw_drop(s->cbw); + } else { + block_copy_state_free(s->bcs); + s->bcs = NULL; + blk_unref(s->source_blk); + s->source_blk = NULL; + blk_unref(s->target_blk); + s->target_blk = NULL; + } } void backup_do_checkpoint(BlockJob *job, Error **errp) @@ -356,6 +374,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BitmapSyncMode bitmap_mode, bool compress, const char *filter_node_name, + bool immutable_source, BackupPerf *perf, BlockdevOnError on_source_error, BlockdevOnError on_target_error, @@ -368,6 +387,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, int64_t cluster_size; BlockDriverState *cbw = NULL; BlockCopyState *bcs = NULL; + BlockBackend *source_blk = NULL, *target_blk = NULL; assert(bs); assert(target); @@ -376,6 +396,12 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); assert(sync_bitmap || sync_mode != MIRROR_SYNC_MODE_BITMAP); + if (immutable_source && filter_node_name) { + error_setg(errp, "immutable-source and filter-node-name should not " + "be set simultaneously"); + return NULL; + } + if (bs == target) { error_setg(errp, "Source and target cannot be the same"); return NULL; @@ -450,9 +476,30 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, goto error; } - cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp); - if (!cbw) { - goto error; + if (immutable_source) { + source_blk = blk_new_with_bs(bs, BLK_PERM_CONSISTENT_READ, + BLK_PERM_WRITE_UNCHANGED | + BLK_PERM_CONSISTENT_READ, errp); + if (!source_blk) { + goto error; + } + + target_blk = blk_new_with_bs(target, BLK_PERM_WRITE, + BLK_PERM_CONSISTENT_READ, errp); + if (!target_blk) { + goto error; + } + + bcs = block_copy_state_new(blk_root(source_blk), blk_root(target_blk), + NULL, false, errp); + if (!bcs) { + goto error; + } + } else { + cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp); + if (!cbw) { + goto error; + } } cluster_size = block_copy_cluster_size(bcs); @@ -464,7 +511,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, } /* job->len is fixed, so we can't allow resize */ - job = block_job_create(job_id, &backup_job_driver, txn, cbw, + job = block_job_create(job_id, &backup_job_driver, txn, cbw ?: bs, 0, BLK_PERM_ALL, speed, creation_flags, cb, opaque, errp); if (!job) { @@ -474,6 +521,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, job->cbw = cbw; job->source_bs = bs; job->target_bs = target; + job->source_blk = source_blk; + job->target_blk = target_blk; job->on_source_error = on_source_error; job->on_target_error = on_target_error; job->sync_mode = sync_mode; @@ -501,6 +550,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, if (cbw) { bdrv_cbw_drop(cbw); } + blk_unref(source_blk); + blk_unref(target_blk); return NULL; } diff --git a/block/replication.c b/block/replication.c index 32444b9a8f..5dba4907b8 100644 --- a/block/replication.c +++ b/block/replication.c @@ -590,7 +590,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, s->backup_job = backup_job_create( NULL, s->secondary_disk->bs, s->hidden_disk->bs, 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL, - &perf, + false, &perf, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, backup_job_completed, bs, NULL, &local_err); diff --git a/blockdev.c b/blockdev.c index 3d8ac368a1..3a8ff7c5ce 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2911,6 +2911,7 @@ static BlockJob *do_backup_common(BackupCommon *backup, backup->sync, bmap, backup->bitmap_mode, backup->compress, backup->filter_node_name, + backup->immutable_source, &perf, backup->on_source_error, backup->on_target_error, -- 2.29.2