Split out cluster_size calculation. Move copy-bitmap creation above
block-job creation, as we are going to share it with upcoming
backup-top filter, which also should be created before actual block job
creation.
Also, while being here, drop unnecessary "goto error" from
bdrv_getlength error path.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/backup.c | 84 +++++++++++++++++++++++++++++++-------------------
1 file changed, 53 insertions(+), 31 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index b54386b699..79db4fbb6d 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -507,6 +507,42 @@ static const BlockJobDriver backup_job_driver = {
.drain = backup_drain,
};
+static int64_t backup_calculate_cluster_size(BlockDriverState *target,
+ Error **errp)
+{
+ int ret;
+ BlockDriverInfo bdi;
+
+ /*
+ * If there is no backing file on the target, we cannot rely on COW if our
+ * backup cluster size is smaller than the target cluster size. Even for
+ * targets with a backing file, try to avoid COW if possible.
+ */
+ ret = bdrv_get_info(target, &bdi);
+ if (ret == -ENOTSUP && !target->backing) {
+ /* Cluster size is not defined */
+ warn_report("The target block device doesn't provide "
+ "information about the block size and it doesn't have a "
+ "backing file. The default block size of %u bytes is "
+ "used. If the actual block size of the target exceeds "
+ "this default, the backup may be unusable",
+ BACKUP_CLUSTER_SIZE_DEFAULT);
+ return BACKUP_CLUSTER_SIZE_DEFAULT;
+ } else if (ret < 0 && !target->backing) {
+ error_setg_errno(errp, -ret,
+ "Couldn't determine the cluster size of the target image, "
+ "which has no backing file");
+ error_append_hint(errp,
+ "Aborting, since this may create an unusable destination image\n");
+ return ret;
+ } else if (ret < 0 && target->backing) {
+ /* Not fatal; just trudge on ahead. */
+ return BACKUP_CLUSTER_SIZE_DEFAULT;
+ }
+
+ return MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
+}
+
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
@@ -518,9 +554,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
JobTxn *txn, Error **errp)
{
int64_t len;
- BlockDriverInfo bdi;
BackupBlockJob *job = NULL;
int ret;
+ int64_t cluster_size;
+ HBitmap *copy_bitmap = NULL;
assert(bs);
assert(target);
@@ -579,9 +616,16 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
if (len < 0) {
error_setg_errno(errp, -len, "unable to get length for '%s'",
bdrv_get_device_name(bs));
- goto error;
+ return NULL;
+ }
+
+ cluster_size = backup_calculate_cluster_size(target, errp);
+ if (cluster_size < 0) {
+ return NULL;
}
+ copy_bitmap = hbitmap_alloc(len, ctz32(cluster_size));
+
/* job->len is fixed, so we can't allow resize */
job = block_job_create(job_id, &backup_job_driver, txn, bs,
BLK_PERM_CONSISTENT_READ,
@@ -610,35 +654,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
/* Detect image-fleecing (and similar) schemes */
job->serialize_target_writes = bdrv_chain_contains(target, bs);
-
- /* If there is no backing file on the target, we cannot rely on COW if our
- * backup cluster size is smaller than the target cluster size. Even for
- * targets with a backing file, try to avoid COW if possible. */
- ret = bdrv_get_info(target, &bdi);
- if (ret == -ENOTSUP && !target->backing) {
- /* Cluster size is not defined */
- warn_report("The target block device doesn't provide "
- "information about the block size and it doesn't have a "
- "backing file. The default block size of %u bytes is "
- "used. If the actual block size of the target exceeds "
- "this default, the backup may be unusable",
- BACKUP_CLUSTER_SIZE_DEFAULT);
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
- } else if (ret < 0 && !target->backing) {
- error_setg_errno(errp, -ret,
- "Couldn't determine the cluster size of the target image, "
- "which has no backing file");
- error_append_hint(errp,
- "Aborting, since this may create an unusable destination image\n");
- goto error;
- } else if (ret < 0 && target->backing) {
- /* Not fatal; just trudge on ahead. */
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
- } else {
- job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
- }
-
- job->copy_bitmap = hbitmap_alloc(len, ctz32(job->cluster_size));
+ job->cluster_size = cluster_size;
+ job->copy_bitmap = copy_bitmap;
+ copy_bitmap = NULL;
job->use_copy_range = true;
job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk),
blk_get_max_transfer(job->target));
@@ -654,6 +672,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return &job->common;
error:
+ if (copy_bitmap) {
+ assert(!job || !job->copy_bitmap);
+ hbitmap_free(copy_bitmap);
+ }
if (sync_bitmap) {
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
}
--
2.18.0
On 15.04.19 16:49, Vladimir Sementsov-Ogievskiy wrote: > Split out cluster_size calculation. Move copy-bitmap creation above > block-job creation, as we are going to share it with upcoming > backup-top filter, which also should be created before actual block job > creation. > > Also, while being here, drop unnecessary "goto error" from > bdrv_getlength error path. It isn’t unnecessary, though. Before this, we invoke bdrv_dirty_bitmap_create_successor(), so the error path has to clean that up with bdrv_reclaim_dirty_bitmap(). Max
26.04.2019 21:30, Max Reitz wrote: > On 15.04.19 16:49, Vladimir Sementsov-Ogievskiy wrote: >> Split out cluster_size calculation. Move copy-bitmap creation above >> block-job creation, as we are going to share it with upcoming >> backup-top filter, which also should be created before actual block job >> creation. >> >> Also, while being here, drop unnecessary "goto error" from >> bdrv_getlength error path. > > It isn’t unnecessary, though. Before this, we invoke > bdrv_dirty_bitmap_create_successor(), so the error path has to clean > that up with bdrv_reclaim_dirty_bitmap(). > > Max > Oops, will resend. I was looking at previous plain "return NULL", but missed that in "if" branch we do thing to be rolled-back on fail. Thank you for review! -- Best regards, Vladimir
© 2016 - 2026 Red Hat, Inc.