plan9fox/sys/src/cmd/ext2srv/iobuf.c
2011-03-30 19:35:09 +03:00

175 lines
2.8 KiB
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);
}