[PATCH v2 20/25] vhost-user: add vmstate

Vladimir Sementsov-Ogievskiy posted 25 patches 4 weeks, 1 day ago
[PATCH v2 20/25] vhost-user: add vmstate
Posted by Vladimir Sementsov-Ogievskiy 4 weeks, 1 day ago
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 hw/virtio/vhost-user.c         | 95 ++++++++++++++++++++++++++++++++++
 include/hw/virtio/vhost-user.h |  4 ++
 2 files changed, 99 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index c5cb5ed528..a820214188 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"
 
@@ -3137,6 +3139,99 @@ void vhost_user_qmp_status(struct vhost_dev *dev, VirtioStatus *status)
         qmp_decode_protocols(u->protocol_features);
 }
 
+typedef struct VhostUserMigTmp {
+    struct vhost_dev *parent;
+    bool has_backend_channel;
+    int backend_fd;
+    uint32_t memory_slots;
+    uint64_t protocol_features;
+} VhostUserMigTmp;
+
+static int vhost_user_tmp_pre_save(void *opaque)
+{
+    VhostUserMigTmp *tmp = opaque;
+    struct vhost_dev *dev = tmp->parent;
+    struct vhost_user *u = dev->opaque;
+    QIOChannelSocket *sioc = u->backend_sioc;
+
+    if (sioc && sioc->fd < 0) {
+        return -EINVAL;
+    }
+
+    tmp->backend_fd = sioc ? sioc->fd : -1;
+    tmp->has_backend_channel = !!sioc;
+    tmp->memory_slots = u->user->memory_slots;
+    tmp->protocol_features = u->protocol_features;
+
+    return 0;
+}
+
+static int vhost_user_tmp_post_load(void *opaque, int version_id)
+{
+    struct VhostUserMigTmp *tmp = opaque;
+    struct vhost_dev *dev = tmp->parent;
+    struct vhost_user *u = dev->opaque;
+    Error *local_err = NULL;
+
+    if (tmp->has_backend_channel) {
+        u->backend_sioc = qio_channel_socket_new_fd(tmp->backend_fd,
+                                                    &local_err);
+        if (!u->backend_sioc) {
+            error_report_err(local_err);
+            return -EINVAL;
+        }
+        u->backend_src = qio_channel_add_watch_source(
+            QIO_CHANNEL(u->backend_sioc), G_IO_IN | G_IO_HUP,
+            backend_read, u->dev, NULL, NULL);
+    }
+
+    u->user->memory_slots = tmp->memory_slots;
+    u->protocol_features = tmp->protocol_features;
+
+    return 0;
+}
+
+static bool vhost_user_tmp_test_fd(void *opaque, int version_id)
+{
+    struct VhostUserMigTmp *tmp = opaque;
+
+    return tmp->has_backend_channel;
+}
+
+static const VMStateDescription vmstate_vhost_user_blk_tmp = {
+    .name = "vhost-user-blk-tmp",
+    .pre_save = vhost_user_tmp_pre_save,
+    .post_load = vhost_user_tmp_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT64(protocol_features, VhostUserMigTmp),
+        VMSTATE_UINT32(memory_slots, VhostUserMigTmp),
+        VMSTATE_BOOL(has_backend_channel, VhostUserMigTmp),
+        VMSTATE_FD_TEST(backend_fd, VhostUserMigTmp, vhost_user_tmp_test_fd),
+        VMSTATE_END_OF_LIST()
+   },
+};
+
+static int vhost_user_post_load(void *opaque, int version_id)
+{
+    struct vhost_dev *dev = opaque;
+    struct vhost_user *u = dev->opaque;
+
+    u->postcopy_notifier.notify = vhost_user_postcopy_notifier;
+    postcopy_add_notifier(&u->postcopy_notifier);
+
+    return 0;
+}
+
+const VMStateDescription vmstate_vhost_user = {
+    .name = "vhost-user",
+    .post_load = vhost_user_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_WITH_TMP(struct vhost_dev, VhostUserMigTmp,
+                         vmstate_vhost_user_blk_tmp),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VhostOps user_ops = {
         .backend_type = VHOST_BACKEND_TYPE_USER,
         .vhost_backend_init = vhost_user_backend_init,
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
index 36d96296a3..fb89268de2 100644
--- a/include/hw/virtio/vhost-user.h
+++ b/include/hw/virtio/vhost-user.h
@@ -114,4 +114,8 @@ void vhost_user_async_close(DeviceState *d,
 
 void vhost_user_qmp_status(struct vhost_dev *dev, VirtioStatus *status);
 
+extern const VMStateDescription vmstate_vhost_user;
+#define VMSTATE_BACKEND_TRANSFER_VHOST_USER(_field, _state) \
+    VMSTATE_STRUCT(_field, _state, 0, vmstate_vhost_user, struct vhost_dev)
+
 #endif
-- 
2.48.1
Re: [PATCH v2 20/25] vhost-user: add vmstate
Posted by Raphael Norwitz 3 weeks, 3 days ago
For now a naming nit and a question.

On Thu, Oct 16, 2025 at 7:44 AM Vladimir Sementsov-Ogievskiy
<vsementsov@yandex-team.ru> wrote:
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
>  hw/virtio/vhost-user.c         | 95 ++++++++++++++++++++++++++++++++++
>  include/hw/virtio/vhost-user.h |  4 ++
>  2 files changed, 99 insertions(+)
>
> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> index c5cb5ed528..a820214188 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"
>
> @@ -3137,6 +3139,99 @@ void vhost_user_qmp_status(struct vhost_dev *dev, VirtioStatus *status)
>          qmp_decode_protocols(u->protocol_features);
>  }
>
> +typedef struct VhostUserMigTmp {
> +    struct vhost_dev *parent;
> +    bool has_backend_channel;
> +    int backend_fd;
> +    uint32_t memory_slots;
> +    uint64_t protocol_features;
> +} VhostUserMigTmp;
> +
> +static int vhost_user_tmp_pre_save(void *opaque)
> +{
> +    VhostUserMigTmp *tmp = opaque;
> +    struct vhost_dev *dev = tmp->parent;
> +    struct vhost_user *u = dev->opaque;
> +    QIOChannelSocket *sioc = u->backend_sioc;
> +
> +    if (sioc && sioc->fd < 0) {
> +        return -EINVAL;
> +    }
> +
> +    tmp->backend_fd = sioc ? sioc->fd : -1;
> +    tmp->has_backend_channel = !!sioc;
> +    tmp->memory_slots = u->user->memory_slots;
> +    tmp->protocol_features = u->protocol_features;
> +
> +    return 0;
> +}
> +
> +static int vhost_user_tmp_post_load(void *opaque, int version_id)
> +{
> +    struct VhostUserMigTmp *tmp = opaque;
> +    struct vhost_dev *dev = tmp->parent;
> +    struct vhost_user *u = dev->opaque;
> +    Error *local_err = NULL;
> +
> +    if (tmp->has_backend_channel) {
> +        u->backend_sioc = qio_channel_socket_new_fd(tmp->backend_fd,
> +                                                    &local_err);
> +        if (!u->backend_sioc) {
> +            error_report_err(local_err);
> +            return -EINVAL;
> +        }
> +        u->backend_src = qio_channel_add_watch_source(
> +            QIO_CHANNEL(u->backend_sioc), G_IO_IN | G_IO_HUP,
> +            backend_read, u->dev, NULL, NULL);
> +    }
> +
> +    u->user->memory_slots = tmp->memory_slots;
> +    u->protocol_features = tmp->protocol_features;
> +
> +    return 0;
> +}
> +
> +static bool vhost_user_tmp_test_fd(void *opaque, int version_id)
> +{
> +    struct VhostUserMigTmp *tmp = opaque;
> +
> +    return tmp->has_backend_channel;
> +}
> +

Will this be vhost-user-blk specific? It should probably be something
like vhost_user_backend_transfer_tmp?

> +static const VMStateDescription vmstate_vhost_user_blk_tmp = {
> +    .name = "vhost-user-blk-tmp",
> +    .pre_save = vhost_user_tmp_pre_save,
> +    .post_load = vhost_user_tmp_post_load,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_UINT64(protocol_features, VhostUserMigTmp),
> +        VMSTATE_UINT32(memory_slots, VhostUserMigTmp),
> +        VMSTATE_BOOL(has_backend_channel, VhostUserMigTmp),
> +        VMSTATE_FD_TEST(backend_fd, VhostUserMigTmp, vhost_user_tmp_test_fd),
> +        VMSTATE_END_OF_LIST()
> +   },
> +};
> +
> +static int vhost_user_post_load(void *opaque, int version_id)
> +{
> +    struct vhost_dev *dev = opaque;
> +    struct vhost_user *u = dev->opaque;
> +
> +    u->postcopy_notifier.notify = vhost_user_postcopy_notifier;
> +    postcopy_add_notifier(&u->postcopy_notifier);
> +
> +    return 0;
> +}
> +

Why do we need a second post_load() callback here? Why can't
u->postcopy_notifier.notify be set in vhost_user_tmp_post_load()?


> +const VMStateDescription vmstate_vhost_user = {
> +    .name = "vhost-user",
> +    .post_load = vhost_user_post_load,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_WITH_TMP(struct vhost_dev, VhostUserMigTmp,
> +                         vmstate_vhost_user_blk_tmp),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  const VhostOps user_ops = {
>          .backend_type = VHOST_BACKEND_TYPE_USER,
>          .vhost_backend_init = vhost_user_backend_init,
> diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
> index 36d96296a3..fb89268de2 100644
> --- a/include/hw/virtio/vhost-user.h
> +++ b/include/hw/virtio/vhost-user.h
> @@ -114,4 +114,8 @@ void vhost_user_async_close(DeviceState *d,
>
>  void vhost_user_qmp_status(struct vhost_dev *dev, VirtioStatus *status);
>
> +extern const VMStateDescription vmstate_vhost_user;
> +#define VMSTATE_BACKEND_TRANSFER_VHOST_USER(_field, _state) \
> +    VMSTATE_STRUCT(_field, _state, 0, vmstate_vhost_user, struct vhost_dev)
> +
>  #endif
> --
> 2.48.1
>
>
Re: [PATCH v2 20/25] vhost-user: add vmstate
Posted by Vladimir Sementsov-Ogievskiy 3 weeks, 3 days ago
On 21.10.25 02:51, Raphael Norwitz wrote:
> For now a naming nit and a question.
> 
> On Thu, Oct 16, 2025 at 7:44 AM Vladimir Sementsov-Ogievskiy
> <vsementsov@yandex-team.ru> wrote:
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
>> ---
>>   hw/virtio/vhost-user.c         | 95 ++++++++++++++++++++++++++++++++++
>>   include/hw/virtio/vhost-user.h |  4 ++
>>   2 files changed, 99 insertions(+)
>>
>> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
>> index c5cb5ed528..a820214188 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"
>>
>> @@ -3137,6 +3139,99 @@ void vhost_user_qmp_status(struct vhost_dev *dev, VirtioStatus *status)
>>           qmp_decode_protocols(u->protocol_features);
>>   }
>>
>> +typedef struct VhostUserMigTmp {
>> +    struct vhost_dev *parent;
>> +    bool has_backend_channel;
>> +    int backend_fd;
>> +    uint32_t memory_slots;
>> +    uint64_t protocol_features;
>> +} VhostUserMigTmp;
>> +
>> +static int vhost_user_tmp_pre_save(void *opaque)
>> +{
>> +    VhostUserMigTmp *tmp = opaque;
>> +    struct vhost_dev *dev = tmp->parent;
>> +    struct vhost_user *u = dev->opaque;
>> +    QIOChannelSocket *sioc = u->backend_sioc;
>> +
>> +    if (sioc && sioc->fd < 0) {
>> +        return -EINVAL;
>> +    }
>> +
>> +    tmp->backend_fd = sioc ? sioc->fd : -1;
>> +    tmp->has_backend_channel = !!sioc;
>> +    tmp->memory_slots = u->user->memory_slots;
>> +    tmp->protocol_features = u->protocol_features;
>> +
>> +    return 0;
>> +}
>> +
>> +static int vhost_user_tmp_post_load(void *opaque, int version_id)
>> +{
>> +    struct VhostUserMigTmp *tmp = opaque;
>> +    struct vhost_dev *dev = tmp->parent;
>> +    struct vhost_user *u = dev->opaque;
>> +    Error *local_err = NULL;
>> +
>> +    if (tmp->has_backend_channel) {
>> +        u->backend_sioc = qio_channel_socket_new_fd(tmp->backend_fd,
>> +                                                    &local_err);
>> +        if (!u->backend_sioc) {
>> +            error_report_err(local_err);
>> +            return -EINVAL;
>> +        }
>> +        u->backend_src = qio_channel_add_watch_source(
>> +            QIO_CHANNEL(u->backend_sioc), G_IO_IN | G_IO_HUP,
>> +            backend_read, u->dev, NULL, NULL);
>> +    }
>> +
>> +    u->user->memory_slots = tmp->memory_slots;
>> +    u->protocol_features = tmp->protocol_features;
>> +
>> +    return 0;
>> +}
>> +
>> +static bool vhost_user_tmp_test_fd(void *opaque, int version_id)
>> +{
>> +    struct VhostUserMigTmp *tmp = opaque;
>> +
>> +    return tmp->has_backend_channel;
>> +}
>> +
> 
> Will this be vhost-user-blk specific? It should probably be something
> like vhost_user_backend_transfer_tmp?
> 

Oh right. a mistake.

>> +static const VMStateDescription vmstate_vhost_user_blk_tmp = {
>> +    .name = "vhost-user-blk-tmp",
>> +    .pre_save = vhost_user_tmp_pre_save,
>> +    .post_load = vhost_user_tmp_post_load,
>> +    .fields = (const VMStateField[]) {
>> +        VMSTATE_UINT64(protocol_features, VhostUserMigTmp),
>> +        VMSTATE_UINT32(memory_slots, VhostUserMigTmp),
>> +        VMSTATE_BOOL(has_backend_channel, VhostUserMigTmp),
>> +        VMSTATE_FD_TEST(backend_fd, VhostUserMigTmp, vhost_user_tmp_test_fd),
>> +        VMSTATE_END_OF_LIST()
>> +   },
>> +};
>> +
>> +static int vhost_user_post_load(void *opaque, int version_id)
>> +{
>> +    struct vhost_dev *dev = opaque;
>> +    struct vhost_user *u = dev->opaque;
>> +
>> +    u->postcopy_notifier.notify = vhost_user_postcopy_notifier;
>> +    postcopy_add_notifier(&u->postcopy_notifier);
>> +
>> +    return 0;
>> +}
>> +
> 
> Why do we need a second post_load() callback here? Why can't
> u->postcopy_notifier.notify be set in vhost_user_tmp_post_load()?

Hmm.. Yes, looks strange, I don't remember. Will try to merge.

> 
> 
>> +const VMStateDescription vmstate_vhost_user = {
>> +    .name = "vhost-user",
>> +    .post_load = vhost_user_post_load,
>> +    .fields = (const VMStateField[]) {
>> +        VMSTATE_WITH_TMP(struct vhost_dev, VhostUserMigTmp,
>> +                         vmstate_vhost_user_blk_tmp),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>>   const VhostOps user_ops = {
>>           .backend_type = VHOST_BACKEND_TYPE_USER,
>>           .vhost_backend_init = vhost_user_backend_init,
>> diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
>> index 36d96296a3..fb89268de2 100644
>> --- a/include/hw/virtio/vhost-user.h
>> +++ b/include/hw/virtio/vhost-user.h
>> @@ -114,4 +114,8 @@ void vhost_user_async_close(DeviceState *d,
>>
>>   void vhost_user_qmp_status(struct vhost_dev *dev, VirtioStatus *status);
>>
>> +extern const VMStateDescription vmstate_vhost_user;
>> +#define VMSTATE_BACKEND_TRANSFER_VHOST_USER(_field, _state) \
>> +    VMSTATE_STRUCT(_field, _state, 0, vmstate_vhost_user, struct vhost_dev)
>> +
>>   #endif
>> --
>> 2.48.1
>>
>>


-- 
Best regards,
Vladimir