@samitouri / QOSamiQemu / commits / 7c7aaaa342

lsi53c895a: keep lsi_request alive as long as the SCSIRequest

To protect against using the lsi_request after SCSIRequest has been freed, keep the HBA-private data alive until the last reference to the SCSIRequest is gone. Because req->hba_private was used (even if just for an assertion) to check that the request was still either current or queued, add a boolean field that is set when the SCSIRequest is cancelled or completed, which is when the lsi_request would have been unqueued. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Paolo Bonzini committed Mar 27, 2026 at 18:40 UTC 7c7aaaa342b57b0099d7fc4a9803e987b891322b
1 file changed +16 -11
hw/scsi/lsi53c895a.c
+16 -11
@@ -197,6 +197,7 @@ typedef struct lsi_request {
197 uint8_t *dma_buf;
198 uint32_t pending;
199 int out;
200 + bool orphan;
201 QTAILQ_ENTRY(lsi_request) next;
202 } lsi_request;
203
@@ -748,14 +749,20 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
749 return NULL;
750 }
751
751 -static void lsi_request_free(LSIState *s, lsi_request *p)
752 +static void lsi_request_orphan(LSIState *s, lsi_request *p)
753 {
754 + p->orphan = true;
755 if (p == s->current) {
756 s->current = NULL;
757 } else {
758 QTAILQ_REMOVE(&s->queue, p, next);
759 }
758 - g_free(p);
760 + scsi_req_unref(p->req);
761 +}
762 +
763 +static void lsi_free_request(SCSIBus *bus, void *priv)
764 +{
765 + g_free(priv);
766 }
767
768 static void lsi_request_cancelled(SCSIRequest *req)
@@ -763,9 +770,7 @@ static void lsi_request_cancelled(SCSIRequest *req)
770 LSIState *s = LSI53C895A(req->bus->qbus.parent);
771 lsi_request *p = req->hba_private;
772
766 - req->hba_private = NULL;
767 - lsi_request_free(s, p);
768 - scsi_req_unref(req);
773 + lsi_request_orphan(s, p);
774 }
775
776 /* Record that data is available for a queued command. Returns zero if
@@ -817,9 +822,7 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
822 }
823
824 if (req->hba_private == s->current) {
820 - req->hba_private = NULL;
821 - lsi_request_free(s, s->current);
822 - scsi_req_unref(req);
825 + lsi_request_orphan(s, s->current);
826 }
827 if (!stop) {
828 lsi_resume_script(s);
@@ -830,10 +833,11 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
833 static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
834 {
835 LSIState *s = LSI53C895A(req->bus->qbus.parent);
836 + lsi_request *p = req->hba_private;
837 int out;
838
835 - assert(req->hba_private);
836 - if (s->waiting == LSI_WAIT_RESELECT || req->hba_private != s->current ||
839 + assert(!p->orphan);
840 + if (s->waiting == LSI_WAIT_RESELECT || p != s->current ||
841 (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
842 if (lsi_queue_req(s, req, len)) {
843 return;
@@ -2325,7 +2329,8 @@ static const struct SCSIBusInfo lsi_scsi_info = {
2329
2330 .transfer_data = lsi_transfer_data,
2331 .complete = lsi_command_complete,
2328 - .cancel = lsi_request_cancelled
2332 + .cancel = lsi_request_cancelled,
2333 + .free_request = lsi_free_request,
2334 };
2335
2336 static void scripts_timer_cb(void *opaque)