@@ -361,6 +361,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BackupPerf *perf,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
+ OnCbwError on_cbw_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,
JobTxn *txn, Error **errp)
@@ -458,7 +459,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
}
cbw = bdrv_cbw_append(bs, target, filter_node_name, discard_source,
- perf->min_cluster_size, &bcs, errp);
+ perf->min_cluster_size, &bcs, on_cbw_error, errp);
if (!cbw) {
goto error;
}
@@ -551,6 +551,7 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
bool discard_source,
uint64_t min_cluster_size,
BlockCopyState **bcs,
+ OnCbwError on_cbw_error,
Error **errp)
{
BDRVCopyBeforeWriteState *state;
@@ -568,6 +569,7 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
}
qdict_put_str(opts, "file", bdrv_get_node_name(source));
qdict_put_str(opts, "target", bdrv_get_node_name(target));
+ qdict_put_str(opts, "on-cbw-error", OnCbwError_str(on_cbw_error));
if (min_cluster_size > INT64_MAX) {
error_setg(errp, "min-cluster-size too large: %" PRIu64 " > %" PRIi64,
@@ -42,6 +42,7 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
bool discard_source,
uint64_t min_cluster_size,
BlockCopyState **bcs,
+ OnCbwError on_cbw_error,
Error **errp);
void bdrv_cbw_drop(BlockDriverState *bs);
@@ -584,7 +584,9 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, false,
NULL, &perf,
BLOCKDEV_ON_ERROR_REPORT,
- BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
+ BLOCKDEV_ON_ERROR_REPORT,
+ ON_CBW_ERROR_BREAK_GUEST_WRITE,
+ JOB_INTERNAL,
backup_job_completed, bs, NULL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -2641,6 +2641,7 @@ static BlockJob *do_backup_common(BackupCommon *backup,
BdrvDirtyBitmap *bmap = NULL;
BackupPerf perf = { .max_workers = 64 };
int job_flags = JOB_DEFAULT;
+ OnCbwError on_cbw_error = ON_CBW_ERROR_BREAK_GUEST_WRITE;
if (!backup->has_speed) {
backup->speed = 0;
@@ -2745,6 +2746,10 @@ static BlockJob *do_backup_common(BackupCommon *backup,
job_flags |= JOB_MANUAL_DISMISS;
}
+ if (backup->has_on_cbw_error) {
+ on_cbw_error = backup->on_cbw_error;
+ }
+
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, bmap, backup->bitmap_mode,
backup->compress, backup->discard_source,
@@ -2752,6 +2757,7 @@ static BlockJob *do_backup_common(BackupCommon *backup,
&perf,
backup->on_source_error,
backup->on_target_error,
+ on_cbw_error,
job_flags, NULL, NULL, txn, errp);
return job;
}
@@ -179,6 +179,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
* all ".has_*" fields are ignored.
* @on_source_error: The action to take upon error reading from the source.
* @on_target_error: The action to take upon error writing to the target.
+ * @on_cbw_error: The action to take upon error in copy-before-write operations.
* @creation_flags: Flags that control the behavior of the Job lifetime.
* See @BlockJobCreateFlags
* @cb: Completion function for the job.
@@ -198,6 +199,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BackupPerf *perf,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
+ OnCbwError on_cbw_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,
JobTxn *txn, Error **errp);
@@ -1622,6 +1622,9 @@
# @discard-source: Discard blocks on source which have already been
# copied to the target. (Since 9.1)
#
+# @on-cbw-error: optional policy defining behavior on I/O errors in
+# copy-before-write jobs; defaults to break-guest-write. (Since 10.0)
+#
# @x-perf: Performance options. (Since 6.0)
#
# Features:
@@ -1641,6 +1644,7 @@
'*compress': 'bool',
'*on-source-error': 'BlockdevOnError',
'*on-target-error': 'BlockdevOnError',
+ '*on-cbw-error': 'OnCbwError',
'*auto-finalize': 'bool', '*auto-dismiss': 'bool',
'*filter-node-name': 'str',
'*discard-source': 'bool',
This patch extends the blockdev-backup QMP command to allow users to specify how to behave when IO errors occur during copy-before-write operations. Previously, the behavior was fixed and could not be controlled by the user. The new 'on-cbw-error' option can be set to one of two values: - 'break-guest-write': Forwards the IO error to the guest and triggers the on-source-error policy. This preserves snapshot integrity at the expense of guest IO operations. - 'break-snapshot': Allows the guest OS to continue running normally, but invalidates the snapshot and aborts related jobs. This prioritizes guest operation over backup consistency. This enhancement provides more flexibility for backup operations in different environments where requirements for guest availability versus backup consistency may vary. The default behavior remains unchanged to maintain backward compatibility. Signed-off-by: Raman Dzehtsiar <Raman.Dzehtsiar@gmail.com> --- block/backup.c | 3 ++- block/copy-before-write.c | 2 ++ block/copy-before-write.h | 1 + block/replication.c | 4 +++- blockdev.c | 6 ++++++ include/block/block_int-global-state.h | 2 ++ qapi/block-core.json | 4 ++++ 7 files changed, 20 insertions(+), 2 deletions(-)