Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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);     
}