plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

iobuf.c (3224B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <auth.h>
      4 #include <fcall.h>
      5 #include "dat.h"
      6 #include "fns.h"
      7 
      8 /*
      9  * We used to use 100 i/o buffers of size 2kb (Sectorsize).
     10  * Unfortunately, reading 2kb at a time often hopping around
     11  * the disk doesn't let us get near the disk bandwidth.
     12  *
     13  * Based on a trace of iobuf address accesses taken while
     14  * tarring up a Plan 9 distribution CD, we now use 16 128kb
     15  * buffers.  This works for ISO9660 because data is required
     16  * to be laid out contiguously; effectively we're doing agressive
     17  * readahead.  Because the buffers are so big and the typical
     18  * disk accesses so concentrated, it's okay that we have so few
     19  * of them.
     20  *
     21  * If this is used to access multiple discs at once, it's not clear
     22  * how gracefully the scheme degrades, but I'm not convinced
     23  * it's worth worrying about.		-rsc
     24  */
     25 
     26 /* trying a larger value to get greater throughput - geoff */
     27 #define	BUFPERCLUST	256 /* sectors/cluster; was 64, 64*Sectorsize = 128kb */
     28 #define	NCLUST		16
     29 
     30 int nclust = NCLUST;
     31 
     32 static Ioclust*	iohead;
     33 static Ioclust*	iotail;
     34 
     35 static Ioclust*	getclust(Xdata*, long);
     36 static void	putclust(Ioclust*);
     37 static void	xread(Ioclust*);
     38 
     39 void
     40 iobuf_init(void)
     41 {
     42 	int i, j, n;
     43 	Ioclust *c;
     44 	Iobuf *b;
     45 	uchar *mem;
     46 
     47 	n = nclust*sizeof(Ioclust) +
     48 		nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize);
     49 	mem = malloc(n);
     50 	if(mem == (void*)0)
     51 		panic(0, "iobuf_init");
     52 	memset(mem, 0, n);
     53 
     54 	for(i=0; i<nclust; i++){
     55 		c = (Ioclust*)mem;
     56 		mem += sizeof(Ioclust);
     57 		c->addr = -1;
     58 		c->prev = iotail;
     59 		if(iotail)
     60 			iotail->next = c;
     61 		iotail = c;
     62 		if(iohead == nil)
     63 			iohead = c;
     64 
     65 		c->buf = (Iobuf*)mem;
     66 		mem += BUFPERCLUST*sizeof(Iobuf);
     67 		c->iobuf = mem;
     68 		mem += BUFPERCLUST*Sectorsize;
     69 		for(j=0; j<BUFPERCLUST; j++){
     70 			b = &c->buf[j];
     71 			b->clust = c;
     72 			b->addr = -1;
     73 			b->iobuf = c->iobuf+j*Sectorsize;
     74 		}
     75 	}
     76 }
     77 
     78 void
     79 purgebuf(Xdata *dev)
     80 {
     81 	Ioclust *p;
     82 
     83 	for(p=iohead; p!=nil; p=p->next)
     84 		if(p->dev == dev){
     85 			p->addr = -1;
     86 			p->busy = 0;
     87 		}
     88 }
     89 
     90 static Ioclust*
     91 getclust(Xdata *dev, long addr)
     92 {
     93 	Ioclust *c, *f;
     94 
     95 	f = nil;
     96 	for(c=iohead; c; c=c->next){
     97 		if(!c->busy)
     98 			f = c;
     99 		if(c->addr == addr && c->dev == dev){
    100 			c->busy++;
    101 			return c;
    102 		}
    103 	}
    104 
    105 	if(f == nil)
    106 		panic(0, "out of buffers");
    107 
    108 	f->addr = addr;
    109 	f->dev = dev;
    110 	f->busy++;
    111 	if(waserror()){
    112 		f->addr = -1;	/* stop caching */
    113 		putclust(f);
    114 		nexterror();
    115 	}
    116 	xread(f);
    117 	poperror();
    118 	return f;
    119 }
    120 
    121 static void
    122 putclust(Ioclust *c)
    123 {
    124 	if(c->busy <= 0)
    125 		panic(0, "putbuf");
    126 	c->busy--;
    127 
    128 	/* Link onto head for LRU */
    129 	if(c == iohead)
    130 		return;
    131 	c->prev->next = c->next;
    132 
    133 	if(c->next)
    134 		c->next->prev = c->prev;
    135 	else
    136 		iotail = c->prev;
    137 
    138 	c->prev = nil;
    139 	c->next = iohead;
    140 	iohead->prev = c;
    141 	iohead = c;
    142 }
    143 
    144 Iobuf*
    145 getbuf(Xdata *dev, ulong addr)
    146 {
    147 	int off;
    148 	Ioclust *c;
    149 
    150 	off = addr%BUFPERCLUST;
    151 	c = getclust(dev, addr - off);
    152 	if(c->nbuf < off){
    153 		c->busy--;
    154 		error("I/O read error");
    155 	}
    156 	return &c->buf[off];
    157 }
    158 
    159 void
    160 putbuf(Iobuf *b)
    161 {
    162 	putclust(b->clust);
    163 }
    164 
    165 static void
    166 xread(Ioclust *c)
    167 {
    168 	int n;
    169 	Xdata *dev;
    170 
    171 	dev = c->dev;
    172 	seek(dev->dev, (vlong)c->addr * Sectorsize, 0);
    173 	n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize);
    174 	if(n < Sectorsize)
    175 		error("I/O read error");
    176 	c->nbuf = n/Sectorsize;
    177 }