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
6 based on migration/channel-block.c and the implementation that was
7 present in migration/savevm-async.c before QEMU 7.1.
9 Passes along read/write requests to the given BlockBackend, while
10 ensuring that a read request going beyond the end results in a
13 Additionally, allows tracking the current position from the outside
14 (intended to be used for progress tracking).
16 Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
18 migration/channel-savevm-async.c | 181 +++++++++++++++++++++++++++++++
19 migration/channel-savevm-async.h | 51 +++++++++
20 migration/meson.build | 1 +
21 3 files changed, 233 insertions(+)
22 create mode 100644 migration/channel-savevm-async.c
23 create mode 100644 migration/channel-savevm-async.h
25 diff --git a/migration/channel-savevm-async.c b/migration/channel-savevm-async.c
27 index 0000000000..efea3842cf
29 +++ b/migration/channel-savevm-async.c
32 + * QIO Channel implementation to be used by savevm-async QMP calls
34 +#include "qemu/osdep.h"
35 +#include "migration/channel-savevm-async.h"
36 +#include "qapi/error.h"
37 +#include "sysemu/block-backend.h"
40 +QIOChannelSavevmAsync *
41 +qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos)
43 + QIOChannelSavevmAsync *ioc;
45 + ioc = QIO_CHANNEL_SAVEVM_ASYNC(object_new(TYPE_QIO_CHANNEL_SAVEVM_ASYNC));
47 + bdrv_ref(blk_bs(be));
49 + ioc->bs_pos = bs_pos;
56 +qio_channel_savevm_async_finalize(Object *obj)
58 + QIOChannelSavevmAsync *ioc = QIO_CHANNEL_SAVEVM_ASYNC(obj);
61 + bdrv_unref(blk_bs(ioc->be));
69 +qio_channel_savevm_async_readv(QIOChannel *ioc,
70 + const struct iovec *iov,
76 + QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
77 + BlockBackend *be = saioc->be;
78 + int64_t maxlen = blk_getlength(be);
83 + qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
85 + if (*saioc->bs_pos >= maxlen) {
86 + error_setg(errp, "cannot read beyond maxlen");
90 + if (maxlen - *saioc->bs_pos < qiov.size) {
91 + size = maxlen - *saioc->bs_pos;
96 + // returns 0 on success
97 + ret = blk_preadv(be, *saioc->bs_pos, size, &qiov, 0);
99 + error_setg(errp, "blk_preadv returned %d", ret);
103 + *saioc->bs_pos += size;
109 +qio_channel_savevm_async_writev(QIOChannel *ioc,
110 + const struct iovec *iov,
117 + QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
118 + BlockBackend *be = saioc->be;
122 + qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
124 + if (qemu_in_coroutine()) {
125 + ret = blk_co_pwritev(be, *saioc->bs_pos, qiov.size, &qiov, 0);
128 + ret = blk_pwritev(be, *saioc->bs_pos, qiov.size, &qiov, 0);
135 + *saioc->bs_pos += qiov.size;
141 +qio_channel_savevm_async_set_blocking(QIOChannel *ioc,
146 + error_setg(errp, "Non-blocking mode not supported for savevm-async");
154 +qio_channel_savevm_async_close(QIOChannel *ioc,
157 + QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
158 + int rv = bdrv_flush(blk_bs(saioc->be));
161 + error_setg_errno(errp, -rv, "Unable to flush VMState");
165 + bdrv_unref(blk_bs(saioc->be));
167 + saioc->bs_pos = NULL;
174 +qio_channel_savevm_async_set_aio_fd_handler(QIOChannel *ioc,
176 + IOHandler *io_read,
177 + IOHandler *io_write,
180 + // if channel-block starts doing something, check if this needs adaptation
185 +qio_channel_savevm_async_class_init(ObjectClass *klass,
186 + void *class_data G_GNUC_UNUSED)
188 + QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
190 + ioc_klass->io_writev = qio_channel_savevm_async_writev;
191 + ioc_klass->io_readv = qio_channel_savevm_async_readv;
192 + ioc_klass->io_set_blocking = qio_channel_savevm_async_set_blocking;
193 + ioc_klass->io_close = qio_channel_savevm_async_close;
194 + ioc_klass->io_set_aio_fd_handler = qio_channel_savevm_async_set_aio_fd_handler;
197 +static const TypeInfo qio_channel_savevm_async_info = {
198 + .parent = TYPE_QIO_CHANNEL,
199 + .name = TYPE_QIO_CHANNEL_SAVEVM_ASYNC,
200 + .instance_size = sizeof(QIOChannelSavevmAsync),
201 + .instance_finalize = qio_channel_savevm_async_finalize,
202 + .class_init = qio_channel_savevm_async_class_init,
206 +qio_channel_savevm_async_register_types(void)
208 + type_register_static(&qio_channel_savevm_async_info);
211 +type_init(qio_channel_savevm_async_register_types);
212 diff --git a/migration/channel-savevm-async.h b/migration/channel-savevm-async.h
214 index 0000000000..17ae2cb261
216 +++ b/migration/channel-savevm-async.h
219 + * QEMU I/O channels driver for savevm-async.c
221 + * Copyright (c) 2022 Proxmox Server Solutions
224 + * Fiona Ebner (f.ebner@proxmox.com)
226 + * This work is licensed under the terms of the GNU GPL, version 2 or later.
227 + * See the COPYING file in the top-level directory.
230 +#ifndef QIO_CHANNEL_SAVEVM_ASYNC_H
231 +#define QIO_CHANNEL_SAVEVM_ASYNC_H
233 +#include "io/channel.h"
234 +#include "qom/object.h"
236 +#define TYPE_QIO_CHANNEL_SAVEVM_ASYNC "qio-channel-savevm-async"
237 +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelSavevmAsync, QIO_CHANNEL_SAVEVM_ASYNC)
241 + * QIOChannelSavevmAsync:
243 + * The QIOChannelBlock object provides a channel implementation that is able to
244 + * perform I/O on any BlockBackend whose BlockDriverState directly contains a
245 + * VMState (as opposed to indirectly, like qcow2). It allows tracking the
246 + * current position from the outside.
248 +struct QIOChannelSavevmAsync {
256 + * qio_channel_savevm_async_new:
257 + * @be: the block backend
258 + * @bs_pos: used to keep track of the IOChannels current position
260 + * Create a new IO channel object that can perform I/O on a BlockBackend object
261 + * whose BlockDriverState directly contains a VMState.
263 + * Returns: the new channel object
265 +QIOChannelSavevmAsync *
266 +qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos);
268 +#endif /* QIO_CHANNEL_SAVEVM_ASYNC_H */
269 diff --git a/migration/meson.build b/migration/meson.build
270 index 690487cf1a..8cac83c06c 100644
271 --- a/migration/meson.build
272 +++ b/migration/meson.build
273 @@ -13,6 +13,7 @@ softmmu_ss.add(files(
274 'block-dirty-bitmap.c',
277 + 'channel-savevm-async.c',