Daniel P. Berrangé <berra...@redhat.com> wrote: > Introduce a QIOChannelBlock class that exposes the BlockDriverState > VMState region for I/O. > > This is kept in the migration/ directory rather than io/, to avoid > a mutual dependancy between block/ <-> io/ directories. Also the > VMState should only be used by the migration code. > > Reviewed-by: Daniel P. Berrangé <berra...@redhat.com>
I will maggically charge this to a: Signed-off-by: Daniel P. Berrangé <berra...@redhat.com> O:-) > --- > migration/channel-block.c | 195 ++++++++++++++++++++++++++++++++++++++ > migration/channel-block.h | 59 ++++++++++++ > migration/meson.build | 1 + > 3 files changed, 255 insertions(+) > create mode 100644 migration/channel-block.c > create mode 100644 migration/channel-block.h > > diff --git a/migration/channel-block.c b/migration/channel-block.c > new file mode 100644 > index 0000000000..ad52342c10 > --- /dev/null > +++ b/migration/channel-block.c > @@ -0,0 +1,195 @@ > +/* > + * QEMU I/O channels block driver > + * > + * Copyright (c) 2022 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + * > + */ > + > +#include "qemu/osdep.h" > +#include "migration/channel-block.h" > +#include "qapi/error.h" > +#include "block/block.h" > +#include "trace.h" > + > +QIOChannelBlock * > +qio_channel_block_new(BlockDriverState *bs) > +{ > + QIOChannelBlock *ioc; > + > + ioc = QIO_CHANNEL_BLOCK(object_new(TYPE_QIO_CHANNEL_BLOCK)); > + > + bdrv_ref(bs); > + ioc->bs = bs; > + > + return ioc; > +} > + > + > +static void > +qio_channel_block_finalize(Object *obj) > +{ > + QIOChannelBlock *ioc = QIO_CHANNEL_BLOCK(obj); > + > + g_clear_pointer(&ioc->bs, bdrv_unref); > +} > + > + > +static ssize_t > +qio_channel_block_readv(QIOChannel *ioc, > + const struct iovec *iov, > + size_t niov, > + int **fds, > + size_t *nfds, > + Error **errp) > +{ > + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); > + QEMUIOVector qiov; > + int ret; > + > + qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); > + ret = bdrv_readv_vmstate(bioc->bs, &qiov, bioc->offset); > + if (ret < 0) { > + return ret; > + } > + > + bioc->offset += qiov.size; > + return qiov.size; > +} > + > + > +static ssize_t > +qio_channel_block_writev(QIOChannel *ioc, > + const struct iovec *iov, > + size_t niov, > + int *fds, > + size_t nfds, > + int flags, > + Error **errp) > +{ > + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); > + QEMUIOVector qiov; > + int ret; > + > + qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); > + ret = bdrv_writev_vmstate(bioc->bs, &qiov, bioc->offset); > + if (ret < 0) { > + return ret; > + } > + > + bioc->offset += qiov.size; > + return qiov.size; > +} > + > + > +static int > +qio_channel_block_set_blocking(QIOChannel *ioc, > + bool enabled, > + Error **errp) > +{ > + if (!enabled) { > + error_setg(errp, "Non-blocking mode not supported for block > devices"); > + return -1; > + } > + return 0; > +} > + > + > +static off_t > +qio_channel_block_seek(QIOChannel *ioc, > + off_t offset, > + int whence, > + Error **errp) > +{ > + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); > + > + switch (whence) { > + case SEEK_SET: > + bioc->offset = offset; > + break; > + case SEEK_CUR: > + bioc->offset += whence; > + break; > + case SEEK_END: > + error_setg(errp, "Size of VMstate region is unknown"); > + return (off_t)-1; > + default: > + g_assert_not_reached(); > + } > + > + return bioc->offset; > +} > + > + > +static int > +qio_channel_block_close(QIOChannel *ioc, > + Error **errp) > +{ > + QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); > + int rv; > + > + if ((rv = bdrv_flush(bioc->bs)) < 0) { > + error_setg_errno(errp, -rv, > + "Unable to flush VMState"); > + return -1; > + } > + > + g_clear_pointer(&bioc->bs, bdrv_unref); > + bioc->offset = 0; > + > + return 0; > +} > + > + > +static void > +qio_channel_block_set_aio_fd_handler(QIOChannel *ioc, > + AioContext *ctx, > + IOHandler *io_read, > + IOHandler *io_write, > + void *opaque) > +{ > + /* XXX anything we can do here ? */ > +} > + > + > +static void > +qio_channel_block_class_init(ObjectClass *klass, > + void *class_data G_GNUC_UNUSED) > +{ > + QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); > + > + ioc_klass->io_writev = qio_channel_block_writev; > + ioc_klass->io_readv = qio_channel_block_readv; > + ioc_klass->io_set_blocking = qio_channel_block_set_blocking; > + ioc_klass->io_seek = qio_channel_block_seek; > + ioc_klass->io_close = qio_channel_block_close; > + ioc_klass->io_set_aio_fd_handler = qio_channel_block_set_aio_fd_handler; > +} > + > +static const TypeInfo qio_channel_block_info = { > + .parent = TYPE_QIO_CHANNEL, > + .name = TYPE_QIO_CHANNEL_BLOCK, > + .instance_size = sizeof(QIOChannelBlock), > + .instance_finalize = qio_channel_block_finalize, > + .class_init = qio_channel_block_class_init, > +}; > + > +static void > +qio_channel_block_register_types(void) > +{ > + type_register_static(&qio_channel_block_info); > +} > + > +type_init(qio_channel_block_register_types); > diff --git a/migration/channel-block.h b/migration/channel-block.h > new file mode 100644 > index 0000000000..31673824e6 > --- /dev/null > +++ b/migration/channel-block.h > @@ -0,0 +1,59 @@ > +/* > + * QEMU I/O channels block driver > + * > + * Copyright (c) 2022 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + * > + */ > + > +#ifndef QIO_CHANNEL_BLOCK_H > +#define QIO_CHANNEL_BLOCK_H > + > +#include "io/channel.h" > +#include "qom/object.h" > + > +#define TYPE_QIO_CHANNEL_BLOCK "qio-channel-block" > +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBlock, QIO_CHANNEL_BLOCK) > + > + > +/** > + * QIOChannelBlock: > + * > + * The QIOChannelBlock object provides a channel implementation > + * that is able to perform I/O on the BlockDriverState objects > + * to the VMState region. > + */ > + > +struct QIOChannelBlock { > + QIOChannel parent; > + BlockDriverState *bs; > + off_t offset; > +}; > + > + > +/** > + * qio_channel_block_new: > + * @bs: the block driver state > + * > + * Create a new IO channel object that can perform > + * I/O on a BlockDriverState object to the VMState > + * region > + * > + * Returns: the new channel object > + */ > +QIOChannelBlock * > +qio_channel_block_new(BlockDriverState *bs); > + > +#endif /* QIO_CHANNEL_BLOCK_H */ > diff --git a/migration/meson.build b/migration/meson.build > index 6880b61b10..8d309f5849 100644 > --- a/migration/meson.build > +++ b/migration/meson.build > @@ -13,6 +13,7 @@ softmmu_ss.add(migration_files) > softmmu_ss.add(files( > 'block-dirty-bitmap.c', > 'channel.c', > + 'channel-block.c', > 'colo-failover.c', > 'colo.c', > 'exec.c',