]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/pve/0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
backup: improve error when copy-before-write fails for fleecing
[pve-qemu.git] / debian / patches / pve / 0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
CommitLineData
5b15e2ec
FE
1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Fiona Ebner <f.ebner@proxmox.com>
3Date: Thu, 13 Oct 2022 11:33:50 +0200
4Subject: [PATCH] PVE: add IOChannel implementation for savevm-async
5
6based on migration/channel-block.c and the implementation that was
7present in migration/savevm-async.c before QEMU 7.1.
8
9Passes along read/write requests to the given BlockBackend, while
10ensuring that a read request going beyond the end results in a
11graceful short read.
12
13Additionally, allows tracking the current position from the outside
14(intended to be used for progress tracking).
15
16Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
8dd76cc5 17Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
5b15e2ec 18---
f1eed34a 19 migration/channel-savevm-async.c | 184 +++++++++++++++++++++++++++++++
5b15e2ec
FE
20 migration/channel-savevm-async.h | 51 +++++++++
21 migration/meson.build | 1 +
f1eed34a 22 3 files changed, 236 insertions(+)
5b15e2ec
FE
23 create mode 100644 migration/channel-savevm-async.c
24 create mode 100644 migration/channel-savevm-async.h
25
26diff --git a/migration/channel-savevm-async.c b/migration/channel-savevm-async.c
27new file mode 100644
f1eed34a 28index 0000000000..081a192f49
5b15e2ec
FE
29--- /dev/null
30+++ b/migration/channel-savevm-async.c
f1eed34a 31@@ -0,0 +1,184 @@
5b15e2ec
FE
32+/*
33+ * QIO Channel implementation to be used by savevm-async QMP calls
34+ */
35+#include "qemu/osdep.h"
36+#include "migration/channel-savevm-async.h"
37+#include "qapi/error.h"
38+#include "sysemu/block-backend.h"
39+#include "trace.h"
40+
41+QIOChannelSavevmAsync *
42+qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos)
43+{
44+ QIOChannelSavevmAsync *ioc;
45+
46+ ioc = QIO_CHANNEL_SAVEVM_ASYNC(object_new(TYPE_QIO_CHANNEL_SAVEVM_ASYNC));
47+
48+ bdrv_ref(blk_bs(be));
49+ ioc->be = be;
50+ ioc->bs_pos = bs_pos;
51+
52+ return ioc;
53+}
54+
55+
56+static void
57+qio_channel_savevm_async_finalize(Object *obj)
58+{
59+ QIOChannelSavevmAsync *ioc = QIO_CHANNEL_SAVEVM_ASYNC(obj);
60+
61+ if (ioc->be) {
62+ bdrv_unref(blk_bs(ioc->be));
63+ ioc->be = NULL;
64+ }
65+ ioc->bs_pos = NULL;
66+}
67+
68+
69+static ssize_t
70+qio_channel_savevm_async_readv(QIOChannel *ioc,
71+ const struct iovec *iov,
72+ size_t niov,
73+ int **fds,
74+ size_t *nfds,
bf251437 75+ int flags,
5b15e2ec
FE
76+ Error **errp)
77+{
78+ QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
79+ BlockBackend *be = saioc->be;
80+ int64_t maxlen = blk_getlength(be);
81+ QEMUIOVector qiov;
82+ size_t size;
83+ int ret;
84+
85+ qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
86+
87+ if (*saioc->bs_pos >= maxlen) {
88+ error_setg(errp, "cannot read beyond maxlen");
89+ return -1;
90+ }
91+
92+ if (maxlen - *saioc->bs_pos < qiov.size) {
93+ size = maxlen - *saioc->bs_pos;
94+ } else {
95+ size = qiov.size;
96+ }
97+
98+ // returns 0 on success
99+ ret = blk_preadv(be, *saioc->bs_pos, size, &qiov, 0);
100+ if (ret < 0) {
0af826b4 101+ error_setg_errno(errp, -ret, "blk_preadv failed");
5b15e2ec
FE
102+ return -1;
103+ }
104+
105+ *saioc->bs_pos += size;
106+ return size;
107+}
108+
109+
110+static ssize_t
111+qio_channel_savevm_async_writev(QIOChannel *ioc,
112+ const struct iovec *iov,
113+ size_t niov,
114+ int *fds,
115+ size_t nfds,
116+ int flags,
117+ Error **errp)
118+{
119+ QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
120+ BlockBackend *be = saioc->be;
121+ QEMUIOVector qiov;
122+ int ret;
123+
124+ qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
125+
126+ if (qemu_in_coroutine()) {
127+ ret = blk_co_pwritev(be, *saioc->bs_pos, qiov.size, &qiov, 0);
128+ aio_wait_kick();
129+ } else {
130+ ret = blk_pwritev(be, *saioc->bs_pos, qiov.size, &qiov, 0);
131+ }
132+
133+ if (ret < 0) {
0af826b4
FE
134+ error_setg_errno(errp, -ret, "blk(_co)_pwritev failed");
135+ return -1;
5b15e2ec
FE
136+ }
137+
138+ *saioc->bs_pos += qiov.size;
139+ return qiov.size;
140+}
141+
142+
143+static int
144+qio_channel_savevm_async_set_blocking(QIOChannel *ioc,
145+ bool enabled,
146+ Error **errp)
147+{
148+ if (!enabled) {
149+ error_setg(errp, "Non-blocking mode not supported for savevm-async");
150+ return -1;
151+ }
152+ return 0;
153+}
154+
155+
156+static int
157+qio_channel_savevm_async_close(QIOChannel *ioc,
158+ Error **errp)
159+{
160+ QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
161+ int rv = bdrv_flush(blk_bs(saioc->be));
162+
163+ if (rv < 0) {
164+ error_setg_errno(errp, -rv, "Unable to flush VMState");
165+ return -1;
166+ }
167+
168+ bdrv_unref(blk_bs(saioc->be));
169+ saioc->be = NULL;
170+ saioc->bs_pos = NULL;
171+
172+ return 0;
173+}
174+
175+
176+static void
177+qio_channel_savevm_async_set_aio_fd_handler(QIOChannel *ioc,
f1eed34a 178+ AioContext *read_ctx,
5b15e2ec 179+ IOHandler *io_read,
f1eed34a 180+ AioContext *write_ctx,
5b15e2ec
FE
181+ IOHandler *io_write,
182+ void *opaque)
183+{
184+ // if channel-block starts doing something, check if this needs adaptation
185+}
186+
187+
188+static void
189+qio_channel_savevm_async_class_init(ObjectClass *klass,
190+ void *class_data G_GNUC_UNUSED)
191+{
192+ QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
193+
194+ ioc_klass->io_writev = qio_channel_savevm_async_writev;
195+ ioc_klass->io_readv = qio_channel_savevm_async_readv;
196+ ioc_klass->io_set_blocking = qio_channel_savevm_async_set_blocking;
197+ ioc_klass->io_close = qio_channel_savevm_async_close;
198+ ioc_klass->io_set_aio_fd_handler = qio_channel_savevm_async_set_aio_fd_handler;
199+}
200+
201+static const TypeInfo qio_channel_savevm_async_info = {
202+ .parent = TYPE_QIO_CHANNEL,
203+ .name = TYPE_QIO_CHANNEL_SAVEVM_ASYNC,
204+ .instance_size = sizeof(QIOChannelSavevmAsync),
205+ .instance_finalize = qio_channel_savevm_async_finalize,
206+ .class_init = qio_channel_savevm_async_class_init,
207+};
208+
209+static void
210+qio_channel_savevm_async_register_types(void)
211+{
212+ type_register_static(&qio_channel_savevm_async_info);
213+}
214+
215+type_init(qio_channel_savevm_async_register_types);
216diff --git a/migration/channel-savevm-async.h b/migration/channel-savevm-async.h
217new file mode 100644
218index 0000000000..17ae2cb261
219--- /dev/null
220+++ b/migration/channel-savevm-async.h
221@@ -0,0 +1,51 @@
222+/*
223+ * QEMU I/O channels driver for savevm-async.c
224+ *
225+ * Copyright (c) 2022 Proxmox Server Solutions
226+ *
227+ * Authors:
228+ * Fiona Ebner (f.ebner@proxmox.com)
229+ *
230+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
231+ * See the COPYING file in the top-level directory.
232+ */
233+
234+#ifndef QIO_CHANNEL_SAVEVM_ASYNC_H
235+#define QIO_CHANNEL_SAVEVM_ASYNC_H
236+
237+#include "io/channel.h"
238+#include "qom/object.h"
239+
240+#define TYPE_QIO_CHANNEL_SAVEVM_ASYNC "qio-channel-savevm-async"
241+OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelSavevmAsync, QIO_CHANNEL_SAVEVM_ASYNC)
242+
243+
244+/**
245+ * QIOChannelSavevmAsync:
246+ *
247+ * The QIOChannelBlock object provides a channel implementation that is able to
248+ * perform I/O on any BlockBackend whose BlockDriverState directly contains a
249+ * VMState (as opposed to indirectly, like qcow2). It allows tracking the
250+ * current position from the outside.
251+ */
252+struct QIOChannelSavevmAsync {
253+ QIOChannel parent;
254+ BlockBackend *be;
255+ size_t *bs_pos;
256+};
257+
258+
259+/**
260+ * qio_channel_savevm_async_new:
261+ * @be: the block backend
262+ * @bs_pos: used to keep track of the IOChannels current position
263+ *
264+ * Create a new IO channel object that can perform I/O on a BlockBackend object
265+ * whose BlockDriverState directly contains a VMState.
266+ *
267+ * Returns: the new channel object
268+ */
269+QIOChannelSavevmAsync *
270+qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos);
271+
272+#endif /* QIO_CHANNEL_SAVEVM_ASYNC_H */
273diff --git a/migration/meson.build b/migration/meson.build
4fbd50e2 274index 1eeb915ff6..95d1cf2250 100644
5b15e2ec
FE
275--- a/migration/meson.build
276+++ b/migration/meson.build
10e10933 277@@ -13,6 +13,7 @@ system_ss.add(files(
5b15e2ec
FE
278 'block-dirty-bitmap.c',
279 'channel.c',
280 'channel-block.c',
281+ 'channel-savevm-async.c',
10e10933 282 'dirtyrate.c',
5b15e2ec 283 'exec.c',
10e10933 284 'fd.c',