237 lines
9.2 KiB
Diff
237 lines
9.2 KiB
Diff
|
From 1078c0f6acc1bfba04b7d5cdfdeb02b161b5f7c4 Mon Sep 17 00:00:00 2001
|
||
|
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||
|
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
|
||
|
|