Commit bd50c5dc182b ("vsock/virtio: add support for device
suspend/resume") made the *_run flags transition from false to true when
restore installs replacement virtqueues.  The RX, TX and event workers
read their virtqueue before locking and checking the corresponding flag,
so a worker delayed across freeze and restore can observe the replacement
queue's running state while retaining a pointer to the deleted queue.

Read each virtqueue under its mutex after checking the run flag, keeping
the pointer and state in the same queue generation.

Fixes: bd50c5dc182b ("vsock/virtio: add support for device suspend/resume")
Cc: [email protected]
Reported-by: Xiang Mei <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Assisted-by: OpenAI-Codex:gpt-5
Signed-off-by: Weiming Shi <[email protected]>
---
 net/vmw_vsock/virtio_transport.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index 57f2d6ec3ffc..a8e1dd95ba8c 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -346,12 +346,13 @@ static void virtio_transport_tx_work(struct work_struct 
*work)
        struct virtqueue *vq;
        bool added = false;
 
-       vq = vsock->vqs[VSOCK_VQ_TX];
        mutex_lock(&vsock->tx_lock);
 
        if (!vsock->tx_run)
                goto out;
 
+       vq = vsock->vqs[VSOCK_VQ_TX];
+
        do {
                struct sk_buff *skb;
                unsigned int len;
@@ -451,13 +452,13 @@ static void virtio_transport_event_work(struct 
work_struct *work)
                container_of(work, struct virtio_vsock, event_work);
        struct virtqueue *vq;
 
-       vq = vsock->vqs[VSOCK_VQ_EVENT];
-
        mutex_lock(&vsock->event_lock);
 
        if (!vsock->event_run)
                goto out;
 
+       vq = vsock->vqs[VSOCK_VQ_EVENT];
+
        do {
                struct virtio_vsock_event *event;
                unsigned int len;
@@ -634,13 +635,13 @@ static void virtio_transport_rx_work(struct work_struct 
*work)
                container_of(work, struct virtio_vsock, rx_work);
        struct virtqueue *vq;
 
-       vq = vsock->vqs[VSOCK_VQ_RX];
-
        mutex_lock(&vsock->rx_lock);
 
        if (!vsock->rx_run)
                goto out;
 
+       vq = vsock->vqs[VSOCK_VQ_RX];
+
        do {
                virtqueue_disable_cb(vq);
                for (;;) {
-- 
2.55.0


Reply via email to