]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
scsi: virtio_scsi: Move INIT_WORK calls to virtscsi_probe()
authorJoshua Daley <jdaley@linux.ibm.com>
Wed, 25 Mar 2026 18:08:56 +0000 (19:08 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 27 Mar 2026 20:42:08 +0000 (16:42 -0400)
The last step of virtscsi_handle_event() is to call
virtscsi_kick_event(), which calls INIT_WORK on its own work
item. INIT_WORK resets the work item's data bits to 0.

If this occurs while the work item is being flushed by
cancel_work_sync(), then kernel/workqueue.c/work_offqd_enable triggers a
kernel warning, as it expects the "disable" bit to be 1:

[   21.450115] workqueue: work disable count underflowed
[   21.450117] WARNING: CPU: 1 PID: 56 at kernel/workqueue.c:4328 enable_work+0x10a/0x120
...
[   21.450171] Call Trace:
[   21.450173]  [<000003db2e5bdc3e>] enable_work+0x10e/0x120
[   21.450176] ([<000003db2e5bdc3a>] enable_work+0x10a/0x120)
[   21.450178]  [<000003db2e5bdd86>] cancel_work_sync+0x86/0xa0
[   21.450181]  [<000003daae97d9e4>] virtscsi_remove+0xb4/0xd0 [virtio_scsi]
[   21.450184]  [<000003db2ef3b5ca>] virtio_dev_remove+0x6a/0xd0
[   21.450186]  [<000003db2ef9106c>] device_release_driver_internal+0x1ac/0x260
[   21.450190]  [<000003db2ef8edc8>] bus_remove_device+0xf8/0x190
[   21.450192]  [<000003db2ef88d72>] device_del+0x142/0x340
[   21.450194]  [<000003db2ef88fa0>] device_unregister+0x30/0xa0
[   21.450196]  [<000003db2ef3b2fa>] unregister_virtio_device+0x2a/0x40

This warning may occur if a controller is detached immediately following
a disk detach.

Move the INIT_WORK call to prevent this. Don't re-init event list work
items in virtscsi_kick_event(), init them only once in virtscsi_probe()
instead.

Signed-off-by: Joshua Daley <jdaley@linux.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Link: https://patch.msgid.link/20260325180857.3675854-2-jdaley@linux.ibm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/virtio_scsi.c

index 0ed8558dad724db3540e796893b83b50876983ba..64b6c942f57208257e56f823a3107e5a7193eab1 100644 (file)
@@ -233,7 +233,6 @@ static void virtscsi_ctrl_done(struct virtqueue *vq)
        virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free);
 };
 
-static void virtscsi_handle_event(struct work_struct *work);
 
 static int virtscsi_kick_event(struct virtio_scsi *vscsi,
                               struct virtio_scsi_event_node *event_node)
@@ -242,7 +241,6 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi,
        struct scatterlist sg;
        unsigned long flags;
 
-       INIT_WORK(&event_node->work, virtscsi_handle_event);
        sg_init_one(&sg, event_node->event, sizeof(struct virtio_scsi_event));
 
        spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
@@ -984,8 +982,11 @@ static int virtscsi_probe(struct virtio_device *vdev)
 
        virtio_device_ready(vdev);
 
-       if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
+       if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
+               for (int i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++)
+                       INIT_WORK(&vscsi->event_list[i].work, virtscsi_handle_event);
                virtscsi_kick_event_all(vscsi);
+       }
 
        scsi_scan_host(shost);
        return 0;