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);
--
⑨