+++ /dev/null
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Fiona Ebner <f.ebner@proxmox.com>
-Date: Thu, 13 Oct 2022 11:33:50 +0200
-Subject: [PATCH] PVE: add IOChannel implementation for savevm-async
-
-based on migration/channel-block.c and the implementation that was
-present in migration/savevm-async.c before QEMU 7.1.
-
-Passes along read/write requests to the given BlockBackend, while
-ensuring that a read request going beyond the end results in a
-graceful short read.
-
-Additionally, allows tracking the current position from the outside
-(intended to be used for progress tracking).
-
-Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
----
- migration/channel-savevm-async.c | 183 +++++++++++++++++++++++++++++++
- migration/channel-savevm-async.h | 51 +++++++++
- migration/meson.build | 1 +
- 3 files changed, 235 insertions(+)
- create mode 100644 migration/channel-savevm-async.c
- create mode 100644 migration/channel-savevm-async.h
-
-diff --git a/migration/channel-savevm-async.c b/migration/channel-savevm-async.c
-new file mode 100644
-index 0000000000..aab081ce07
---- /dev/null
-+++ b/migration/channel-savevm-async.c
-@@ -0,0 +1,183 @@
-+/*
-+ * QIO Channel implementation to be used by savevm-async QMP calls
-+ */
-+#include "qemu/osdep.h"
-+#include "migration/channel-savevm-async.h"
-+#include "qapi/error.h"
-+#include "sysemu/block-backend.h"
-+#include "trace.h"
-+
-+QIOChannelSavevmAsync *
-+qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos)
-+{
-+ QIOChannelSavevmAsync *ioc;
-+
-+ ioc = QIO_CHANNEL_SAVEVM_ASYNC(object_new(TYPE_QIO_CHANNEL_SAVEVM_ASYNC));
-+
-+ bdrv_ref(blk_bs(be));
-+ ioc->be = be;
-+ ioc->bs_pos = bs_pos;
-+
-+ return ioc;
-+}
-+
-+
-+static void
-+qio_channel_savevm_async_finalize(Object *obj)
-+{
-+ QIOChannelSavevmAsync *ioc = QIO_CHANNEL_SAVEVM_ASYNC(obj);
-+
-+ if (ioc->be) {
-+ bdrv_unref(blk_bs(ioc->be));
-+ ioc->be = NULL;
-+ }
-+ ioc->bs_pos = NULL;
-+}
-+
-+
-+static ssize_t
-+qio_channel_savevm_async_readv(QIOChannel *ioc,
-+ const struct iovec *iov,
-+ size_t niov,
-+ int **fds,
-+ size_t *nfds,
-+ int flags,
-+ Error **errp)
-+{
-+ QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
-+ BlockBackend *be = saioc->be;
-+ int64_t maxlen = blk_getlength(be);
-+ QEMUIOVector qiov;
-+ size_t size;
-+ int ret;
-+
-+ qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
-+
-+ if (*saioc->bs_pos >= maxlen) {
-+ error_setg(errp, "cannot read beyond maxlen");
-+ return -1;
-+ }
-+
-+ if (maxlen - *saioc->bs_pos < qiov.size) {
-+ size = maxlen - *saioc->bs_pos;
-+ } else {
-+ size = qiov.size;
-+ }
-+
-+ // returns 0 on success
-+ ret = blk_preadv(be, *saioc->bs_pos, size, &qiov, 0);
-+ if (ret < 0) {
-+ error_setg_errno(errp, -ret, "blk_preadv failed");
-+ return -1;
-+ }
-+
-+ *saioc->bs_pos += size;
-+ return size;
-+}
-+
-+
-+static ssize_t
-+qio_channel_savevm_async_writev(QIOChannel *ioc,
-+ const struct iovec *iov,
-+ size_t niov,
-+ int *fds,
-+ size_t nfds,
-+ int flags,
-+ Error **errp)
-+{
-+ QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
-+ BlockBackend *be = saioc->be;
-+ QEMUIOVector qiov;
-+ int ret;
-+
-+ qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
-+
-+ if (qemu_in_coroutine()) {
-+ ret = blk_co_pwritev(be, *saioc->bs_pos, qiov.size, &qiov, 0);
-+ aio_wait_kick();
-+ } else {
-+ ret = blk_pwritev(be, *saioc->bs_pos, qiov.size, &qiov, 0);
-+ }
-+
-+ if (ret < 0) {
-+ error_setg_errno(errp, -ret, "blk(_co)_pwritev failed");
-+ return -1;
-+ }
-+
-+ *saioc->bs_pos += qiov.size;
-+ return qiov.size;
-+}
-+
-+
-+static int
-+qio_channel_savevm_async_set_blocking(QIOChannel *ioc,
-+ bool enabled,
-+ Error **errp)
-+{
-+ if (!enabled) {
-+ error_setg(errp, "Non-blocking mode not supported for savevm-async");
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+
-+static int
-+qio_channel_savevm_async_close(QIOChannel *ioc,
-+ Error **errp)
-+{
-+ QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
-+ int rv = bdrv_flush(blk_bs(saioc->be));
-+
-+ if (rv < 0) {
-+ error_setg_errno(errp, -rv, "Unable to flush VMState");
-+ return -1;
-+ }
-+
-+ bdrv_unref(blk_bs(saioc->be));
-+ saioc->be = NULL;
-+ saioc->bs_pos = NULL;
-+
-+ return 0;
-+}
-+
-+
-+static void
-+qio_channel_savevm_async_set_aio_fd_handler(QIOChannel *ioc,
-+ AioContext *ctx,
-+ IOHandler *io_read,
-+ IOHandler *io_write,
-+ void *opaque)
-+{
-+ // if channel-block starts doing something, check if this needs adaptation
-+}
-+
-+
-+static void
-+qio_channel_savevm_async_class_init(ObjectClass *klass,
-+ void *class_data G_GNUC_UNUSED)
-+{
-+ QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
-+
-+ ioc_klass->io_writev = qio_channel_savevm_async_writev;
-+ ioc_klass->io_readv = qio_channel_savevm_async_readv;
-+ ioc_klass->io_set_blocking = qio_channel_savevm_async_set_blocking;
-+ ioc_klass->io_close = qio_channel_savevm_async_close;
-+ ioc_klass->io_set_aio_fd_handler = qio_channel_savevm_async_set_aio_fd_handler;
-+}
-+
-+static const TypeInfo qio_channel_savevm_async_info = {
-+ .parent = TYPE_QIO_CHANNEL,
-+ .name = TYPE_QIO_CHANNEL_SAVEVM_ASYNC,
-+ .instance_size = sizeof(QIOChannelSavevmAsync),
-+ .instance_finalize = qio_channel_savevm_async_finalize,
-+ .class_init = qio_channel_savevm_async_class_init,
-+};
-+
-+static void
-+qio_channel_savevm_async_register_types(void)
-+{
-+ type_register_static(&qio_channel_savevm_async_info);
-+}
-+
-+type_init(qio_channel_savevm_async_register_types);
-diff --git a/migration/channel-savevm-async.h b/migration/channel-savevm-async.h
-new file mode 100644
-index 0000000000..17ae2cb261
---- /dev/null
-+++ b/migration/channel-savevm-async.h
-@@ -0,0 +1,51 @@
-+/*
-+ * QEMU I/O channels driver for savevm-async.c
-+ *
-+ * Copyright (c) 2022 Proxmox Server Solutions
-+ *
-+ * Authors:
-+ * Fiona Ebner (f.ebner@proxmox.com)
-+ *
-+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
-+ * See the COPYING file in the top-level directory.
-+ */
-+
-+#ifndef QIO_CHANNEL_SAVEVM_ASYNC_H
-+#define QIO_CHANNEL_SAVEVM_ASYNC_H
-+
-+#include "io/channel.h"
-+#include "qom/object.h"
-+
-+#define TYPE_QIO_CHANNEL_SAVEVM_ASYNC "qio-channel-savevm-async"
-+OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelSavevmAsync, QIO_CHANNEL_SAVEVM_ASYNC)
-+
-+
-+/**
-+ * QIOChannelSavevmAsync:
-+ *
-+ * The QIOChannelBlock object provides a channel implementation that is able to
-+ * perform I/O on any BlockBackend whose BlockDriverState directly contains a
-+ * VMState (as opposed to indirectly, like qcow2). It allows tracking the
-+ * current position from the outside.
-+ */
-+struct QIOChannelSavevmAsync {
-+ QIOChannel parent;
-+ BlockBackend *be;
-+ size_t *bs_pos;
-+};
-+
-+
-+/**
-+ * qio_channel_savevm_async_new:
-+ * @be: the block backend
-+ * @bs_pos: used to keep track of the IOChannels current position
-+ *
-+ * Create a new IO channel object that can perform I/O on a BlockBackend object
-+ * whose BlockDriverState directly contains a VMState.
-+ *
-+ * Returns: the new channel object
-+ */
-+QIOChannelSavevmAsync *
-+qio_channel_savevm_async_new(BlockBackend *be, size_t *bs_pos);
-+
-+#endif /* QIO_CHANNEL_SAVEVM_ASYNC_H */
-diff --git a/migration/meson.build b/migration/meson.build
-index 0d1bb9f96e..8a142fc7a9 100644
---- a/migration/meson.build
-+++ b/migration/meson.build
-@@ -13,6 +13,7 @@ softmmu_ss.add(files(
- 'block-dirty-bitmap.c',
- 'channel.c',
- 'channel-block.c',
-+ 'channel-savevm-async.c',
- 'colo-failover.c',
- 'colo.c',
- 'exec.c',