]> git.proxmox.com Git - pve-qemu.git/blob - debian/patches/pve/0050-copy-before-write-allow-specifying-minimum-cluster-s.patch
backup: improve error when copy-before-write fails for fleecing
[pve-qemu.git] / debian / patches / pve / 0050-copy-before-write-allow-specifying-minimum-cluster-s.patch
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
5
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
8 target.
9
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.
14
15 The QAPI uses uint32 so the value will be non-negative, but still fit
16 into a uint64_t.
17
18 Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
19 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
20 ---
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(-)
26
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,
32 }
33
34 static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
35 + int64_t min_cluster_size,
36 Error **errp)
37 {
38 int ret;
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,
49 return ret;
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);
54 }
55
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));
59 }
60
61 BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
62 BlockDriverState *copy_bitmap_bs,
63 const BdrvDirtyBitmap *bitmap,
64 bool discard_source,
65 + int64_t min_cluster_size,
66 Error **errp)
67 {
68 ERRP_GUARD();
69 @@ -358,7 +361,13 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
70 BdrvDirtyBitmap *copy_bitmap;
71 bool is_fleecing;
72
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");
76 + return NULL;
77 + }
78 +
79 + cluster_size = block_copy_calculate_cluster_size(target->bs,
80 + min_cluster_size, errp);
81 if (cluster_size < 0) {
82 return NULL;
83 }
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,
89
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);
95 if (!s->bcs) {
96 error_prepend(errp, "Cannot create block-copy-state: ");
97 ret = -EINVAL;
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,
105 bool discard_source,
106 + int64_t min_cluster_size,
107 Error **errp);
108
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)
117 #
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.
121 +# (Since 8.1)
122 +#
123 # Since: 6.2
124 ##
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' } }
131
132 ##
133 # @BlockdevOptions: