13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include "dat.h"
63e12c5d1SDavid du Colombier #include "fns.h"
73e12c5d1SDavid du Colombier
89a747e4fSDavid du Colombier /*
99a747e4fSDavid du Colombier * We used to use 100 i/o buffers of size 2kb (Sectorsize).
109a747e4fSDavid du Colombier * Unfortunately, reading 2kb at a time often hopping around
119a747e4fSDavid du Colombier * the disk doesn't let us get near the disk bandwidth.
129a747e4fSDavid du Colombier *
139a747e4fSDavid du Colombier * Based on a trace of iobuf address accesses taken while
149a747e4fSDavid du Colombier * tarring up a Plan 9 distribution CD, we now use 16 128kb
159a747e4fSDavid du Colombier * buffers. This works for ISO9660 because data is required
169a747e4fSDavid du Colombier * to be laid out contiguously; effectively we're doing agressive
179a747e4fSDavid du Colombier * readahead. Because the buffers are so big and the typical
189a747e4fSDavid du Colombier * disk accesses so concentrated, it's okay that we have so few
199a747e4fSDavid du Colombier * of them.
209a747e4fSDavid du Colombier *
219a747e4fSDavid du Colombier * If this is used to access multiple discs at once, it's not clear
229a747e4fSDavid du Colombier * how gracefully the scheme degrades, but I'm not convinced
239a747e4fSDavid du Colombier * it's worth worrying about. -rsc
249a747e4fSDavid du Colombier */
253e12c5d1SDavid du Colombier
2631919746SDavid du Colombier /* trying a larger value to get greater throughput - geoff */
2731919746SDavid du Colombier #define BUFPERCLUST 256 /* sectors/cluster; was 64, 64*Sectorsize = 128kb */
289a747e4fSDavid du Colombier #define NCLUST 16
293e12c5d1SDavid du Colombier
30208510e1SDavid du Colombier int nclust = NCLUST;
31208510e1SDavid du Colombier
329a747e4fSDavid du Colombier static Ioclust* iohead;
339a747e4fSDavid du Colombier static Ioclust* iotail;
3431919746SDavid du Colombier
35*3e33a36fSDavid du Colombier static Ioclust* getclust(Xdata*, vlong);
369a747e4fSDavid du Colombier static void putclust(Ioclust*);
379a747e4fSDavid du Colombier static void xread(Ioclust*);
383e12c5d1SDavid du Colombier
393e12c5d1SDavid du Colombier void
iobuf_init(void)409a747e4fSDavid du Colombier iobuf_init(void)
413e12c5d1SDavid du Colombier {
429a747e4fSDavid du Colombier int i, j, n;
439a747e4fSDavid du Colombier Ioclust *c;
449a747e4fSDavid du Colombier Iobuf *b;
459a747e4fSDavid du Colombier uchar *mem;
463e12c5d1SDavid du Colombier
47208510e1SDavid du Colombier n = nclust*sizeof(Ioclust) +
48208510e1SDavid du Colombier nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize);
499a747e4fSDavid du Colombier mem = sbrk(n);
5068412abfSDavid du Colombier if(mem == (void*)-1)
519a747e4fSDavid du Colombier panic(0, "iobuf_init");
529a747e4fSDavid du Colombier memset(mem, 0, n);
533e12c5d1SDavid du Colombier
54208510e1SDavid du Colombier for(i=0; i<nclust; i++){
559a747e4fSDavid du Colombier c = (Ioclust*)mem;
569a747e4fSDavid du Colombier mem += sizeof(Ioclust);
579a747e4fSDavid du Colombier c->addr = -1;
589a747e4fSDavid du Colombier c->prev = iotail;
599a747e4fSDavid du Colombier if(iotail)
609a747e4fSDavid du Colombier iotail->next = c;
619a747e4fSDavid du Colombier iotail = c;
629a747e4fSDavid du Colombier if(iohead == nil)
639a747e4fSDavid du Colombier iohead = c;
643e12c5d1SDavid du Colombier
659a747e4fSDavid du Colombier c->buf = (Iobuf*)mem;
669a747e4fSDavid du Colombier mem += BUFPERCLUST*sizeof(Iobuf);
679a747e4fSDavid du Colombier c->iobuf = mem;
689a747e4fSDavid du Colombier mem += BUFPERCLUST*Sectorsize;
699a747e4fSDavid du Colombier for(j=0; j<BUFPERCLUST; j++){
709a747e4fSDavid du Colombier b = &c->buf[j];
719a747e4fSDavid du Colombier b->clust = c;
729a747e4fSDavid du Colombier b->addr = -1;
739a747e4fSDavid du Colombier b->iobuf = c->iobuf+j*Sectorsize;
749a747e4fSDavid du Colombier }
759a747e4fSDavid du Colombier }
763e12c5d1SDavid du Colombier }
773e12c5d1SDavid du Colombier
783e12c5d1SDavid du Colombier void
purgebuf(Xdata * dev)793e12c5d1SDavid du Colombier purgebuf(Xdata *dev)
803e12c5d1SDavid du Colombier {
819a747e4fSDavid du Colombier Ioclust *p;
823e12c5d1SDavid du Colombier
839a747e4fSDavid du Colombier for(p=iohead; p!=nil; p=p->next)
845d459b5aSDavid du Colombier if(p->dev == dev){
855d459b5aSDavid du Colombier p->addr = -1;
863e12c5d1SDavid du Colombier p->busy = 0;
879a747e4fSDavid du Colombier }
885d459b5aSDavid du Colombier }
893e12c5d1SDavid du Colombier
909a747e4fSDavid du Colombier static Ioclust*
getclust(Xdata * dev,vlong addr)91*3e33a36fSDavid du Colombier getclust(Xdata *dev, vlong addr)
929a747e4fSDavid du Colombier {
939a747e4fSDavid du Colombier Ioclust *c, *f;
949a747e4fSDavid du Colombier
959a747e4fSDavid du Colombier f = nil;
969a747e4fSDavid du Colombier for(c=iohead; c; c=c->next){
979a747e4fSDavid du Colombier if(!c->busy)
989a747e4fSDavid du Colombier f = c;
999a747e4fSDavid du Colombier if(c->addr == addr && c->dev == dev){
1009a747e4fSDavid du Colombier c->busy++;
1019a747e4fSDavid du Colombier return c;
1029a747e4fSDavid du Colombier }
1039a747e4fSDavid du Colombier }
1049a747e4fSDavid du Colombier
1059a747e4fSDavid du Colombier if(f == nil)
1069a747e4fSDavid du Colombier panic(0, "out of buffers");
1079a747e4fSDavid du Colombier
1089a747e4fSDavid du Colombier f->addr = addr;
1099a747e4fSDavid du Colombier f->dev = dev;
1109a747e4fSDavid du Colombier f->busy++;
1119a747e4fSDavid du Colombier if(waserror()){
1129a747e4fSDavid du Colombier f->addr = -1; /* stop caching */
1139a747e4fSDavid du Colombier putclust(f);
1149a747e4fSDavid du Colombier nexterror();
1159a747e4fSDavid du Colombier }
1169a747e4fSDavid du Colombier xread(f);
1179a747e4fSDavid du Colombier poperror();
1189a747e4fSDavid du Colombier return f;
1199a747e4fSDavid du Colombier }
1209a747e4fSDavid du Colombier
1219a747e4fSDavid du Colombier static void
putclust(Ioclust * c)1229a747e4fSDavid du Colombier putclust(Ioclust *c)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier if(c->busy <= 0)
1259a747e4fSDavid du Colombier panic(0, "putbuf");
1269a747e4fSDavid du Colombier c->busy--;
1279a747e4fSDavid du Colombier
1289a747e4fSDavid du Colombier /* Link onto head for LRU */
1299a747e4fSDavid du Colombier if(c == iohead)
1309a747e4fSDavid du Colombier return;
1319a747e4fSDavid du Colombier c->prev->next = c->next;
1329a747e4fSDavid du Colombier
1339a747e4fSDavid du Colombier if(c->next)
1349a747e4fSDavid du Colombier c->next->prev = c->prev;
1359a747e4fSDavid du Colombier else
1369a747e4fSDavid du Colombier iotail = c->prev;
1379a747e4fSDavid du Colombier
1389a747e4fSDavid du Colombier c->prev = nil;
1399a747e4fSDavid du Colombier c->next = iohead;
1409a747e4fSDavid du Colombier iohead->prev = c;
1419a747e4fSDavid du Colombier iohead = c;
1429a747e4fSDavid du Colombier }
1439a747e4fSDavid du Colombier
1449a747e4fSDavid du Colombier Iobuf*
getbuf(Xdata * dev,uvlong addr)145*3e33a36fSDavid du Colombier getbuf(Xdata *dev, uvlong addr)
1469a747e4fSDavid du Colombier {
1479a747e4fSDavid du Colombier int off;
1489a747e4fSDavid du Colombier Ioclust *c;
1499a747e4fSDavid du Colombier
1509a747e4fSDavid du Colombier off = addr%BUFPERCLUST;
1519a747e4fSDavid du Colombier c = getclust(dev, addr - off);
1529a747e4fSDavid du Colombier if(c->nbuf < off){
1539a747e4fSDavid du Colombier c->busy--;
154*3e33a36fSDavid du Colombier error("short read or I/O error");
1559a747e4fSDavid du Colombier }
1569a747e4fSDavid du Colombier return &c->buf[off];
1573e12c5d1SDavid du Colombier }
1583e12c5d1SDavid du Colombier
1593e12c5d1SDavid du Colombier void
putbuf(Iobuf * b)1609a747e4fSDavid du Colombier putbuf(Iobuf *b)
1613e12c5d1SDavid du Colombier {
1629a747e4fSDavid du Colombier putclust(b->clust);
1633e12c5d1SDavid du Colombier }
1643e12c5d1SDavid du Colombier
1659a747e4fSDavid du Colombier static void
xread(Ioclust * c)1669a747e4fSDavid du Colombier xread(Ioclust *c)
1679a747e4fSDavid du Colombier {
1689a747e4fSDavid du Colombier int n;
1699a747e4fSDavid du Colombier Xdata *dev;
1709a747e4fSDavid du Colombier
1719a747e4fSDavid du Colombier dev = c->dev;
17231919746SDavid du Colombier seek(dev->dev, (vlong)c->addr * Sectorsize, 0);
1739a747e4fSDavid du Colombier n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize);
1749a747e4fSDavid du Colombier if(n < Sectorsize)
175*3e33a36fSDavid du Colombier error("short read or I/O error");
1769a747e4fSDavid du Colombier c->nbuf = n/Sectorsize;
1773e12c5d1SDavid du Colombier }
178