diff options
| author | Stefan Hajnoczi <stefanha@redhat.com> | 2023-02-21 16:22:16 -0500 |
|---|---|---|
| committer | Kevin Wolf <kwolf@redhat.com> | 2023-02-23 19:49:35 +0100 |
| commit | 7b7fc3d0102dafe8eb44802493036a526e921a71 (patch) | |
| tree | 1e8919c4735b7e602accbaac7e6cfa5400f504aa /hw/scsi/scsi-generic.c | |
| parent | 8ab8140a04cf771d63e9754d6ba6c1e676bfe507 (diff) | |
| download | focaccia-qemu-7b7fc3d0102dafe8eb44802493036a526e921a71.tar.gz focaccia-qemu-7b7fc3d0102dafe8eb44802493036a526e921a71.zip | |
scsi: protect req->aiocb with AioContext lock
If requests are being processed in the IOThread when a SCSIDevice is unplugged, scsi_device_purge_requests() -> scsi_req_cancel_async() races with I/O completion callbacks. Both threads load and store req->aiocb. This can lead to assert(r->req.aiocb == NULL) failures and undefined behavior. Protect r->req.aiocb with the AioContext lock to prevent the race. Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20230221212218.1378734-2-stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'hw/scsi/scsi-generic.c')
| -rw-r--r-- | hw/scsi/scsi-generic.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 92cce20a4d..ac9fa662b4 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -111,10 +111,11 @@ static void scsi_command_complete(void *opaque, int ret) SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIDevice *s = r->req.dev; + aio_context_acquire(blk_get_aio_context(s->conf.blk)); + assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - aio_context_acquire(blk_get_aio_context(s->conf.blk)); scsi_command_complete_noio(r, ret); aio_context_release(blk_get_aio_context(s->conf.blk)); } @@ -269,11 +270,11 @@ static void scsi_read_complete(void * opaque, int ret) SCSIDevice *s = r->req.dev; int len; + aio_context_acquire(blk_get_aio_context(s->conf.blk)); + assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - aio_context_acquire(blk_get_aio_context(s->conf.blk)); - if (ret || r->req.io_canceled) { scsi_command_complete_noio(r, ret); goto done; @@ -386,11 +387,11 @@ static void scsi_write_complete(void * opaque, int ret) trace_scsi_generic_write_complete(ret); + aio_context_acquire(blk_get_aio_context(s->conf.blk)); + assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - aio_context_acquire(blk_get_aio_context(s->conf.blk)); - if (ret || r->req.io_canceled) { scsi_command_complete_noio(r, ret); goto done; |