[Devel] [PATCH VZ10] vhost/vsock: only refuse connection when guest has never been ready
Andrey Drobyshev
andrey.drobyshev at virtuozzo.com
Fri May 22 00:31:42 MSK 2026
Commit 4ff28534c799 ("ms/vhost/vsock: Refuse the connection immediately
when guest isn't ready") added a check which immediately returns
EHOSTUNREACH when the guest isn't ready yet. Namely, we check that guest
hasn't enabled the RX vq yet, i.e. virtio-vsock has never beed enabled.
However, the check also affects the transient state when backend is
temporarily set to NULL during VHOST_VSOCK_SET_RUNNING(0). Notably,
this is the case with qemu-update operation, during which we perform
VHOST_RESET_OWNER. In this case sendmsg()/connect() on otherwise healthy
connection gets EHOSTUNREACH.
Gate the fast-fail on a sticky started_once bit set in
vhost_vsock_start() and never cleared. Once the guest has brought
up virtio-vsock at least once, a NULL backend means a transient stop
window and the packet must be queued for vhost_vsock_start() to drain
on re-attach.
Fixes: 4ff28534c799 ("ms/vhost/vsock: Refuse the connection immediately when guest isn't ready")
https://virtuozzo.atlassian.net/browse/VSTOR-131956
Signed-off-by: Andrey Drobyshev <andrey.drobyshev at virtuozzo.com>
---
drivers/vhost/vsock.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 0a518c3d1596..f39354db630e 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 started_once; /* latched in vhost_vsock_start(); never cleared */
};
static u32 vhost_transport_get_local_cid(void)
@@ -285,17 +286,14 @@ vhost_transport_send_pkt(struct sk_buff *skb)
return -ENODEV;
}
- /* Fast-fail if the guest hasn't enabled the RX vq yet. Queuing the packet
- * and making the caller wait is pointless: even if the guest manages to init
- * within the timeout, it'll immediately reply with RST, because there's no
- * listener on the port yet.
- *
- * vhost_vq_get_backend() without vq->mutex is acceptable here: locking
- * the mutex would be too expensive in this hot path, and we already have
- * 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.
+ /*
+ * Fast-fail only when the guest has never enabled virtio-vsock.
+ * Once it has, a NULL backend means a transient SET_RUNNING(0)
+ * window (e.g. VHOST_RESET_OWNER); the packet must be
+ * queued for vhost_vsock_start() to drain on re-attach.
*/
- if (unlikely(!data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX])))) {
+ if (unlikely(!READ_ONCE(vsock->started_once)) &&
+ !data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX]))) {
rcu_read_unlock();
kfree_skb(skb);
return -EHOSTUNREACH;
@@ -615,6 +613,9 @@ static int vhost_vsock_start(struct vhost_vsock *vsock)
*/
vhost_vq_work_queue(&vsock->vqs[VSOCK_VQ_RX], &vsock->send_pkt_work);
+ /* See vhost_transport_send_pkt(); never cleared. */
+ WRITE_ONCE(vsock->started_once, true);
+
mutex_unlock(&vsock->dev.mutex);
return 0;
--
2.47.1
More information about the Devel
mailing list