293 lines
13 KiB
Diff
293 lines
13 KiB
Diff
From 4291b03feee4f973686d67dc6e45ecd1ff374379 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/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
|
|
|