]> git.proxmox.com Git - pve-qemu.git/blob - debian/patches/pve/0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
backup: factor out & clean up gathering device info into helper
[pve-qemu.git] / debian / patches / pve / 0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Fiona Ebner <f.ebner@proxmox.com>
3 Date: Thu, 13 Oct 2022 11:33:50 +0200
4 Subject: [PATCH] PVE: add IOChannel implementation for savevm-async
5
6 based on migration/channel-block.c and the implementation that was
7 present in migration/savevm-async.c before QEMU 7.1.
8
9 Passes along read/write requests to the given BlockBackend, while
10 ensuring that a read request going beyond the end results in a
11 graceful short read.
12
13 Additionally, allows tracking the current position from the outside
14 (intended to be used for progress tracking).
15
16 Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
17 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
18 ---
19 migration/channel-savevm-async.c | 183 +++++++++++++++++++++++++++++++
20 migration/channel-savevm-async.h | 51 +++++++++
21 migration/meson.build | 1 +
22 3 files changed, 235 insertions(+)
23 create mode 100644 migration/channel-savevm-async.c
24 create mode 100644 migration/channel-savevm-async.h
25
26 diff --git a/migration/channel-savevm-async.c b/migration/channel-savevm-async.c
27 new file mode 100644
28 index 0000000000..aab081ce07
29 --- /dev/null
30 +++ b/migration/channel-savevm-async.c
31 @@ -0,0 +1,183 @@
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,
75 + int flags,
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) {
101 + error_setg_errno(errp, -ret, "blk_preadv failed");
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) {
134 + error_setg_errno(errp, -ret, "blk(_co)_pwritev failed");
135 + return -1;
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,
178 + AioContext *ctx,
179 + IOHandler *io_read,
180 + IOHandler *io_write,
181 + void *opaque)
182 +{
183 + // if channel-block starts doing something, check if this needs adaptation
184 +}
185 +
186 +
187 +static void
188 +qio_channel_savevm_async_class_init(ObjectClass *klass,
189 + void *class_data G_GNUC_UNUSED)
190 +{
191 + QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
192 +
193 + ioc_klass->io_writev = qio_channel_savevm_async_writev;
194 + ioc_klass->io_readv = qio_channel_savevm_async_readv;
195 + ioc_klass->io_set_blocking = qio_channel_savevm_async_set_blocking;
196 + ioc_klass->io_close = qio_channel_savevm_async_close;
197 + ioc_klass->io_set_aio_fd_handler = qio_channel_savevm_async_set_aio_fd_handler;
198 +}
199 +
200 +static const TypeInfo qio_channel_savevm_async_info = {
201 + .parent = TYPE_QIO_CHANNEL,
202 + .name = TYPE_QIO_CHANNEL_SAVEVM_ASYNC,
203 + .instance_size = sizeof(QIOChannelSavevmAsync),
204 + .instance_finalize = qio_channel_savevm_async_finalize,
205 + .class_init = qio_channel_savevm_async_class_init,
206 +};
207 +
208 +static void
209 +qio_channel_savevm_async_register_types(void)
210 +{
211 + type_register_static(&qio_channel_savevm_async_info);
212 +}
213 +
214 +type_init(qio_channel_savevm_async_register_types);
215 diff --git a/migration/channel-savevm-async.h b/migration/channel-savevm-async.h
216 new file mode 100644
217 index 0000000000..17ae2cb261
218 --- /dev/null
219 +++ b/migration/channel-savevm-async.h
220 @@ -0,0 +1,51 @@
221 +/*
222 + * QEMU I/O channels driver for savevm-async.c
223 + *
224 + * Copyright (c) 2022 Proxmox Server Solutions
225 + *
226 + * Authors:
227 + * Fiona Ebner (f.ebner@proxmox.com)
228 + *
229 + * This work is licensed under the terms of the GNU GPL, version 2 or later.
230 + * See the COPYING file in the top-level directory.
231 + */
232 +
233 +#ifndef QIO_CHANNEL_SAVEVM_ASYNC_H
234 +#define QIO_CHANNEL_SAVEVM_ASYNC_H
235 +
236 +#include "io/channel.h"
237 +#include "qom/object.h"
238 +
239 +#define TYPE_QIO_CHANNEL_SAVEVM_ASYNC "qio-channel-savevm-async"
240 +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelSavevmAsync, QIO_CHANNEL_SAVEVM_ASYNC)
241 +
242 +
243 +/**
244 + * QIOChannelSavevmAsync:
245 + *
246 + * The QIOChannelBlock object provides a channel implementation that is able to
247 + * perform I/O on any BlockBackend whose BlockDriverState directly contains a
248 + * VMState (as opposed to indirectly, like qcow2). It allows tracking the
249 + * current position from the outside.
250 + */
251 +struct QIOChannelSavevmAsync {
252 + QIOChannel parent;
253 + BlockBackend *be;
254 + size_t *bs_pos;
255 +};
256 +
257 +
258 +/**
259 + * qio_channel_savevm_async_new:
260 + * @be: the block backend
261 + * @bs_pos: used to keep track of the IOChannels current position
262 + *
263 + * Create a new IO channel object that can perform I/O on a BlockBackend object
264 + * whose BlockDriverState directly contains a VMState.
265 + *
266 + * Returns: the new channel object
267 + */
268 +QIOChannelSavevmAsync *
269 +qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos);
270 +
271 +#endif /* QIO_CHANNEL_SAVEVM_ASYNC_H */
272 diff --git a/migration/meson.build b/migration/meson.build
273 index 1ae28523a1..37ddcb5d60 100644
274 --- a/migration/meson.build
275 +++ b/migration/meson.build
276 @@ -13,6 +13,7 @@ system_ss.add(files(
277 'block-dirty-bitmap.c',
278 'channel.c',
279 'channel-block.c',
280 + 'channel-savevm-async.c',
281 'dirtyrate.c',
282 'exec.c',
283 'fd.c',