xref: /plan9-contrib/sys/src/cmd/9660srv/iobuf.c (revision 3e33a36fadd1f83a7b3e74f4a2858d02601a619e)
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