|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <auth.h> | 
|  | #include <fcall.h> | 
|  | #include "dat.h" | 
|  | #include "fns.h" | 
|  |  | 
|  | /* | 
|  | * We used to use 100 i/o buffers of size 2kb (Sectorsize). | 
|  | * Unfortunately, reading 2kb at a time often hopping around | 
|  | * the disk doesn't let us get near the disk bandwidth. | 
|  | * | 
|  | * Based on a trace of iobuf address accesses taken while | 
|  | * tarring up a Plan 9 distribution CD, we now use 16 128kb | 
|  | * buffers.  This works for ISO9660 because data is required | 
|  | * to be laid out contiguously; effectively we're doing agressive | 
|  | * readahead.  Because the buffers are so big and the typical | 
|  | * disk accesses so concentrated, it's okay that we have so few | 
|  | * of them. | 
|  | * | 
|  | * If this is used to access multiple discs at once, it's not clear | 
|  | * how gracefully the scheme degrades, but I'm not convinced | 
|  | * it's worth worrying about.		-rsc | 
|  | */ | 
|  |  | 
|  | /* trying a larger value to get greater throughput - geoff */ | 
|  | #define	BUFPERCLUST	256 /* sectors/cluster; was 64, 64*Sectorsize = 128kb */ | 
|  | #define	NCLUST		16 | 
|  |  | 
|  | int nclust = NCLUST; | 
|  |  | 
|  | static Ioclust*	iohead; | 
|  | static Ioclust*	iotail; | 
|  |  | 
|  | static Ioclust*	getclust(Xdata*, long); | 
|  | static void	putclust(Ioclust*); | 
|  | static void	xread(Ioclust*); | 
|  |  | 
|  | void | 
|  | iobuf_init(void) | 
|  | { | 
|  | int i, j, n; | 
|  | Ioclust *c; | 
|  | Iobuf *b; | 
|  | uchar *mem; | 
|  |  | 
|  | n = nclust*sizeof(Ioclust) + | 
|  | nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize); | 
|  | mem = sbrk(n); | 
|  | if(mem == (void*)-1) | 
|  | panic(0, "iobuf_init"); | 
|  | memset(mem, 0, n); | 
|  |  | 
|  | for(i=0; i<nclust; i++){ | 
|  | c = (Ioclust*)mem; | 
|  | mem += sizeof(Ioclust); | 
|  | c->addr = -1; | 
|  | c->prev = iotail; | 
|  | if(iotail) | 
|  | iotail->next = c; | 
|  | iotail = c; | 
|  | if(iohead == nil) | 
|  | iohead = c; | 
|  |  | 
|  | c->buf = (Iobuf*)mem; | 
|  | mem += BUFPERCLUST*sizeof(Iobuf); | 
|  | c->iobuf = mem; | 
|  | mem += BUFPERCLUST*Sectorsize; | 
|  | for(j=0; j<BUFPERCLUST; j++){ | 
|  | b = &c->buf[j]; | 
|  | b->clust = c; | 
|  | b->addr = -1; | 
|  | b->iobuf = c->iobuf+j*Sectorsize; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | purgebuf(Xdata *dev) | 
|  | { | 
|  | Ioclust *p; | 
|  |  | 
|  | for(p=iohead; p!=nil; p=p->next) | 
|  | if(p->dev == dev){ | 
|  | p->addr = -1; | 
|  | p->busy = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static Ioclust* | 
|  | getclust(Xdata *dev, long addr) | 
|  | { | 
|  | Ioclust *c, *f; | 
|  |  | 
|  | f = nil; | 
|  | for(c=iohead; c; c=c->next){ | 
|  | if(!c->busy) | 
|  | f = c; | 
|  | if(c->addr == addr && c->dev == dev){ | 
|  | c->busy++; | 
|  | return c; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(f == nil) | 
|  | panic(0, "out of buffers"); | 
|  |  | 
|  | f->addr = addr; | 
|  | f->dev = dev; | 
|  | f->busy++; | 
|  | if(waserror()){ | 
|  | f->addr = -1;	/* stop caching */ | 
|  | putclust(f); | 
|  | nexterror(); | 
|  | } | 
|  | xread(f); | 
|  | poperror(); | 
|  | return f; | 
|  | } | 
|  |  | 
|  | static void | 
|  | putclust(Ioclust *c) | 
|  | { | 
|  | if(c->busy <= 0) | 
|  | panic(0, "putbuf"); | 
|  | c->busy--; | 
|  |  | 
|  | /* Link onto head for LRU */ | 
|  | if(c == iohead) | 
|  | return; | 
|  | c->prev->next = c->next; | 
|  |  | 
|  | if(c->next) | 
|  | c->next->prev = c->prev; | 
|  | else | 
|  | iotail = c->prev; | 
|  |  | 
|  | c->prev = nil; | 
|  | c->next = iohead; | 
|  | iohead->prev = c; | 
|  | iohead = c; | 
|  | } | 
|  |  | 
|  | Iobuf* | 
|  | getbuf(Xdata *dev, ulong addr) | 
|  | { | 
|  | int off; | 
|  | Ioclust *c; | 
|  |  | 
|  | off = addr%BUFPERCLUST; | 
|  | c = getclust(dev, addr - off); | 
|  | if(c->nbuf < off){ | 
|  | c->busy--; | 
|  | error("I/O read error"); | 
|  | } | 
|  | return &c->buf[off]; | 
|  | } | 
|  |  | 
|  | void | 
|  | putbuf(Iobuf *b) | 
|  | { | 
|  | putclust(b->clust); | 
|  | } | 
|  |  | 
|  | static void | 
|  | xread(Ioclust *c) | 
|  | { | 
|  | int n; | 
|  | Xdata *dev; | 
|  |  | 
|  | dev = c->dev; | 
|  | seek(dev->dev, (vlong)c->addr * Sectorsize, 0); | 
|  | n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize); | 
|  | if(n < Sectorsize) | 
|  | error("I/O read error"); | 
|  | c->nbuf = n/Sectorsize; | 
|  | } |