Marco Cavenati <marco.caven...@eurecom.fr> writes: > 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.
We'll need to add the infrastructure to reject multifd and direct-io before this. The rest of the capabilities should not affect mapped-ram, so it's fine (for now) if we don't honor them. What about zero page handling? Mapped-ram doesn't send zero pages because the file will always have zeroes in it and the migration destination is guaranteed to not have been running previously. I believe loading a snapshot in a VM that's already been running would leave stale data in the guest's memory. > > 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;