On 5/22/26 3:06 PM, Pavel Tikhomirov wrote:
> 
> 
> On 5/22/26 12:09, Denis V. Lunev wrote:
>> The companion commit preserves ring state across VHOST_RESET_OWNER,
>> but QEMU still issues VHOST_VSOCK_SET_RUNNING(0) before RESET_OWNER,
>> nulling vq->private_data via vhost_vsock_drop_backends(). The
>> fast-fail in vhost_transport_send_pkt() from 4ff28534c799 then
>> rejects every host send with -EHOSTUNREACH until the destination
>> calls SET_RUNNING(1) -- the entire CPR window becomes a hard
>> outage for host AF_VSOCK clients (VSTOR-131956).
>>
>> Add a cpr_paused flag set by vhost_vsock_stop() when the backend
>> was previously live, cleared by vhost_vsock_start(). When set,
>> vhost_transport_send_pkt() queues the skb instead of fast-failing;
>> the existing kick of send_pkt_work in vhost_vsock_start() drains
>> it on resume. A device that has never run keeps cpr_paused == false
>> and the boot-time fast-fail behaviour is preserved.
>>
>> Set the flag before dropping backends so a concurrent sender never
>> observes (NULL, !paused).
>>
>> Feature: kvm
>>
>> https://virtuozzo.atlassian.net/browse/VSTOR-131956
>> Signed-off-by: Denis V. Lunev <[email protected]>
>> ---
>>  drivers/vhost/vsock.c | 11 ++++++++++-
>>  1 file changed, 10 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
>> index 0a518c3d1596..1d2ceec7f2e0 100644
>> --- a/drivers/vhost/vsock.c
>> +++ b/drivers/vhost/vsock.c
>> @@ -57,6 +57,7 @@ struct vhost_vsock {
>>  
>>      u32 guest_cid;
>>      bool seqpacket_allow;
>> +    bool cpr_paused;        /* between stop and next start; queues sends */
>>  };
>>  
>>  static u32 vhost_transport_get_local_cid(void)
>> @@ -295,7 +296,9 @@ vhost_transport_send_pkt(struct sk_buff *skb)
>>       * all the outcomes covered: if the backend becomes NULL right after 
>> the check,
>>       * vhost_transport_do_send_pkt() will check it under the mutex anyway.
>>       */
>> -    if 
>> (unlikely(!data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX])))) {
>> +    /* cpr_paused: queue across CPR; else NULL backend means not ready. */
>> +    if (unlikely(!data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX])) 
>> &&
>> +                 !READ_ONCE(vsock->cpr_paused))) {
>>              rcu_read_unlock();
>>              kfree_skb(skb);
>>              return -EHOSTUNREACH;
>> @@ -610,6 +613,8 @@ static int vhost_vsock_start(struct vhost_vsock *vsock)
>>              mutex_unlock(&vq->mutex);
>>      }
>>  
>> +    WRITE_ONCE(vsock->cpr_paused, false);
>> +
>>      /* Some packets may have been queued before the device was started,
>>       * let's kick the send worker to send them.
>>       */
>> @@ -653,6 +658,7 @@ static void vhost_vsock_drop_backends(struct vhost_vsock 
>> *vsock)
>>  static int vhost_vsock_stop(struct vhost_vsock *vsock, bool check_owner)
>>  {
>>      int ret = 0;
>> +    bool was_running;
>>  
>>      mutex_lock(&vsock->dev.mutex);
>>  
>> @@ -662,6 +668,9 @@ static int vhost_vsock_stop(struct vhost_vsock *vsock, 
>> bool check_owner)
>>                      goto err;
>>      }
>>  
>> +    was_running = !!vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX]);
>> +    if (was_running)
>> +            WRITE_ONCE(vsock->cpr_paused, true);
>>      vhost_vsock_drop_backends(vsock);
> 
> Should we do the same in vhost_vsock_reset_owner? We also do 
> vhost_vsock_drop_backends there.
>

At least for qemu-update case it's not necessary.  Here QEMU calls
VHOST_VSOCK_SET_RUNNING(0) BEFORE it calls VHOST_RESET_OWNER.

But for whatever other use case which does VHOST_RESET_OWNER
independently it should probably be done.  Though I don't know what this
case might be.

Overall: it should be a no-op for our qemu-update case, and a safe move
for whatever other case.

>>  err:
>>      mutex_unlock(&vsock->dev.mutex);
> 

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to