From 1078c0f6acc1bfba04b7d5cdfdeb02b161b5f7c4 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 15:04:57 +0100 Subject: [PATCH 14/47] 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 | 82 +++++++++++++++++++++++++++++++---------------- blockdev.c | 6 ++-- include/block/block_int.h | 5 +++ 3 files changed, 63 insertions(+), 30 deletions(-) diff --git a/block/backup.c b/block/backup.c index 2c05323..f3c0ba3 100644 --- a/block/backup.c +++ b/block/backup.c @@ -41,6 +41,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; @@ -149,12 +150,23 @@ 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, 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, 0); + } } if (ret < 0) { trace_backup_do_cow_write_fail(job, start, ret); @@ -268,9 +280,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; } } @@ -393,6 +407,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); @@ -467,7 +482,9 @@ static void coroutine_fn backup_run(void *opaque) qemu_co_rwlock_unlock(&job->flush_rwlock); g_free(job->done_bitmap); - bdrv_op_unblock_all(blk_bs(target), job->common.blocker); + if (target) { + bdrv_op_unblock_all(blk_bs(target), job->common.blocker); + } data = g_malloc(sizeof(*data)); data->ret = ret; @@ -479,7 +496,9 @@ void backup_start(const char *job_id, BlockDriverState *bs, MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, BlockdevOnError on_source_error, BlockdevOnError on_target_error, + BackupDumpFunc *dump_cb, BlockCompletionFunc *cb, void *opaque, + int pause_count, BlockJobTxn *txn, Error **errp) { int64_t len; @@ -488,7 +507,7 @@ void backup_start(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"); @@ -501,7 +520,7 @@ void backup_start(const char *job_id, BlockDriverState *bs, return; } - 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; @@ -511,7 +530,7 @@ void backup_start(const char *job_id, BlockDriverState *bs, return; } - 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; } @@ -547,34 +566,43 @@ void backup_start(const char *job_id, BlockDriverState *bs, goto error; } - job->target = blk_new(); - blk_insert_bs(job->target, target); + if (target) { + job->target = blk_new(); + blk_insert_bs(job->target, target); + } + job->dump_cb = dump_cb; job->on_source_error = on_source_error; job->on_target_error = on_target_error; job->sync_mode = sync_mode; job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ? sync_bitmap : NULL; - /* 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 < 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 < 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); + } + + bdrv_op_block_all(target, job->common.blocker); } else { - job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); + job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; } - bdrv_op_block_all(target, job->common.blocker); + job->common.pause_count = pause_count; job->common.len = len; job->common.co = qemu_coroutine_create(backup_run, job); block_job_txn_add_job(txn, &job->common); diff --git a/blockdev.c b/blockdev.c index 2161400..5e3707d 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3277,8 +3277,8 @@ static void do_drive_backup(const char *job_id, const char *device, } backup_start(job_id, bs, target_bs, speed, sync, bmap, - on_source_error, on_target_error, - block_job_cb, bs, txn, &local_err); + on_source_error, on_target_error, NULL, + block_job_cb, bs, 0, txn, &local_err); bdrv_unref(target_bs); if (local_err != NULL) { error_propagate(errp, local_err); @@ -3371,7 +3371,7 @@ void do_blockdev_backup(const char *job_id, const char *device, } } backup_start(job_id, bs, target_bs, speed, sync, NULL, on_source_error, - on_target_error, block_job_cb, bs, txn, &local_err); + on_target_error, NULL, block_job_cb, bs, 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 1e939de..db4650e 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, @@ -767,7 +770,9 @@ void backup_start(const char *job_id, BlockDriverState *bs, MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, BlockdevOnError on_source_error, BlockdevOnError on_target_error, + 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.1.4