Blame SOURCES/kvm-virtio-scsi-fix-race-in-virtio_scsi_dataplane_start.patch

586cba
From cbcab5ed1686fddeb2c6adb3a3f6ed0678a36e71 Mon Sep 17 00:00:00 2001
586cba
From: Stefan Hajnoczi <stefanha@redhat.com>
586cba
Date: Mon, 8 Aug 2022 12:21:34 -0400
586cba
Subject: [PATCH 23/23] virtio-scsi: fix race in virtio_scsi_dataplane_start()
586cba
586cba
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
586cba
RH-MergeRequest: 211: virtio-scsi: fix race in virtio_scsi_dataplane_start() (RHEL src-git)
586cba
RH-Commit: [1/1] 2d4964d8863e259326a73fb918fa2f5f63b4a60a
586cba
RH-Bugzilla: 2099541
586cba
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
586cba
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
586cba
RH-Acked-by: Hanna Reitz <hreitz@redhat.com>
586cba
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
586cba
586cba
As soon as virtio_scsi_data_plane_start() attaches host notifiers the
586cba
IOThread may start virtqueue processing. There is a race between
586cba
IOThread virtqueue processing and virtio_scsi_data_plane_start() because
586cba
it only assigns s->dataplane_started after attaching host notifiers.
586cba
586cba
When a virtqueue handler function in the IOThread calls
586cba
virtio_scsi_defer_to_dataplane() it may see !s->dataplane_started and
586cba
attempt to start dataplane even though we're already in the IOThread:
586cba
586cba
  #0  0x00007f67b360857c __pthread_kill_implementation (libc.so.6 + 0xa257c)
586cba
  #1  0x00007f67b35bbd56 raise (libc.so.6 + 0x55d56)
586cba
  #2  0x00007f67b358e833 abort (libc.so.6 + 0x28833)
586cba
  #3  0x00007f67b358e75b __assert_fail_base.cold (libc.so.6 + 0x2875b)
586cba
  #4  0x00007f67b35b4cd6 __assert_fail (libc.so.6 + 0x4ecd6)
586cba
  #5  0x000055ca87fd411b memory_region_transaction_commit (qemu-kvm + 0x67511b)
586cba
  #6  0x000055ca87e17811 virtio_pci_ioeventfd_assign (qemu-kvm + 0x4b8811)
586cba
  #7  0x000055ca87e14836 virtio_bus_set_host_notifier (qemu-kvm + 0x4b5836)
586cba
  #8  0x000055ca87f8e14e virtio_scsi_set_host_notifier (qemu-kvm + 0x62f14e)
586cba
  #9  0x000055ca87f8dd62 virtio_scsi_dataplane_start (qemu-kvm + 0x62ed62)
586cba
  #10 0x000055ca87e14610 virtio_bus_start_ioeventfd (qemu-kvm + 0x4b5610)
586cba
  #11 0x000055ca87f8c29a virtio_scsi_handle_ctrl (qemu-kvm + 0x62d29a)
586cba
  #12 0x000055ca87fa5902 virtio_queue_host_notifier_read (qemu-kvm + 0x646902)
586cba
  #13 0x000055ca882c099e aio_dispatch_handler (qemu-kvm + 0x96199e)
586cba
  #14 0x000055ca882c1761 aio_poll (qemu-kvm + 0x962761)
586cba
  #15 0x000055ca880e1052 iothread_run (qemu-kvm + 0x782052)
586cba
  #16 0x000055ca882c562a qemu_thread_start (qemu-kvm + 0x96662a)
586cba
586cba
This patch assigns s->dataplane_started before attaching host notifiers
586cba
so that virtqueue handler functions that run in the IOThread before
586cba
virtio_scsi_data_plane_start() returns correctly identify that dataplane
586cba
does not need to be started. This fix is taken from the virtio-blk
586cba
dataplane code and it's worth adding a comment in virtio-blk as well to
586cba
explain why it works.
586cba
586cba
Note that s->dataplane_started does not need the AioContext lock because
586cba
it is set before attaching host notifiers and cleared after detaching
586cba
host notifiers. In other words, the IOThread always sees the value true
586cba
and the main loop thread does not modify it while the IOThread is
586cba
active.
586cba
586cba
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2099541
586cba
Reported-by: Qing Wang <qinwang@redhat.com>
586cba
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
586cba
Message-Id: <20220808162134.240405-1-stefanha@redhat.com>
586cba
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
586cba
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
586cba
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
586cba
(cherry picked from commit 9a4b6a63aee885931622549c85669dcca03bed39)
586cba
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
586cba
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
586cba
---
586cba
 hw/block/dataplane/virtio-blk.c |  5 +++++
586cba
 hw/scsi/virtio-scsi-dataplane.c | 11 ++++++++---
586cba
 2 files changed, 13 insertions(+), 3 deletions(-)
586cba
586cba
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
586cba
index 49276e46f2..26f965cabc 100644
586cba
--- a/hw/block/dataplane/virtio-blk.c
586cba
+++ b/hw/block/dataplane/virtio-blk.c
586cba
@@ -219,6 +219,11 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
586cba
 
586cba
     memory_region_transaction_commit();
586cba
 
586cba
+    /*
586cba
+     * These fields are visible to the IOThread so we rely on implicit barriers
586cba
+     * in aio_context_acquire() on the write side and aio_notify_accept() on
586cba
+     * the read side.
586cba
+     */
586cba
     s->starting = false;
586cba
     vblk->dataplane_started = true;
586cba
     trace_virtio_blk_data_plane_start(s);
586cba
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
586cba
index 8bb6e6acfc..20bb91766e 100644
586cba
--- a/hw/scsi/virtio-scsi-dataplane.c
586cba
+++ b/hw/scsi/virtio-scsi-dataplane.c
586cba
@@ -136,6 +136,14 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
586cba
 
586cba
     memory_region_transaction_commit();
586cba
 
586cba
+    /*
586cba
+     * These fields are visible to the IOThread so we rely on implicit barriers
586cba
+     * in aio_context_acquire() on the write side and aio_notify_accept() on
586cba
+     * the read side.
586cba
+     */
586cba
+    s->dataplane_starting = false;
586cba
+    s->dataplane_started = true;
586cba
+
586cba
     aio_context_acquire(s->ctx);
586cba
     virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
586cba
     virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
586cba
@@ -143,9 +151,6 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
586cba
     for (i = 0; i < vs->conf.num_queues; i++) {
586cba
         virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
586cba
     }
586cba
-
586cba
-    s->dataplane_starting = false;
586cba
-    s->dataplane_started = true;
586cba
     aio_context_release(s->ctx);
586cba
     return 0;
586cba
 
586cba
-- 
586cba
2.31.1
586cba