ref: a8d00e5d56b261376410c3c87c46327362763bd8
dir: /sys/src/cmd/ext2srv/iobuf.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include "dat.h" #include "fns.h" #define NIOBUF 100 #define HIOB (NIOBUF/3) static Iobuf* hiob[HIOB]; /* hash buckets */ static Iobuf iobuf[NIOBUF]; /* buffer headers */ static Iobuf* iohead; static Iobuf* iotail; Iobuf* getbuf(Xfs *dev, long addr) { Iobuf *p, *h, **l, **f; l = &hiob[addr%HIOB]; for(p = *l; p; p = p->hash) { if(p->addr == addr && p->dev == dev) { p->busy++; return p; } } /* Find a non-busy buffer from the tail */ for(p = iotail; p && (p->busy > 0); p = p->prev) ; if(!p) panic("all buffers busy"); if(p->dirty){ xwrite(p); p->dirty = 0; } if( xread(dev, p, addr) < 0) return 0; /* Delete from hash chain */ f = &hiob[p->addr%HIOB]; if( *f == p ) *f = p->hash; else { for(h = *f; h ; h = h->hash) if( h->hash == p ){ h->hash = p->hash; break; } } /* Fill and hash */ p->hash = *l; *l = p; p->addr = addr; p->dev = dev; p->busy=1; return p; } void putbuf(Iobuf *p) { if(p->busy <= 0) panic("putbuf"); p->busy--; /* Link onto head for lru */ if(p == iohead) return; if( p == iotail ){ p->prev->next = 0; iotail = p->prev; }else{ p->prev->next = p->next; p->next->prev = p->prev; } p->prev = 0; p->next = iohead; iohead->prev = p; iohead = p; } void dirtybuf(Iobuf *p) { if(p->busy <=0) panic("dirtybuf"); p->dirty = 1; } void syncbuf(void) { Iobuf *p; for(p=&iobuf[0] ; p<&iobuf[NIOBUF]; p++) if( p->dirty ){ xwrite(p); p->dirty = 0; } } void purgebuf(Xfs *dev) { Iobuf *p; for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) if(p->dev == dev) p->busy = 0; /* Blow hash chains */ memset(hiob, 0, sizeof(hiob)); } void iobuf_init(void) { Iobuf *p; iohead = iobuf; iotail = iobuf+NIOBUF-1; for(p = iobuf; p <= iotail; p++) { p->next = p+1; p->prev = p-1; p->iobuf = (char *)malloc(EXT2_MAX_BLOCK_SIZE); if(p->iobuf == 0) panic("iobuf_init"); } iohead->prev = 0; iotail->next = 0; } int xread(Xfs *dev, Iobuf *p, long addr) { /*chat("xread %d,%d...", dev->dev, addr);*/ seek(dev->dev, (vlong)addr*dev->block_size, 0); if(read(dev->dev, p->iobuf, dev->block_size) != dev->block_size){ chat("xread %d, block=%d failed ...", dev->dev, addr); errno = Eio; return -1; } /*chat("xread ok...");*/ return 0; } void xwrite(Iobuf *p) { Xfs *dev; long addr; dev = p->dev; addr = p->addr; /*chat("xwrite %d,%d...", dev->dev, addr);*/ seek(dev->dev, (vlong)addr*dev->block_size, 0); if(write(dev->dev, p->iobuf, dev->block_size) != dev->block_size){ chat("xwrite %d, block=%d failed ...", dev->dev, addr); errno = Eio; return; } /*chat("xwrite ok...");*/ } void dumpbuf(void) { Iobuf *p; for(p = iotail; p ; p = p->prev) if( p->busy ) mchat("\nHi ERROR buf(%x, %d, %d)\n", p, p->addr, p->busy); }