Re: [PATCH v3 5/5] vhost-user: add skip_drain param to GET_VRING_BASE

Raphael Norwitz <[email protected]> Mon, 25 May 2026 17:34:37 -0400
Newsgroups dev.linux.lists.virtio-fs,org.nongnu.qemu-devel
Message-ID <[email protected]>
Apologies for the late reply.

On 5/12/26 1:55 AM, Alexandr Moshkov wrote:
> Gentle ping :)
> 

[...]

>>>>> On 4/16/26 5:26 AM, Alexandr Moshkov wrote:
>>>>>> Greetings! Thanks for reply!
>>>>>>
>>>>>>
>>>>>> On 4/15/26 20:21, Raphael Norwitz wrote:
>>>>>>> I’m not sure I like using the num field in vhost_vring_state to 
>>>>>>> set magic values which affect protocol behavior for 
>>>>>>> GET_VRING_BASE. It feels like a hack to me. I would think the 
>>>>>>> proper solution if we want to support migration from new to old 
>>>>>>> would be to have new use a different new message entirely. Can we 
>>>>>>> do that?
>>>>>>
>>>>>> I think we can, but I thought at first that this will be almost a 
>>>>>> complete copy of GET_VRING_BASE message, with the exception of 
>>>>>> waiting for drain of requests, so I choose to expand existing 
>>>>>> message.
>>>>>>
>>>>>
>>>>> I think a new message would be cleaner. Anyone else have thoughts?
>>>>>
>>>>>> If this is not an appropriate approach, is it better to make a new 
>>>>>> message like GET_VRING_BASE or a separate message used together 
>>>>>> with default GET_VRING_BASE message (for example, message for 
>>>>>> setting some kind of status on the server)? What should I name 
>>>>>> this new message?
>>>>>>
>>>>>
>>>>> Maybe GET_VRING_BASE_SKIP_DRAIN? How would a separate message used 
>>>>> together with default GET_VRING_BASE message work? 
>>>>
>>>> I was thinking about a message something like SET_VRING_ENABLE - for 
>>>> example SET_SKIP_DRAIN_ENABLE, that would enable/disable some state 
>>>> (skip_drain) in the backend.
>>>
>>> I'd need to see the flow in more detail but sounds promising.
>>
>> On migration vhost-user-blk firstly send SET_SKIP_DRAIN_ENABLE with 
>> num = 1 message if `inflight-migration` device parameter 
>> and VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT enabled. Then send 
>> GET_VRING_BASE and continue work as usual.
>>
>> On SET_SKIP_DRAIN_ENABLE backend sets inner state (skip_drain) so when 
>> GET_VRING_BASE is called and skip_drain is true the drain will skipped.
>>
>> What do you think?
>>

I'm happy with that in theory but would like more clarity on the 
details. In particular, I'm not sure what you mean by "vhost-user-blk 
firstly send SET_SKIP_DRAIN_ENABLE". To add a new message I would think 
we would have to do a vhost-user protocol feature negotiation to gate it.

Also what are the precise semantics for SET_SKIP_DRAIN_ENABLE? Would it 
be sent on backend connect or when we're about to migrate?

I was hoping others would comment but at this point I'd suggest drafting 
the code and then we can re-review.

