From 675087c762f95c498524164de7417f9f77d3ed15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 7 Jul 2026 14:33:43 +0200 Subject: [PATCH] vduse: do not take rwsem at reset work flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patches need to check suspend flag at this work item, and the rwlock is used to protect the suspend flag update. If the work takes the rwlock too it will produce a deadlock. Make flushing work do nothing when called by de-initializing everything: vq->ready, vq->kickfd, vq->cb.callback. Signed-off-by: Eugenio Pérez Signed-off-by: Michael S. Tsirkin Message-ID: <20260707123344.244575-2-eperezma@redhat.com> --- drivers/vdpa/vdpa_user/vduse_dev.c | 67 ++++++++++++++++-------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 87d6748b50cc..9aff26fbb583 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -502,46 +502,49 @@ static void vduse_dev_reset(struct vduse_dev *dev) vduse_domain_reset_bounce_map(domain); } - down_write(&dev->rwsem); + scoped_guard(rwsem_write, &dev->rwsem) { + dev->status = 0; + dev->driver_features = 0; + dev->generation++; + spin_lock(&dev->irq_lock); + dev->config_cb.callback = NULL; + dev->config_cb.private = NULL; + spin_unlock(&dev->irq_lock); + + for (i = 0; i < dev->vq_num; i++) { + struct vduse_virtqueue *vq = dev->vqs[i]; + + scoped_guard(spinlock_bh, &vq->ready_lock) { + vq->ready = false; + } + vq->desc_addr = 0; + vq->driver_addr = 0; + vq->device_addr = 0; + vq->num = 0; + memset(&vq->state, 0, sizeof(vq->state)); + + spin_lock(&vq->kick_lock); + vq->kicked = false; + if (vq->kickfd) + eventfd_ctx_put(vq->kickfd); + vq->kickfd = NULL; + spin_unlock(&vq->kick_lock); + + spin_lock(&vq->irq_lock); + vq->cb.callback = NULL; + vq->cb.private = NULL; + vq->cb.trigger = NULL; + spin_unlock(&vq->irq_lock); + } + } - dev->status = 0; - dev->driver_features = 0; - dev->generation++; - spin_lock(&dev->irq_lock); - dev->config_cb.callback = NULL; - dev->config_cb.private = NULL; - spin_unlock(&dev->irq_lock); flush_work(&dev->inject); - for (i = 0; i < dev->vq_num; i++) { struct vduse_virtqueue *vq = dev->vqs[i]; - scoped_guard(spinlock_bh, &vq->ready_lock) { - vq->ready = false; - } - vq->desc_addr = 0; - vq->driver_addr = 0; - vq->device_addr = 0; - vq->num = 0; - memset(&vq->state, 0, sizeof(vq->state)); - - spin_lock(&vq->kick_lock); - vq->kicked = false; - if (vq->kickfd) - eventfd_ctx_put(vq->kickfd); - vq->kickfd = NULL; - spin_unlock(&vq->kick_lock); - - spin_lock(&vq->irq_lock); - vq->cb.callback = NULL; - vq->cb.private = NULL; - vq->cb.trigger = NULL; - spin_unlock(&vq->irq_lock); flush_work(&vq->inject); flush_work(&vq->kick); } - - up_write(&dev->rwsem); } static int vduse_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 idx,