ed5979
From 0a4f5bcc2a6f8ac31431e971c1dce9e6ab2191c2 Mon Sep 17 00:00:00 2001
ed5979
From: Stefan Hajnoczi <stefanha@redhat.com>
ed5979
Date: Tue, 21 Feb 2023 16:22:16 -0500
ed5979
Subject: [PATCH 01/12] scsi: protect req->aiocb with AioContext lock
ed5979
ed5979
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
ed5979
RH-MergeRequest: 155: virtio-scsi: reset SCSI devices from main loop thread
ed5979
RH-Bugzilla: 2155748
ed5979
RH-Acked-by: Eric Blake <eblake@redhat.com>
ed5979
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
ed5979
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
ed5979
RH-Commit: [1/3] 61727297bd31dfe18220b61f1d265ced0649c60d (stefanha/centos-stream-qemu-kvm)
ed5979
ed5979
If requests are being processed in the IOThread when a SCSIDevice is
ed5979
unplugged, scsi_device_purge_requests() -> scsi_req_cancel_async() races
ed5979
with I/O completion callbacks. Both threads load and store req->aiocb.
ed5979
This can lead to assert(r->req.aiocb == NULL) failures and undefined
ed5979
behavior.
ed5979
ed5979
Protect r->req.aiocb with the AioContext lock to prevent the race.
ed5979
ed5979
Reviewed-by: Eric Blake <eblake@redhat.com>
ed5979
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
ed5979
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
ed5979
Message-Id: <20230221212218.1378734-2-stefanha@redhat.com>
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
(cherry picked from commit 7b7fc3d0102dafe8eb44802493036a526e921a71)
ed5979
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
ed5979
---
ed5979
 hw/scsi/scsi-disk.c    | 23 ++++++++++++++++-------
ed5979
 hw/scsi/scsi-generic.c | 11 ++++++-----
ed5979
 2 files changed, 22 insertions(+), 12 deletions(-)
ed5979
ed5979
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
ed5979
index e493c28814..5327f93f4c 100644
ed5979
--- a/hw/scsi/scsi-disk.c
ed5979
+++ b/hw/scsi/scsi-disk.c
ed5979
@@ -273,9 +273,11 @@ static void scsi_aio_complete(void *opaque, int ret)
ed5979
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     if (scsi_disk_req_check_error(r, ret, true)) {
ed5979
         goto done;
ed5979
     }
ed5979
@@ -357,10 +359,11 @@ static void scsi_dma_complete(void *opaque, int ret)
ed5979
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
     if (ret < 0) {
ed5979
         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
ed5979
     } else {
ed5979
@@ -393,10 +396,11 @@ static void scsi_read_complete(void *opaque, int ret)
ed5979
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
     if (ret < 0) {
ed5979
         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
ed5979
     } else {
ed5979
@@ -446,10 +450,11 @@ static void scsi_do_read_cb(void *opaque, int ret)
ed5979
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert (r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
     if (ret < 0) {
ed5979
         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
ed5979
     } else {
ed5979
@@ -530,10 +535,11 @@ static void scsi_write_complete(void * opaque, int ret)
ed5979
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert (r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
     if (ret < 0) {
ed5979
         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
ed5979
     } else {
ed5979
@@ -1737,10 +1743,11 @@ static void scsi_unmap_complete(void *opaque, int ret)
ed5979
     SCSIDiskReq *r = data->r;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
     if (scsi_disk_req_check_error(r, ret, true)) {
ed5979
         scsi_req_unref(&r->req);
ed5979
         g_free(data);
ed5979
@@ -1816,9 +1823,11 @@ static void scsi_write_same_complete(void *opaque, int ret)
ed5979
     SCSIDiskReq *r = data->r;
ed5979
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
-    aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
ed5979
+
ed5979
     if (scsi_disk_req_check_error(r, ret, true)) {
ed5979
         goto done;
ed5979
     }
ed5979
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
ed5979
index 92cce20a4d..ac9fa662b4 100644
ed5979
--- a/hw/scsi/scsi-generic.c
ed5979
+++ b/hw/scsi/scsi-generic.c
ed5979
@@ -111,10 +111,11 @@ static void scsi_command_complete(void *opaque, int ret)
ed5979
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
ed5979
     SCSIDevice *s = r->req.dev;
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->conf.blk));
ed5979
     scsi_command_complete_noio(r, ret);
ed5979
     aio_context_release(blk_get_aio_context(s->conf.blk));
ed5979
 }
ed5979
@@ -269,11 +270,11 @@ static void scsi_read_complete(void * opaque, int ret)
ed5979
     SCSIDevice *s = r->req.dev;
ed5979
     int len;
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->conf.blk));
ed5979
-
ed5979
     if (ret || r->req.io_canceled) {
ed5979
         scsi_command_complete_noio(r, ret);
ed5979
         goto done;
ed5979
@@ -386,11 +387,11 @@ static void scsi_write_complete(void * opaque, int ret)
ed5979
 
ed5979
     trace_scsi_generic_write_complete(ret);
ed5979
 
ed5979
+    aio_context_acquire(blk_get_aio_context(s->conf.blk));
ed5979
+
ed5979
     assert(r->req.aiocb != NULL);
ed5979
     r->req.aiocb = NULL;
ed5979
 
ed5979
-    aio_context_acquire(blk_get_aio_context(s->conf.blk));
ed5979
-
ed5979
     if (ret || r->req.io_canceled) {
ed5979
         scsi_command_complete_noio(r, ret);
ed5979
         goto done;
ed5979
-- 
ed5979
2.39.1
ed5979