From 48a355cf5b382570975e60857450ff3d42f268e9 Mon Sep 17 00:00:00 2001 From: Karl Mehltretter Date: Tue, 8 Sep 2026 07:38:13 +0200 Subject: [PATCH] virtio_ccw: always take irq_lock in the classic interrupt handler virtio_ccw_int_handler() takes vcdev->irq_lock around its vring_interrupt() calls only when VIRTIO_HARDEN_NOTIFICATION is enabled. The virtio shutdown path calls synchronize_cbs() even when notification hardening is disabled. virtio_reset_device() now does so after the transport reset too. For classic interrupts, synchronize_cbs() takes vcdev->irq_lock for writing, but the interrupt handler does not take the matching read lock in that configuration. synchronize_cbs() can return while a callback is still running. Take the read lock unconditionally so the write side can synchronize with the callbacks. Fixes: 8bd2fa086a04 ("virtio: break and reset virtio devices on device_shutdown()") Assisted-by: LLM Signed-off-by: Karl Mehltretter Signed-off-by: Michael S. Tsirkin Message-ID: <20260908053817.26065-3-kmehltretter@gmail.com> --- drivers/s390/virtio/virtio_ccw.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index b90299205698..552d77998012 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -1204,13 +1204,11 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, vcdev->err = -EIO; } virtio_ccw_check_activity(vcdev, activity); -#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION /* * Paired with virtio_ccw_synchronize_cbs() and interrupts are * disabled here. */ read_lock(&vcdev->irq_lock); -#endif for_each_set_bit(i, indicators(vcdev), sizeof(*indicators(vcdev)) * BITS_PER_BYTE) { /* The bit clear must happen before the vring kick. */ @@ -1219,9 +1217,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, vq = virtio_ccw_vq_by_ind(vcdev, i); vring_interrupt(0, vq); } -#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION read_unlock(&vcdev->irq_lock); -#endif if (test_bit(0, indicators2(vcdev))) { virtio_config_changed(&vcdev->vdev); clear_bit(0, indicators2(vcdev));