]> git.proxmox.com Git - pve-qemu.git/blob - debian/patches/pve/0030-PVE-Backup-add-backup-dump-block-driver.patch
9b3f8910b72a03026e089077b7f499d5b27f5ab9
[pve-qemu.git] / debian / patches / pve / 0030-PVE-Backup-add-backup-dump-block-driver.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Dietmar Maurer <dietmar@proxmox.com>
3 Date: Tue, 10 Mar 2020 12:55:27 +0100
4 Subject: [PATCH 30/32] PVE-Backup: add backup-dump block driver
5
6 - add backup-dump block driver block/backup-dump.c
7 - move BackupBlockJob declaration from block/backup.c to include/block/block_int.h
8 - block/backup.c - backup-job-create: also consider source cluster size
9 - block/io.c - bdrv_do_drained_begin_quiesce: check for coroutine
10 - job.c: make job_should_pause non-static
11 ---
12 block/Makefile.objs | 1 +
13 block/backup-dump.c | 169 ++++++++++++++++++++++++++++++++++++++
14 block/backup.c | 23 ++----
15 block/io.c | 8 +-
16 include/block/block_int.h | 30 +++++++
17 job.c | 3 +-
18 6 files changed, 214 insertions(+), 20 deletions(-)
19 create mode 100644 block/backup-dump.c
20
21 diff --git a/block/Makefile.objs b/block/Makefile.objs
22 index a10ceabf5b..5cd9e40d8d 100644
23 --- a/block/Makefile.objs
24 +++ b/block/Makefile.objs
25 @@ -33,6 +33,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
26 block-obj-$(CONFIG_GLUSTERFS) += gluster.o
27 block-obj-$(CONFIG_VXHS) += vxhs.o
28 block-obj-$(CONFIG_LIBSSH) += ssh.o
29 +block-obj-y += backup-dump.o
30 block-obj-y += accounting.o dirty-bitmap.o
31 block-obj-y += write-threshold.o
32 block-obj-y += backup.o
33 diff --git a/block/backup-dump.c b/block/backup-dump.c
34 new file mode 100644
35 index 0000000000..3066ab0698
36 --- /dev/null
37 +++ b/block/backup-dump.c
38 @@ -0,0 +1,169 @@
39 +/*
40 + * BlockDriver to send backup data stream to a callback function
41 + *
42 + * Copyright (C) 2020 Proxmox Server Solutions GmbH
43 + *
44 + * This work is licensed under the terms of the GNU GPL, version 2 or later.
45 + * See the COPYING file in the top-level directory.
46 + *
47 + */
48 +
49 +#include "qemu/osdep.h"
50 +#include "qemu-common.h"
51 +#include "qom/object_interfaces.h"
52 +#include "block/block_int.h"
53 +
54 +typedef struct {
55 + int dump_cb_block_size;
56 + uint64_t byte_size;
57 + BackupDumpFunc *dump_cb;
58 + void *dump_cb_data;
59 +} BDRVBackupDumpState;
60 +
61 +static int qemu_backup_dump_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
62 +{
63 + BDRVBackupDumpState *s = bs->opaque;
64 +
65 + bdi->cluster_size = s->dump_cb_block_size;
66 + bdi->unallocated_blocks_are_zero = true;
67 + return 0;
68 +}
69 +
70 +static int qemu_backup_dump_check_perm(
71 + BlockDriverState *bs,
72 + uint64_t perm,
73 + uint64_t shared,
74 + Error **errp)
75 +{
76 + /* Nothing to do. */
77 + return 0;
78 +}
79 +
80 +static void qemu_backup_dump_set_perm(
81 + BlockDriverState *bs,
82 + uint64_t perm,
83 + uint64_t shared)
84 +{
85 + /* Nothing to do. */
86 +}
87 +
88 +static void qemu_backup_dump_abort_perm_update(BlockDriverState *bs)
89 +{
90 + /* Nothing to do. */
91 +}
92 +
93 +static void qemu_backup_dump_refresh_limits(BlockDriverState *bs, Error **errp)
94 +{
95 + bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
96 +}
97 +
98 +static void qemu_backup_dump_close(BlockDriverState *bs)
99 +{
100 + /* Nothing to do. */
101 +}
102 +
103 +static int64_t qemu_backup_dump_getlength(BlockDriverState *bs)
104 +{
105 + BDRVBackupDumpState *s = bs->opaque;
106 +
107 + return s->byte_size;
108 +}
109 +
110 +static coroutine_fn int qemu_backup_dump_co_writev(
111 + BlockDriverState *bs,
112 + int64_t sector_num,
113 + int nb_sectors,
114 + QEMUIOVector *qiov,
115 + int flags)
116 +{
117 + /* flags can be only values we set in supported_write_flags */
118 + assert(flags == 0);
119 +
120 + BDRVBackupDumpState *s = bs->opaque;
121 + off_t offset = sector_num * BDRV_SECTOR_SIZE;
122 +
123 + uint64_t written = 0;
124 +
125 + for (int i = 0; i < qiov->niov; ++i) {
126 + const struct iovec *v = &qiov->iov[i];
127 +
128 + int rc = s->dump_cb(s->dump_cb_data, offset, v->iov_len, v->iov_base);
129 + if (rc < 0) {
130 + return rc;
131 + }
132 +
133 + if (rc != v->iov_len) {
134 + return -EIO;
135 + }
136 +
137 + written += v->iov_len;
138 + offset += v->iov_len;
139 + }
140 +
141 + return written;
142 +}
143 +
144 +static void qemu_backup_dump_child_perm(
145 + BlockDriverState *bs,
146 + BdrvChild *c,
147 + const BdrvChildRole *role,
148 + BlockReopenQueue *reopen_queue,
149 + uint64_t perm, uint64_t shared,
150 + uint64_t *nperm, uint64_t *nshared)
151 +{
152 + *nperm = BLK_PERM_ALL;
153 + *nshared = BLK_PERM_ALL;
154 +}
155 +
156 +static BlockDriver bdrv_backup_dump_drive = {
157 + .format_name = "backup-dump-drive",
158 + .protocol_name = "backup-dump",
159 + .instance_size = sizeof(BDRVBackupDumpState),
160 +
161 + .bdrv_close = qemu_backup_dump_close,
162 + .bdrv_has_zero_init = bdrv_has_zero_init_1,
163 + .bdrv_getlength = qemu_backup_dump_getlength,
164 + .bdrv_get_info = qemu_backup_dump_get_info,
165 +
166 + .bdrv_co_writev = qemu_backup_dump_co_writev,
167 +
168 + .bdrv_refresh_limits = qemu_backup_dump_refresh_limits,
169 + .bdrv_check_perm = qemu_backup_dump_check_perm,
170 + .bdrv_set_perm = qemu_backup_dump_set_perm,
171 + .bdrv_abort_perm_update = qemu_backup_dump_abort_perm_update,
172 + .bdrv_child_perm = qemu_backup_dump_child_perm,
173 +};
174 +
175 +static void bdrv_backup_dump_init(void)
176 +{
177 + bdrv_register(&bdrv_backup_dump_drive);
178 +}
179 +
180 +block_init(bdrv_backup_dump_init);
181 +
182 +
183 +BlockDriverState *bdrv_backup_dump_create(
184 + int dump_cb_block_size,
185 + uint64_t byte_size,
186 + BackupDumpFunc *dump_cb,
187 + void *dump_cb_data,
188 + Error **errp)
189 +{
190 + BDRVBackupDumpState *state;
191 + BlockDriverState *bs = bdrv_new_open_driver(
192 + &bdrv_backup_dump_drive, NULL, BDRV_O_RDWR, errp);
193 +
194 + if (!bs) {
195 + return NULL;
196 + }
197 +
198 + bs->total_sectors = byte_size / BDRV_SECTOR_SIZE;
199 + bs->opaque = state = g_new0(BDRVBackupDumpState, 1);
200 +
201 + state->dump_cb_block_size = dump_cb_block_size;
202 + state->byte_size = byte_size;
203 + state->dump_cb = dump_cb;
204 + state->dump_cb_data = dump_cb_data;
205 +
206 + return bs;
207 +}
208 diff --git a/block/backup.c b/block/backup.c
209 index c155081de2..9d23da027f 100644
210 --- a/block/backup.c
211 +++ b/block/backup.c
212 @@ -32,24 +32,6 @@
213
214 #define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
215
216 -typedef struct BackupBlockJob {
217 - BlockJob common;
218 - BlockDriverState *backup_top;
219 - BlockDriverState *source_bs;
220 -
221 - BdrvDirtyBitmap *sync_bitmap;
222 -
223 - MirrorSyncMode sync_mode;
224 - BitmapSyncMode bitmap_mode;
225 - BlockdevOnError on_source_error;
226 - BlockdevOnError on_target_error;
227 - uint64_t len;
228 - uint64_t bytes_read;
229 - int64_t cluster_size;
230 -
231 - BlockCopyState *bcs;
232 -} BackupBlockJob;
233 -
234 static const BlockJobDriver backup_job_driver;
235
236 static void backup_progress_bytes_callback(int64_t bytes, void *opaque)
237 @@ -420,6 +402,11 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
238 goto error;
239 }
240
241 + BlockDriverInfo bdi;
242 + if (bdrv_get_info(bs, &bdi) == 0) {
243 + cluster_size = MAX(cluster_size, bdi.cluster_size);
244 + }
245 +
246 /*
247 * If source is in backing chain of target assume that target is going to be
248 * used for "image fleecing", i.e. it should represent a kind of snapshot of
249 diff --git a/block/io.c b/block/io.c
250 index f75777f5ea..75dea5ae33 100644
251 --- a/block/io.c
252 +++ b/block/io.c
253 @@ -381,7 +381,13 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
254 void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
255 BdrvChild *parent, bool ignore_bds_parents)
256 {
257 - assert(!qemu_in_coroutine());
258 + // AFAICT this function is just an optimization, but sadly it doesn't play
259 + // nice with the PVE backup code (when we're in a coroutine, even in
260 + // pvebackup_co_start), so just call the full-blown drain begin instead
261 + if (qemu_in_coroutine()) {
262 + bdrv_do_drained_begin(bs, false, parent, ignore_bds_parents, false);
263 + return;
264 + }
265
266 /* Stop things in parent-to-child order */
267 if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
268 diff --git a/include/block/block_int.h b/include/block/block_int.h
269 index b0d5eb9485..105bffe0f7 100644
270 --- a/include/block/block_int.h
271 +++ b/include/block/block_int.h
272 @@ -60,6 +60,36 @@
273
274 #define BLOCK_PROBE_BUF_SIZE 512
275
276 +typedef int BackupDumpFunc(void *opaque, uint64_t offset, uint64_t bytes, const void *buf);
277 +
278 +BlockDriverState *bdrv_backuo_dump_create(
279 + int dump_cb_block_size,
280 + uint64_t byte_size,
281 + BackupDumpFunc *dump_cb,
282 + void *dump_cb_data,
283 + Error **errp);
284 +
285 +// Needs to be defined here, since it's used in blockdev.c to detect PVE backup
286 +// jobs with source_bs
287 +typedef struct BlockCopyState BlockCopyState;
288 +typedef struct BackupBlockJob {
289 + BlockJob common;
290 + BlockDriverState *backup_top;
291 + BlockDriverState *source_bs;
292 +
293 + BdrvDirtyBitmap *sync_bitmap;
294 +
295 + MirrorSyncMode sync_mode;
296 + BitmapSyncMode bitmap_mode;
297 + BlockdevOnError on_source_error;
298 + BlockdevOnError on_target_error;
299 + uint64_t len;
300 + uint64_t bytes_read;
301 + int64_t cluster_size;
302 +
303 + BlockCopyState *bcs;
304 +} BackupBlockJob;
305 +
306 enum BdrvTrackedRequestType {
307 BDRV_TRACKED_READ,
308 BDRV_TRACKED_WRITE,
309 diff --git a/job.c b/job.c
310 index 7554f735e3..b03ef989e2 100644
311 --- a/job.c
312 +++ b/job.c
313 @@ -248,7 +248,8 @@ static bool job_started(Job *job)
314 return job->co;
315 }
316
317 -static bool job_should_pause(Job *job)
318 +bool job_should_pause(Job *job);
319 +bool job_should_pause(Job *job)
320 {
321 return job->pause_count > 0;
322 }