1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Fiona Ebner <f.ebner@proxmox.com>
3 Date: Thu, 11 Apr 2024 11:29:26 +0200
4 Subject: [PATCH] copy-before-write: allow specifying minimum cluster size
6 Useful to make discard-source work in the context of backup fleecing
7 when the fleecing image has a larger granularity than the backup
10 Copy-before-write operations will use at least this granularity and in
11 particular, discard requests to the source node will too. If the
12 granularity is too small, they will just be aligned down in
13 cbw_co_pdiscard_snapshot() and thus effectively ignored.
15 The QAPI uses uint32 so the value will be non-negative, but still fit
18 Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
19 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
21 block/block-copy.c | 17 +++++++++++++----
22 block/copy-before-write.c | 3 ++-
23 include/block/block-copy.h | 1 +
24 qapi/block-core.json | 8 +++++++-
25 4 files changed, 23 insertions(+), 6 deletions(-)
27 diff --git a/block/block-copy.c b/block/block-copy.c
28 index 3c61e52bae..c9a722a5a6 100644
29 --- a/block/block-copy.c
30 +++ b/block/block-copy.c
31 @@ -310,6 +310,7 @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
34 static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
35 + int64_t min_cluster_size,
39 @@ -330,7 +331,7 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
40 "used. If the actual block size of the target exceeds "
41 "this default, the backup may be unusable",
42 BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
43 - return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
44 + return MAX(min_cluster_size, BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
45 } else if (ret < 0 && !target_does_cow) {
46 error_setg_errno(errp, -ret,
47 "Couldn't determine the cluster size of the target image, "
48 @@ -340,16 +341,18 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
50 } else if (ret < 0 && target_does_cow) {
51 /* Not fatal; just trudge on ahead. */
52 - return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
53 + return MAX(min_cluster_size, BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
56 - return MAX(BLOCK_COPY_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
57 + return MAX(min_cluster_size,
58 + MAX(BLOCK_COPY_CLUSTER_SIZE_DEFAULT, bdi.cluster_size));
61 BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
62 BlockDriverState *copy_bitmap_bs,
63 const BdrvDirtyBitmap *bitmap,
65 + int64_t min_cluster_size,
69 @@ -358,7 +361,13 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
70 BdrvDirtyBitmap *copy_bitmap;
73 - cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
74 + if (min_cluster_size && !is_power_of_2(min_cluster_size)) {
75 + error_setg(errp, "min-cluster-size needs to be a power of 2");
79 + cluster_size = block_copy_calculate_cluster_size(target->bs,
80 + min_cluster_size, errp);
81 if (cluster_size < 0) {
84 diff --git a/block/copy-before-write.c b/block/copy-before-write.c
85 index 3503702d71..4a8c5bdb62 100644
86 --- a/block/copy-before-write.c
87 +++ b/block/copy-before-write.c
88 @@ -479,7 +479,8 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
90 s->discard_source = flags & BDRV_O_CBW_DISCARD_SOURCE;
91 s->bcs = block_copy_state_new(bs->file, s->target, bs, bitmap,
92 - flags & BDRV_O_CBW_DISCARD_SOURCE, errp);
93 + flags & BDRV_O_CBW_DISCARD_SOURCE,
94 + opts->min_cluster_size, errp);
96 error_prepend(errp, "Cannot create block-copy-state: ");
98 diff --git a/include/block/block-copy.h b/include/block/block-copy.h
99 index bdc703bacd..77857c6c68 100644
100 --- a/include/block/block-copy.h
101 +++ b/include/block/block-copy.h
102 @@ -28,6 +28,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
103 BlockDriverState *copy_bitmap_bs,
104 const BdrvDirtyBitmap *bitmap,
106 + int64_t min_cluster_size,
109 /* Function should be called prior any actual copy request */
110 diff --git a/qapi/block-core.json b/qapi/block-core.json
111 index 4297e5beda..33e7e3c090 100644
112 --- a/qapi/block-core.json
113 +++ b/qapi/block-core.json
114 @@ -4825,12 +4825,18 @@
115 # @on-cbw-error parameter will decide how this failure is handled.
116 # Default 0. (Since 7.1)
118 +# @min-cluster-size: Minimum size of blocks used by copy-before-write
119 +# operations. Has to be a power of 2. No effect if smaller than
120 +# the maximum of the target's cluster size and 64 KiB. Default 0.
125 { 'struct': 'BlockdevOptionsCbw',
126 'base': 'BlockdevOptionsGenericFormat',
127 'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap',
128 - '*on-cbw-error': 'OnCbwError', '*cbw-timeout': 'uint32' } }
129 + '*on-cbw-error': 'OnCbwError', '*cbw-timeout': 'uint32',
130 + '*min-cluster-size': 'uint32' } }