Enable the use of the mapped-ram migration feature with savevm/loadvm snapshots by adding the QIO_CHANNEL_FEATURE_SEEKABLE feature to QIOChannelBlock. Implement io_preadv and io_pwritev methods to provide positioned I/O capabilities that don't modify the channel's position pointer.
Signed-off-by: Marco Cavenati <marco.caven...@eurecom.fr> --- Hello, Please note that this depends on my previous fix [0] (which has already been reviewed) in order to work. The code in this patch is inspired by commit 0478b030fa2530cbbfc4d6432e8e39a16d06865b that adds the same feature to QIOChannelFile. Thank you, Regards Marco [0] [PATCH] migration: fix SEEK_CUR offset calculation in qio_channel_block_seek https://lore.kernel.org/all/20250326162230.3323199-1-marco.caven...@eurecom.fr/t/#u --- migration/channel-block.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/migration/channel-block.c b/migration/channel-block.c index fff8d87094..741cf6f31b 100644 --- a/migration/channel-block.c +++ b/migration/channel-block.c @@ -30,6 +30,7 @@ qio_channel_block_new(BlockDriverState *bs) QIOChannelBlock *ioc; ioc = QIO_CHANNEL_BLOCK(object_new(TYPE_QIO_CHANNEL_BLOCK)); + qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE); bdrv_ref(bs); ioc->bs = bs; @@ -96,6 +97,49 @@ qio_channel_block_writev(QIOChannel *ioc, return qiov.size; } +#ifdef CONFIG_PREADV +static ssize_t +qio_channel_block_preadv(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + off_t offset, + 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, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "bdrv_readv_vmstate failed"); + return -1; + } + + return qiov.size; +} + +static ssize_t +qio_channel_block_pwritev(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + off_t offset, + 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, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "bdrv_writev_vmstate failed"); + return -1; + } + + return qiov.size; +} +#endif /* CONFIG_PREADV */ static int qio_channel_block_set_blocking(QIOChannel *ioc, @@ -177,6 +221,10 @@ qio_channel_block_class_init(ObjectClass *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; +#ifdef CONFIG_PREADV + ioc_klass->io_preadv = qio_channel_block_preadv; + ioc_klass->io_pwritev = qio_channel_block_pwritev; +#endif 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; -- 2.43.0