[Devel] [PATCH v2 1/1] vhost/vsock: suppress EHOSTUNREACH fast-fail during CPR pause

Andrey Drobyshev andrey.drobyshev at virtuozzo.com
Fri May 22 13:30:35 MSK 2026


On 5/22/26 1:09 PM, 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 <den at openvz.org>
> ---
>  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);
>  err:
>  	mutex_unlock(&vsock->dev.mutex);


This looks better than my original solution.

However it doesn't pass my test. If data transfer is initiated when
qemu-update is performed, we somehow gotcha vhost device in nonworking
state and transmission stalls:

Guest:
> [root at rocky10 ~]# rm -f recv.bin ; socat -u VSOCK-LISTEN:1010 - > /root/recv.bin


Host:
> root at vhs$ virsh qemu-update rocky10 && ... && virsh qemu-update rocky10


Host:
> root at vhs$ socat -u FILE:/root/bigfile.bin VSOCK-CONNECT:10:1010


And it hangs:
> root at vhs$ strace -p `pgrep socat`
> strace: Process 6248 attached
> pselect6(7, [], [6], [], NULL, NULL


Andrey


More information about the Devel mailing list