From: Vladimir Sementsov-Ogievskiy Date: Thu, 7 Apr 2022 13:27:21 +0000 (+0300) Subject: block/copy-before-write: add on-cbw-error open parameter X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f1bb39a8a5b6d486faa1a51a7f28c577155642c9;p=qmiga%2Fqemu.git block/copy-before-write: add on-cbw-error open parameter Currently, behavior on copy-before-write operation failure is simple: report error to the guest. Let's implement alternative behavior: break the whole copy-before-write process (and corresponding backup job or NBD client) but keep guest working. It's needed if we consider guest stability as more important. The realisation is simple: on copy-before-write failure we set s->snapshot_ret and continue guest operations. s->snapshot_ret being set will lead to all further snapshot API requests. Note that all in-flight snapshot-API requests may still success: we do wait for them on BREAK_SNAPSHOT-failure path in cbw_do_copy_before_write(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Hanna Reitz Signed-off-by: Vladimir Sementsov-Ogievskiy --- diff --git a/block/copy-before-write.c b/block/copy-before-write.c index e29c46cd7a..c8a11a09d2 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -41,6 +41,7 @@ typedef struct BDRVCopyBeforeWriteState { BlockCopyState *bcs; BdrvChild *target; + OnCbwError on_cbw_error; /* * @lock: protects access to @access_bitmap, @done_bitmap and @@ -65,6 +66,14 @@ typedef struct BDRVCopyBeforeWriteState { * node. These areas must not be rewritten by guest. */ BlockReqList frozen_read_reqs; + + /* + * @snapshot_error is normally zero. But on first copy-before-write failure + * when @on_cbw_error == ON_CBW_ERROR_BREAK_SNAPSHOT, @snapshot_error takes + * value of this error (<0). After that all in-flight and further + * snapshot-API requests will fail with that error. + */ + int snapshot_error; } BDRVCopyBeforeWriteState; static coroutine_fn int cbw_co_preadv( @@ -95,16 +104,27 @@ static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs, return 0; } + if (s->snapshot_error) { + return 0; + } + off = QEMU_ALIGN_DOWN(offset, cluster_size); end = QEMU_ALIGN_UP(offset + bytes, cluster_size); ret = block_copy(s->bcs, off, end - off, true); - if (ret < 0) { + if (ret < 0 && s->on_cbw_error == ON_CBW_ERROR_BREAK_GUEST_WRITE) { return ret; } WITH_QEMU_LOCK_GUARD(&s->lock) { - bdrv_set_dirty_bitmap(s->done_bitmap, off, end - off); + if (ret < 0) { + assert(s->on_cbw_error == ON_CBW_ERROR_BREAK_SNAPSHOT); + if (!s->snapshot_error) { + s->snapshot_error = ret; + } + } else { + bdrv_set_dirty_bitmap(s->done_bitmap, off, end - off); + } reqlist_wait_all(&s->frozen_read_reqs, off, end - off, &s->lock); } @@ -176,6 +196,11 @@ static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, QEMU_LOCK_GUARD(&s->lock); + if (s->snapshot_error) { + g_free(req); + return NULL; + } + if (bdrv_dirty_bitmap_next_zero(s->access_bitmap, offset, bytes) != -1) { g_free(req); return NULL; @@ -351,6 +376,7 @@ static BlockdevOptions *cbw_parse_options(QDict *options, Error **errp) * object for original options. */ qdict_extract_subqdict(options, NULL, "bitmap"); + qdict_del(options, "on-cbw-error"); out: visit_free(v); @@ -395,6 +421,8 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags, return -EINVAL; } } + s->on_cbw_error = opts->has_on_cbw_error ? opts->on_cbw_error : + ON_CBW_ERROR_BREAK_GUEST_WRITE; bs->total_sectors = bs->file->bs->total_sectors; bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | diff --git a/qapi/block-core.json b/qapi/block-core.json index 457df16638..3e8456a94a 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4185,6 +4185,25 @@ 'data': { '*bottom': 'str' } } ## +# @OnCbwError: +# +# An enumeration of possible behaviors for copy-before-write operation +# failures. +# +# @break-guest-write: report the error to the guest. This way, the guest +# will not be able to overwrite areas that cannot be +# backed up, so the backup process remains valid. +# +# @break-snapshot: continue guest write. Doing so will make the provided +# snapshot state invalid and any backup or export +# process based on it will finally fail. +# +# Since: 7.1 +## +{ 'enum': 'OnCbwError', + 'data': [ 'break-guest-write', 'break-snapshot' ] } + +## # @BlockdevOptionsCbw: # # Driver specific block device options for the copy-before-write driver, @@ -4205,11 +4224,15 @@ # modifications (or removing) of specified bitmap doesn't # influence the filter. (Since 7.0) # +# @on-cbw-error: Behavior on failure of copy-before-write operation. +# Default is @break-guest-write. (Since 7.1) +# # Since: 6.2 ## { 'struct': 'BlockdevOptionsCbw', 'base': 'BlockdevOptionsGenericFormat', - 'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap' } } + 'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap', + '*on-cbw-error': 'OnCbwError' } } ## # @BlockdevOptions: