git: 9front

Download patch

ref: 234d8ff34a5defef6022853b090f0692a45bcded
parent: d59f7275a20e040fe73f81bcbbadb225ff4a4c9f
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Sun Sep 2 21:54:34 EDT 2012

usb: fix isowrite putsamples race

--- a/sys/src/9/pc/usbohci.c
+++ b/sys/src/9/pc/usbohci.c
@@ -1762,25 +1762,23 @@
 
 /*
  * Put new samples in the dummy Td.
- * BUG: This does only a transfer per Td. We could do up to 8.
  */
 static long
-putsamples(Ctlr *ctlr, Ep *ep, Isoio *iso, uchar *b, long count)
+putsamples(Ctlr *ctlr, Ep *ep, Isoio *iso, uchar *b, long n)
 {
 	Td *td;
-	ulong n;
 
 	td = pa2ptr(iso->ed->tail);
-	n = count;
 	if(n > td->nbytes - BLEN(td->bp))
 		n = td->nbytes - BLEN(td->bp);
 	assert(td->bp->wp + n <= td->bp->lim);
+	iunlock(ctlr);		/* We could page fault here */
 	memmove(td->bp->wp, b, n);
-	td->bp->wp += n;
-	if(BLEN(td->bp) == td->nbytes){	/* full Td: activate it */
-		ilock(ctlr);
-		isoadvance(ep, iso, td);
-		iunlock(ctlr);
+	ilock(ctlr);
+	if(td == pa2ptr(iso->ed->tail)){
+		td->bp->wp += n;
+		if(BLEN(td->bp) == td->nbytes)	/* full Td: activate it */
+			isoadvance(ep, iso, td);
 	}
 	return n;
 }
@@ -1834,9 +1832,7 @@
 		}
 		if(iso->state != Qrun)
 			panic("episowrite: iso not running");
-		iunlock(ctlr);		/* We could page fault here */
 		nw = putsamples(ctlr, ep, iso, b+tot, count-tot);
-		ilock(ctlr);
 	}
 	while(isodelay(iso) == 0){
 		iunlock(ctlr);
--- a/sys/src/9/pc/usbuhci.c
+++ b/sys/src/9/pc/usbuhci.c
@@ -993,21 +993,27 @@
  * it is activated and tdu advanced.
  */
 static long
-putsamples(Isoio *iso, uchar *b, long count)
+putsamples(Ctlr *ctlr, Isoio *iso, uchar *b, long count)
 {
-	long tot;
-	long n;
+	long n, tot, left;
+	Td *tdu;
 
 	for(tot = 0; isocanwrite(iso) && tot < count; tot += n){
 		n = count-tot;
-		if(n > maxtdlen(iso->tdu) - iso->nleft)
-			n = maxtdlen(iso->tdu) - iso->nleft;
-		memmove(iso->tdu->data+iso->nleft, b+tot, n);
+		tdu = iso->tdu;
+		left = iso->nleft;
+		if(n > maxtdlen(tdu) - left)
+			n = maxtdlen(tdu) - left;
+		iunlock(ctlr);	/* can pagefault here */
+		memmove(tdu->data+left, b+tot, n);
+		ilock(ctlr);
+		if(tdu != iso->tdu)
+			continue;
 		iso->nleft += n;
-		if(iso->nleft == maxtdlen(iso->tdu)){
-			tdisoinit(iso, iso->tdu, iso->nleft);
+		if(iso->nleft == maxtdlen(tdu)){
+			tdisoinit(iso, tdu, iso->nleft);
+			iso->tdu = tdu->next;
 			iso->nleft = 0;
-			iso->tdu = iso->tdu->next;
 		}
 	}
 	return tot;
@@ -1065,9 +1071,7 @@
 		}
 		if(iso->state != Qrun)
 			panic("episowrite: iso not running");
-		iunlock(ctlr);		/* We could page fault here */
-		nw = putsamples(iso, b+tot, count-tot);
-		ilock(ctlr);
+		nw = putsamples(ctlr, iso, b+tot, count-tot);
 	}
 	while(isodelay(iso) == 0){
 		iunlock(ctlr);
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -1996,33 +1996,44 @@
  * it is activated and tdu advanced.
  */
 static long
-putsamples(Isoio *iso, uchar *b, long count)
+putsamples(Ctlr *ctlr, Isoio *iso, uchar *b, long count)
 {
-	long tot, n;
+	long left, tot, n;
+	Sitd *stdu;
+	Itd *tdu;
 
 	for(tot = 0; isocanwrite(iso) && tot < count; tot += n){
 		n = count-tot;
+		left = iso->nleft;
 		if(iso->hs != 0){
-			if(n > iso->tdu->mdata - iso->nleft)
-				n = iso->tdu->mdata - iso->nleft;
-			memmove(iso->tdu->data + iso->nleft, b + tot, n);
-			coherence();
+			tdu = iso->tdu;
+			if(n > tdu->mdata - left)
+				n = tdu->mdata - left;
+			iunlock(ctlr);		/* We could page fault here */
+			memmove(tdu->data + left, b + tot, n);
+			ilock(ctlr);
+			if(iso->tdu != tdu)
+				continue;
 			iso->nleft += n;
-			if(iso->nleft == iso->tdu->mdata){
-				itdinit(iso, iso->tdu);
+			if(iso->nleft == tdu->mdata){
+				itdinit(iso, tdu);
+				iso->tdu = tdu->next;
 				iso->nleft = 0;
-				iso->tdu = iso->tdu->next;
 			}
 		}else{
-			if(n > iso->stdu->mdata - iso->nleft)
-				n = iso->stdu->mdata - iso->nleft;
-			memmove(iso->stdu->data + iso->nleft, b + tot, n);
-			coherence();
+			stdu = iso->stdu;
+			if(n > stdu->mdata - left)
+				n = stdu->mdata - left;
+			iunlock(ctlr);		/* We could page fault here */
+			memmove(stdu->data + left, b + tot, n);
+			ilock(ctlr);
+			if(iso->stdu != stdu)
+				continue;
 			iso->nleft += n;
-			if(iso->nleft == iso->stdu->mdata){
-				sitdinit(iso, iso->stdu);
+			if(iso->nleft == stdu->mdata){
+				sitdinit(iso, stdu);
+				iso->stdu = stdu->next;
 				iso->nleft = 0;
-				iso->stdu = iso->stdu->next;
 			}
 		}
 	}
@@ -2081,9 +2092,7 @@
 		}
 		if(iso->state != Qrun)
 			panic("episowrite: iso not running");
-		iunlock(ctlr);		/* We could page fault here */
-		nw = putsamples(iso, b+tot, count-tot);
-		ilock(ctlr);
+		nw = putsamples(ctlr, iso, b+tot, count-tot);
 	}
 	while(isodelay(iso) == 0){
 		iunlock(ctlr);
--