Just a naming nit.
On Wed, Aug 13, 2025 at 12:54 PM Vladimir Sementsov-Ogievskiy
<vsementsov@yandex-team.ru> wrote:
>
> In case of local backend migration, skip backend-related
> initialization, but instead get the state from migration
> channel (including secondary channel file descriptor).
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
> hw/virtio/vhost-user.c | 62 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 62 insertions(+)
>
> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> index 3979582975..f220af270e 100644
> --- a/hw/virtio/vhost-user.c
> +++ b/hw/virtio/vhost-user.c
> @@ -28,6 +28,8 @@
> #include "system/runstate.h"
> #include "system/cryptodev.h"
> #include "migration/postcopy-ram.h"
> +#include "migration/qemu-file-types.h"
> +#include "migration/qemu-file.h"
> #include "trace.h"
> #include "system/ramblock.h"
>
> @@ -2273,6 +2275,10 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
> u->dev = dev;
> dev->opaque = u;
>
> + if (dev->migrating_backend) {
> + goto out;
> + }
> +
> err = vhost_user_get_features(dev, &features);
> if (err < 0) {
> error_setg_errno(errp, -err, "vhost_backend_init failed");
> @@ -2387,6 +2393,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
> }
> }
>
Maybe call the goto target migrating_backend_out or something else to
indicate what it's for.
> +out:
> u->postcopy_notifier.notify = vhost_user_postcopy_notifier;
> postcopy_add_notifier(&u->postcopy_notifier);
>
> @@ -2936,6 +2943,10 @@ void vhost_user_async_close(DeviceState *d,
>
> static int vhost_user_dev_start(struct vhost_dev *dev, bool started)
> {
> + if (dev->migrating_backend) {
> + return 0;
> + }
> +
> if (!vhost_user_has_prot(dev, VHOST_USER_PROTOCOL_F_STATUS)) {
> return 0;
> }
> @@ -3105,6 +3116,55 @@ static void vhost_user_qmp_status(struct vhost_dev *dev, VhostStatus *status)
> status->protocol_features = qmp_decode_protocols(u->protocol_features);
> }
>
> +static void vhost_user_save(struct vhost_dev *dev, QEMUFile *f)
> +{
> + struct vhost_user *u = dev->opaque;
> + bool has_backend_channel = !!u->backend_sioc;
> + qemu_put_be64(f, u->protocol_features);
> + qemu_put_be32(f, u->user->memory_slots);
> +
> + qemu_put_byte(f, has_backend_channel);
> + if (u->backend_sioc) {
> + qemu_file_put_fd(f, u->backend_sioc->fd);
> + }
> +}
> +
> +static int vhost_user_load(struct vhost_dev *dev, QEMUFile *f)
> +{
> + struct vhost_user *u = dev->opaque;
> + uint8_t has_backend_channel;
> + uint32_t memory_slots;
> +
> + qemu_get_be64s(f, &u->protocol_features);
> + qemu_get_be32s(f, &memory_slots);
> + qemu_get_8s(f, &has_backend_channel);
> +
> + u->user->memory_slots = memory_slots;
> +
> + if (has_backend_channel) {
> + int fd = qemu_file_get_fd(f);
> + Error *local_err = NULL;
> +
> + u->backend_sioc = qio_channel_socket_new_fd(fd, &local_err);
> + if (!u->backend_sioc) {
> + error_report_err(local_err);
> + return -ECONNREFUSED;
> + }
> + u->backend_src = qio_channel_add_watch_source(
> + QIO_CHANNEL(u->backend_sioc), G_IO_IN | G_IO_HUP,
> + backend_read, dev, NULL, NULL);
> + }
> +
> + if (dev->migration_blocker == NULL &&
> + !vhost_user_has_prot(dev, VHOST_USER_PROTOCOL_F_LOG_SHMFD)) {
> + error_setg(&dev->migration_blocker,
> + "Migration disabled: vhost-user backend lacks "
> + "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature.");
> + }
> +
> + return 0;
> +}
> +
> const VhostOps user_ops = {
> .backend_type = VHOST_BACKEND_TYPE_USER,
> .vhost_backend_init = vhost_user_backend_init,
> @@ -3146,4 +3206,6 @@ const VhostOps user_ops = {
> .vhost_set_device_state_fd = vhost_user_set_device_state_fd,
> .vhost_check_device_state = vhost_user_check_device_state,
> .vhost_qmp_status = vhost_user_qmp_status,
> + .vhost_save_backend = vhost_user_save,
> + .vhost_load_backend = vhost_user_load,
> };
> --
> 2.48.1
>
>