From 4291b03feee4f973686d67dc6e45ecd1ff374379 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 15:04:57 +0100 Subject: [PATCH 14/49] backup: modify job api Introduces a BackupDump function callback and a pause_count for backup_start. For a dump-backup the target parameter can now be NULL so access to target needs to be guarded now. --- block/backup.c | 118 +++++++++++++++++++++++++++++----------------- block/replication.c | 3 +- blockdev.c | 4 +- include/block/block_int.h | 5 ++ 4 files changed, 83 insertions(+), 47 deletions(-) diff --git a/block/backup.c b/block/backup.c index a4fb2884f9..fe4ce7f504 100644 --- a/block/backup.c +++ b/block/backup.c @@ -36,6 +36,7 @@ typedef struct BackupBlockJob { BdrvDirtyBitmap *sync_bitmap; MirrorSyncMode sync_mode; RateLimit limit; + BackupDumpFunc *dump_cb; BlockdevOnError on_source_error; BlockdevOnError on_target_error; CoRwlock flush_rwlock; @@ -145,13 +146,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, goto out; } + int64_t start_sec = start * sectors_per_cluster; if (buffer_is_zero(iov.iov_base, iov.iov_len)) { - ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, - bounce_qiov.size, BDRV_REQ_MAY_UNMAP); + if (job->dump_cb) { + ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL); + } + if (job->target) { + ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, + bounce_qiov.size, BDRV_REQ_MAY_UNMAP); + } } else { - ret = blk_co_pwritev(job->target, start * job->cluster_size, - bounce_qiov.size, &bounce_qiov, - job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); + if (job->dump_cb) { + ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer); + } + if (job->target) { + ret = blk_co_pwritev(job->target, start * job->cluster_size, + bounce_qiov.size, &bounce_qiov, + job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); + } } if (ret < 0) { trace_backup_do_cow_write_fail(job, start, ret); @@ -246,6 +258,8 @@ static void backup_abort(BlockJob *job) static void backup_clean(BlockJob *job) { BackupBlockJob *s = container_of(job, BackupBlockJob, common); + if (!s->target) + return; assert(s->target); blk_unref(s->target); s->target = NULL; @@ -330,9 +344,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job, if (read) { return block_job_error_action(&job->common, job->on_source_error, true, error); - } else { + } else if (job->target) { return block_job_error_action(&job->common, job->on_target_error, false, error); + } else { + return BLOCK_ERROR_ACTION_REPORT; } } @@ -453,6 +469,7 @@ static void coroutine_fn backup_run(void *opaque) job->done_bitmap = bitmap_new(end); + job->before_write.notify = backup_before_write_notify; bdrv_add_before_write_notifier(bs, &job->before_write); @@ -557,7 +574,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BlockdevOnError on_source_error, BlockdevOnError on_target_error, int creation_flags, + BackupDumpFunc *dump_cb, BlockCompletionFunc *cb, void *opaque, + int pause_count, BlockJobTxn *txn, Error **errp) { int64_t len; @@ -566,7 +585,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, int ret; assert(bs); - assert(target); + assert(target || dump_cb); if (bs == target) { error_setg(errp, "Source and target cannot be the same"); @@ -579,13 +598,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, return NULL; } - if (!bdrv_is_inserted(target)) { + if (target && !bdrv_is_inserted(target)) { error_setg(errp, "Device is not inserted: %s", bdrv_get_device_name(target)); return NULL; } - if (compress && target->drv->bdrv_co_pwritev_compressed == NULL) { + if (target && compress && target->drv->bdrv_co_pwritev_compressed == NULL) { error_setg(errp, "Compression is not supported for this drive %s", bdrv_get_device_name(target)); return NULL; @@ -595,7 +614,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, return NULL; } - if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { + if (target && bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { return NULL; } @@ -635,15 +654,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, goto error; } - /* The target must match the source in size, so no resize here either */ - job->target = blk_new(BLK_PERM_WRITE, - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | - BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); - ret = blk_insert_bs(job->target, target, errp); - if (ret < 0) { - goto error; + if (target) { + /* The target must match the source in size, so no resize here either */ + job->target = blk_new(BLK_PERM_WRITE, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | + BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); + ret = blk_insert_bs(job->target, target, errp); + if (ret < 0) { + goto error; + } } + job->dump_cb = dump_cb; job->on_source_error = on_source_error; job->on_target_error = on_target_error; job->sync_mode = sync_mode; @@ -651,36 +673,44 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, sync_bitmap : NULL; job->compress = compress; - /* 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 */ - error_report("WARNING: 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; + if (target) { + /* 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 */ + error_report("WARNING: 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 = BACKUP_CLUSTER_SIZE_DEFAULT; + } } else { - job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); + job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; } - /* Required permissions are already taken with target's blk_new() */ - block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, - &error_abort); + if (target) { + /* Required permissions are already taken with target's blk_new() */ + block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, + &error_abort); + } else { + job->common.pause_count = pause_count; + } job->common.len = len; block_job_txn_add_job(txn, &job->common); diff --git a/block/replication.c b/block/replication.c index bf3c395eb4..60c6524417 100644 --- a/block/replication.c +++ b/block/replication.c @@ -531,7 +531,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, 0, MIRROR_SYNC_MODE_NONE, NULL, false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL, - backup_job_completed, bs, NULL, &local_err); + NULL, + backup_job_completed, bs, 0, NULL, &local_err); if (local_err) { error_propagate(errp, local_err); backup_job_cleanup(bs); diff --git a/blockdev.c b/blockdev.c index 040c152512..bb3fc5bd43 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3273,7 +3273,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, backup->sync, bmap, backup->compress, backup->on_source_error, backup->on_target_error, - BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); + BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); bdrv_unref(target_bs); if (local_err != NULL) { error_propagate(errp, local_err); @@ -3352,7 +3352,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, backup->sync, NULL, backup->compress, backup->on_source_error, backup->on_target_error, - BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); + BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); } diff --git a/include/block/block_int.h b/include/block/block_int.h index 59400bd848..ec655815ca 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -59,6 +59,9 @@ #define BLOCK_PROBE_BUF_SIZE 512 +typedef int BackupDumpFunc(void *opaque, BlockDriverState *bs, + int64_t sector_num, int n_sectors, unsigned char *buf); + enum BdrvTrackedRequestType { BDRV_TRACKED_READ, BDRV_TRACKED_WRITE, @@ -877,7 +880,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BlockdevOnError on_source_error, BlockdevOnError on_target_error, int creation_flags, + BackupDumpFunc *dump_cb, BlockCompletionFunc *cb, void *opaque, + int pause_count, BlockJobTxn *txn, Error **errp); void hmp_drive_add_node(Monitor *mon, const char *optstr); -- 2.11.0