]> git.proxmox.com Git - pve-qemu.git/blobdiff - debian/patches/pve/0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
update submodule and patches to 7.1.0
[pve-qemu.git] / debian / patches / pve / 0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
diff --git a/debian/patches/pve/0016-PVE-add-IOChannel-implementation-for-savevm-async.patch b/debian/patches/pve/0016-PVE-add-IOChannel-implementation-for-savevm-async.patch
new file mode 100644 (file)
index 0000000..e48eb9d
--- /dev/null
@@ -0,0 +1,280 @@
+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 | 181 +++++++++++++++++++++++++++++++
+ migration/channel-savevm-async.h |  51 +++++++++
+ migration/meson.build            |   1 +
+ 3 files changed, 233 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..efea3842cf
+--- /dev/null
++++ b/migration/channel-savevm-async.c
+@@ -0,0 +1,181 @@
++/*
++ * 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,
++                               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(errp, "blk_preadv returned %d", ret);
++        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) {
++        return ret;
++    }
++
++    *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 690487cf1a..8cac83c06c 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',