svn commit: r272223 - head/sys/dev/ahci

Steven Hartland smh at FreeBSD.org
Sat Sep 27 19:14:23 UTC 2014


Author: smh
Date: Sat Sep 27 19:14:22 2014
New Revision: 272223
URL: http://svnweb.freebsd.org/changeset/base/272223

Log:
  Use a local STAILQ for unlocked done CCB processing in ahci direct mode
  
  Previously it was possible for issues e.g. use after free, to result
  from processing the done queue while not holding the channel lock.
  
  While this should never happen in practice, unexpected code flows
  which result in two threads processing from the same queue may
  be possible.
  
  We now use a local STAILQ to prevent this ever being an issue.
  
  Sponsored by:	Multiplay

Modified:
  head/sys/dev/ahci/ahci.c

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c	Sat Sep 27 18:35:16 2014	(r272222)
+++ head/sys/dev/ahci/ahci.c	Sat Sep 27 19:14:22 2014	(r272223)
@@ -1126,6 +1126,7 @@ ahci_ch_intr_direct(void *arg)
 	struct ahci_channel *ch = (struct ahci_channel *)arg;
 	struct ccb_hdr *ccb_h;
 	uint32_t istatus;
+	STAILQ_HEAD(, ccb_hdr) tmp_doneq = STAILQ_HEAD_INITIALIZER(tmp_doneq);
 
 	/* Read interrupt statuses. */
 	istatus = ATA_INL(ch->r_mem, AHCI_P_IS);
@@ -1136,9 +1137,14 @@ ahci_ch_intr_direct(void *arg)
 	ch->batch = 1;
 	ahci_ch_intr_main(ch, istatus);
 	ch->batch = 0;
+	/*
+	 * Prevent the possibility of issues caused by processing the queue
+	 * while unlocked below by moving the contents to a local queue.
+	 */
+	STAILQ_CONCAT(&tmp_doneq, &ch->doneq);
 	mtx_unlock(&ch->mtx);
-	while ((ccb_h = STAILQ_FIRST(&ch->doneq)) != NULL) {
-		STAILQ_REMOVE_HEAD(&ch->doneq, sim_links.stqe);
+	while ((ccb_h = STAILQ_FIRST(&tmp_doneq)) != NULL) {
+		STAILQ_REMOVE_HEAD(&tmp_doneq, sim_links.stqe);
 		xpt_done_direct((union ccb *)ccb_h);
 	}
 }


More information about the svn-src-all mailing list