>>>
>>>>
>>>>>
>>>>>> I also fix other comments, thanks!
>>>>>>
>>>>>>>
>>>>>>> On 3/30/26 11:52 AM, Alexandr Moshkov wrote:
>>>>>>>> In case of migration of QEMU from the new version (where the
>>>>>>>> inllight-migration parameter is present), to the old one (where 
>>>>>>>> it is
>>>>>>>
>>>>>>> nit: spelling inllight-migration
>>>>>>>
>>>>>>>> absent) there is no way to disable this feature on the backend 
>>>>>>>> during
>>>>>>>> runtime.
>>>>>>>>
>>>>>>>> This commit slightly changes the semantics of the protocol feature
>>>>>>>> VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT. Enabling this 
>>>>>>>> feature
>>>>>>>> adds a new parameter for GET_VRING_BASE, which allows to control 
>>>>>>>> the
>>>>>>>> drain in-flight requests on the backend.
>>>>>>>> Thus, QEMU will be able to turn this feature on GET_VRING_BASE 
>>>>>>>> off and
>>>>>>>> on anytime.
>>>>>>>>
>>>>>>>> In vhost-user-blk use inflight_migration param to enable 
>>>>>>>> skip_drain to
>>>>>>>> suspend in-flight I/O requests, and then migrate them throught 
>>>>>>>> inflight
>>>>>>>> subsection.
>>>>>>>>
>>>>>>>> Also now QEMU will always try to setup
>>>>>>>> VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT protocol featrue with
>>>>>>>> backend. This will allow to use skip_drain parameter on 
>>>>>>>> GET_VRING_BASE
>>>>>>>> message.
>>>>>>>>
>>>>>>>> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex- 
>>>>>>>> team.ru>
>>>>>>>> Signed-off-by: Alexandr Moshkov <[email protected]>
>>>>>>>> ---
>>>>>>>>   docs/interop/vhost-user.rst    |  6 ++----
>>>>>>>>   hw/block/vhost-user-blk.c      | 30 +++++++++++++++++++++++ 
>>>>>>>> +------
>>>>>>>>   hw/virtio/vhost-user.c         |  3 +--
>>>>>>>>   hw/virtio/vhost.c              |  1 +
>>>>>>>>   include/hw/virtio/vhost-user.h |  1 -
>>>>>>>>   5 files changed, 28 insertions(+), 13 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost- 
>>>>>>>> user.rst
>>>>>>>> index bfa75ff9a3..63efc87264 100644
>>>>>>>> --- a/docs/interop/vhost-user.rst
>>>>>>>> +++ b/docs/interop/vhost-user.rst
>>>>>>>> @@ -1255,14 +1255,12 @@ Front-end message types
>>>>>>>>     *suspended*, see :ref:`Suspended device state
>>>>>>>>     <suspended_device_state>`.
>>>>>>>>   -  The request payload's *num* field is currently reserved and 
>>>>>>>> must be
>>>>>>>> -  set to 0.
>>>>>>>> -
>>>>>>>>     By default, the back-end must complete all inflight I/O 
>>>>>>>> requests for the
>>>>>>>>     specified vring before stopping it.
>>>>>>>>       If the ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT`` 
>>>>>>>> protocol
>>>>>>>> -  feature has been negotiated, the back-end may suspend in- 
>>>>>>>> flight I/O
>>>>>>>> +  feature has been negotiated, using request payload's *num* 
>>>>>>>> field,
>>>>>>>> +  when *num* is set to 1, QEMU can tell the back-end to suspend 
>>>>>>>> in- flight I/O
>>>>>>>>     requests and record them as described in :ref:`Inflight I/O 
>>>>>>>> tracking
>>>>>>>>     <inflight_io_tracking>` instead of completing them before 
>>>>>>>> stopping the vring.
>>>>>>>>     How to suspend an in-flight request depends on the 
>>>>>>>> implementation of the back-end
>>>>>>>> diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
>>>>>>>> index a3ecd83f54..522e9d34b5 100644
>>>>>>>> --- a/hw/block/vhost-user-blk.c
>>>>>>>> +++ b/hw/block/vhost-user-blk.c
>>>>>>>> @@ -134,10 +134,7 @@ static bool 
>>>>>>>> vhost_user_blk_inflight_needed(void *opaque)
>>>>>>>>   {
>>>>>>>>       struct VHostUserBlk *s = opaque;
>>>>>>>>   -    bool inflight_migration = virtio_has_feature(s- 
>>>>>>>> >dev.protocol_features,
>>>>>>>> - VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
>>>>>>>> -
>>>>>>>> -    return inflight_migration;
>>>>>>>> +    return s->inflight_migration;
>>>>>>>>   }
>>>>>>>>     @@ -232,11 +229,14 @@ static int 
>>>>>>>> vhost_user_blk_stop(VirtIODevice *vdev)
>>>>>>>>           return 0;
>>>>>>>>       }
>>>>>>>>   +    bool skip_drain = vhost_user_blk_inflight_needed(s) &&
>>>>>>>
>>>>>>> nit: declarations on top
>>>>>>>
>>>>>>>> + runstate_check(RUN_STATE_FINISH_MIGRATE);
>>>>>>>> +
>>>>>>>>       force_stop = s->skip_get_vring_base_on_force_shutdown &&
>>>>>>>>                    qemu_force_shutdown_requested();
>>>>>>>>         ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, 
>>>>>>>> true) :
>>>>>>>> -                       vhost_dev_stop(&s->dev, vdev, true, false);
>>>>>>>> +                       vhost_dev_stop(&s->dev, vdev, true, 
>>>>>>>> skip_drain);
>>>>>>>>         if (k->set_guest_notifiers(qbus->parent, s->dev.nvqs, 
>>>>>>>> false) < 0) {
>>>>>>>>           error_report("vhost guest notifier cleanup failed: 
>>>>>>>> %d", ret);
>>>>>>>> @@ -364,7 +364,6 @@ static int 
>>>>>>>> vhost_user_blk_connect(DeviceState *dev, Error **errp)
>>>>>>>>       vhost_dev_set_config_notifier(&s->dev, &blk_ops);
>>>>>>>>         s->vhost_user.supports_config = true;
>>>>>>>> -    s->vhost_user.supports_inflight_migration = s- 
>>>>>>>> >inflight_migration;
>>>>>>>>       ret = vhost_dev_init(&s->dev, &s->vhost_user, 
>>>>>>>> VHOST_BACKEND_TYPE_USER, 0,
>>>>>>>>                            errp);
>>>>>>>>       if (ret < 0) {
>>>>>>>> @@ -580,10 +579,29 @@ static struct vhost_dev 
>>>>>>>> *vhost_user_blk_get_vhost(VirtIODevice *vdev)
>>>>>>>>       return &s->dev;
>>>>>>>>   }
>>>>>>>>   +static bool vhost_user_blk_pre_save(void *opaque, Error **errp)
>>>>>>>> +{
>>>>>>>> +    VHostUserBlk *s = VHOST_USER_BLK(opaque);
>>>>>>>> +
>>>>>>>> +    bool inflight_migration_enabled = virtio_has_feature(
>>>>>>>> +        s->dev.protocol_features,
>>>>>>>> + VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
>>>>>>>> +    if (vhost_user_blk_inflight_needed(s) && ! 
>>>>>>>> inflight_migration_enabled) {
>>>>>>>> +        error_setg(errp, "can't migrate vhost-user-blk device: "
>>>>>>>> +                         "backend doesn't support "
>>>>>>>> + "VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT "
>>>>>>>> +                         "protocol feature");
>>>>>>>> +        return false;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    return true;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>>   static const VMStateDescription 
>>>>>>>> vmstate_vhost_user_blk_inflight = {
>>>>>>>>       .name = "vhost-user-blk/inflight",
>>>>>>>>       .version_id = 1,
>>>>>>>>       .needed = vhost_user_blk_inflight_needed,
>>>>>>>> +    .pre_save_errp = vhost_user_blk_pre_save,
>>>>>>>>       .fields = (const VMStateField[]) {
>>>>>>>>           VMSTATE_VHOST_INFLIGHT_REGION(inflight, VHostUserBlk),
>>>>>>>>           VMSTATE_END_OF_LIST()
>>>>>>>> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
>>>>>>>> index bb8f8eab77..ed95ec7523 100644
>>>>>>>> --- a/hw/virtio/vhost-user.c
>>>>>>>> +++ b/hw/virtio/vhost-user.c
>>>>>>>> @@ -2225,8 +2225,7 @@ static int vhost_user_backend_init(struct 
>>>>>>>> vhost_dev *dev, void *opaque,
>>>>>>>>               }
>>>>>>>>           }
>>>>>>>>   -        if (!u->user->supports_inflight_migration ||
>>>>>>>> -            !virtio_has_feature(protocol_features,
>>>>>>>> +        if (!virtio_has_feature(protocol_features,
>>>>>>>> VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
>>>>>>>>               protocol_features &= ~(1ULL <<
>>>>>>>> VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
>>>>>>>> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
>>>>>>>> index ac4d6fca73..54e4ce2660 100644
>>>>>>>> --- a/hw/virtio/vhost.c
>>>>>>>> +++ b/hw/virtio/vhost.c
>>>>>>>> @@ -1398,6 +1398,7 @@ static int do_vhost_virtqueue_stop(struct 
>>>>>>>> vhost_dev *dev,
>>>>>>>>       int vhost_vq_index = dev->vhost_ops- 
>>>>>>>> >vhost_get_vq_index(dev, idx);
>>>>>>>>       struct vhost_vring_state state = {
>>>>>>>>           .index = vhost_vq_index,
>>>>>>>> +        .num = skip_drain,
>>>>>>>>       };
>>>>>>>>       int r = 0;
>>>>>>>>   diff --git a/include/hw/virtio/vhost-user.h b/include/hw/ 
>>>>>>>> virtio/ vhost-user.h
>>>>>>>> index 53fe996686..c95bad5ddc 100644
>>>>>>>> --- a/include/hw/virtio/vhost-user.h
>>>>>>>> +++ b/include/hw/virtio/vhost-user.h
>>>>>>>> @@ -69,7 +69,6 @@ typedef struct VhostUserState {
>>>>>>>>       GPtrArray *notifiers;
>>>>>>>>       int memory_slots;
>>>>>>>>       bool supports_config;
>>>>>>>> -    bool supports_inflight_migration;
>>>>>>>>   } VhostUserState;
>>>>>>>>     /**
>>>>>>>
>>>>>
>>>