⬢ DragonFlyBSD Kernel Audit
DF-2285 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/cam/scsi/scsi_targ_bh.c
+++ b/sys/bus/cam/scsi/scsi_targ_bh.c
@@ -89,6 +89,7 @@
 	targbh_state	state;
 	targbh_flags	flags;	
 	u_int		init_level;
+	u_int		active_ctios;	/* dispatched CTIOs not yet completed */
 	u_int		inq_data_len;
 	struct		ccb_accept_tio *accept_tio_list;
 	struct		ccb_hdr_slist immed_notify_slist;
@@ -416,6 +417,16 @@
 	case 1:
 		/* FALLTHROUGH */
 	default:
+		/*
+		 * Drain in-flight CTIOs before freeing the softc.  A
+		 * fixed hz/2 sleep is not a wakeup protocol: CTIOs
+		 * dispatched by targbhstart() are owned by the SIM and
+		 * are neither tracked nor aborted by targbhdislun()
+		 * (which only aborts idle ATIOs / immediate notifies).
+		 */
+		while (softc->active_ctios > 0)
+			sim_lock_sleep(&softc->active_ctios, 0, "targbhctio",
+				       0, periph->sim->lock);
 		/* XXX Wait for callback of targbhdislun() */
 		sim_lock_sleep(softc, 0, "targbh", hz/2, periph->sim->lock);
 		kfree(softc, M_SCSIBH);
@@ -492,6 +503,12 @@
 
 		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
 		start_ccb->ccb_h.ccb_atio = atio;
+
+		/*
+		 * Account the CTIO before handing it to the SIM: the SIM
+		 * may complete it synchronously from inside xpt_action().
+		 */
+		softc->active_ctios++;
 		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
 			  ("Sending a CTIO\n"));
 		xpt_action(start_ccb);
@@ -648,6 +665,11 @@
 		TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
 			     periph_links.tqe);
 
+		/* The CTIO is back from the SIM; release the dtor drain. */
+		KKASSERT(softc->active_ctios > 0);
+		softc->active_ctios--;
+		wakeup(&softc->active_ctios);
+
 		/*
 		 * We could check for CAM_SENT_SENSE bein set here,
 		 * but since we're not maintaining any CA/UA state,