diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ext2srv/iobuf.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ext2srv/iobuf.c')
-rwxr-xr-x | sys/src/cmd/ext2srv/iobuf.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/sys/src/cmd/ext2srv/iobuf.c b/sys/src/cmd/ext2srv/iobuf.c new file mode 100755 index 000000000..07e834c3c --- /dev/null +++ b/sys/src/cmd/ext2srv/iobuf.c @@ -0,0 +1,174 @@ +#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); +} |