/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include "cformat.h"#include "lru.h"#include "bcache.h"#include "disk.h"#include "inode.h"#include "stats.h" /* * read the inode blocks and make sure they * haven't been trashed. * * make the in-core table of qid to inode mappings. * N.B. this is just an array. we need a linear search to find * a particular inode. this could be done faster. * * nab is the first inode block. */intiinit(Icache *ic, int f, int psize, char* name){ Ibuf *b; Imap *m; ulong ino; Bbuf *bb; Dinode *bi; /* * get basic sizes and allocation info from disk */ if(dinit(ic, f, psize, name) < 0) return -1; /* * read first inode block to get number of inodes */ bb = bcread(ic, ic->nab); if(bb == 0){ fprint(2, "iinit: can't read disk\n"); return -1; } bi = (Dinode*)bb->data; if(bi->nino==0 || bi->nino>2048){ fprint(2, "iinit: bad nino\n"); return -1; } ic->nino = bi->nino; /* * set up sizing constants */ ic->i2b = (ic->bsize - sizeof(Dihdr))/sizeof(Inode); ic->nib = (ic->nino + ic->i2b - 1)/ic->i2b; /* * allocate the in-core qid/inode map, build it's lru */ if(ic->map) free(ic->map); ic->map = malloc(sizeof(Imap)*ic->nino); if(ic->map == 0){ fprint(2, "iinit: can't alloc map\n"); return -1; } lruinit(&ic->mlru); for(m = ic->map; m < &ic->map[ic->nino]; m++){ m->inuse = 0; m->b = 0; lruadd(&ic->mlru, m); } /* * mark all cache buffers as empty, put them on the lru list */ lruinit(&ic->blru); for(b = ic->ib; b < &ic->ib[Nicache]; b++){ b->inuse = 0; lruadd(&ic->blru, b); } /* * Read all inodes and * build the in-core qid/inode map */ for(ino = 0; ino < ic->nino; ino++){ b = iread(ic, ino); if(b == 0){ fprint(2, "iinit: can't read inode %ld\n", ino); return -1; } if(b->inode.inuse){ m = &ic->map[ino]; m->inuse = 1; m->qid = b->inode.qid; lruref(&ic->mlru, m); } } return 0;} /* * format the inode blocks */intiformat(Icache *ic, int f, ulong nino, char *name, int bsize, int psize){ int nib; ulong bno, i2b, i; Bbuf *bb; Dinode *bi; /* * first format disk allocation */ if(dformat(ic, f, name, bsize, psize) < 0) return -1; fprint(2, "formatting inodes\n"); i2b = (bsize - sizeof(Dihdr))/sizeof(Inode); nib = (nino + i2b - 1)/i2b; for(bno = ic->nab; bno < ic->nab + nib; bno++){ if(dalloc(ic, 0) == Notabno){ fprint(2, "iformat: balloc failed\n"); return -1; } bb = bcalloc(ic, bno); if(bb == 0){ fprint(2, "iformat: bcalloc failed\n"); return -1; } bi = (Dinode*)bb->data; bi->magic = Imagic; bi->nino = nino; for(i = 0; i < i2b; i++) bi->inode[i].inuse = 0; bcmark(ic, bb); } bcsync(ic); return iinit(ic, f, psize, name);} /* * allocate a cache buffer, use least recently used */Ibuf*ialloc(Icache *ic, ulong ino){ Imap *m; Ibuf *b; b = (Ibuf*)ic->blru.lnext; if(b->inuse) ic->map[b->ino].b = 0; b->ino = ino; b->inuse = 1; m = &ic->map[ino]; m->b = b; return b;} /* * free a cache buffer */voidifree(Icache *ic, Ibuf *b){ b->inuse = 0; if(b->inuse) ic->map[b->ino].b = 0; lruderef(&ic->blru, b);} /* * get an inode into the cache. if no inode exists for this qid, create one * from an unused qid/inode map. */Ibuf *iget(Icache *ic, Qid qid){ Imap *m, *me; Ibuf *b; /* * find map entry with same qid.path */ for(m = ic->map, me = &ic->map[ic->nino]; m < me; m++) if(m->inuse && m->qid.path==qid.path){ if(m->qid.vers != qid.vers){ /* * our info is old, forget it */ DPRINT(2, "updating old file %llud.%lud\n", qid.path, qid.vers); m->qid = qid; iupdate(ic, m - ic->map, qid); } break; } /* * if an already existing inode, just get it */ if(m != me) return iread(ic, m - ic->map); /* * create a new inode, throw out the least recently used inode * if necessary */ m = (Imap*)ic->mlru.lnext; if(m->inuse){ DPRINT(2, "superceding file %llud.%ld by %llud.%ld\n", m->qid.path, m->qid.vers, qid.path, qid.vers); if(iremove(ic, m - ic->map) < 0) return 0; } if(statson) cfsstat.ninsert++; /* * init inode and write to disk */ DPRINT(2, "new file %llud.%ld ino %ld\n", qid.path, qid.vers, m - ic->map); b = ialloc(ic, m - ic->map); b->inode.inuse = m->inuse = 1; b->inode.qid = qid; b->inode.length = 0x7fffffffffffffffLL; m->qid = qid; b->inode.ptr.bno = Notabno; iwrite(ic, b); return b;} /* * read an inode into the cache * * ASSUMPTION: the inode is valid */Ibuf*iread(Icache *ic, ulong ino){ Ibuf *b; Imap *m; ulong bno; Bbuf *bb; Dinode *bi; /* * first see if we already have it in a cache entry */ m = &ic->map[ino]; if(m->inuse && m->b){ b = m->b; goto out; } /* * read it */ b = ialloc(ic, ino); bno = ic->nab + ino/ic->i2b; bb = bcread(ic, bno); if(bb == 0){ ifree(ic, b); return 0; } bi = (Dinode*)bb->data; b->inode = bi->inode[ino % ic->i2b]; /* * consistency check */ if(bi->nino!=ic->nino || bi->magic!=Imagic){ fprint(2, "iread: inconsistent inode block\n"); ifree(ic, b); return 0; }out: b->inuse = 1; m->b = b; if(b->inode.inuse) lruref(&ic->mlru, m); lruref(&ic->blru, b); return b;} /* * write an inode back to disk */intiwrite(Icache *ic, Ibuf *b){ ulong bno; Bbuf *bb; Dinode *bi; bno = ic->nab + b->ino/ic->i2b; bb = bcread(ic, bno); if(bb == 0) return 0; bi = (Dinode*)bb->data; bi->inode[b->ino % ic->i2b] = b->inode; bcmark(ic, bb); lruref(&ic->mlru, &ic->map[b->ino]); lruref(&ic->blru, b); return 0;} /* * Forget what we know about an inode without removing it * * N.B: ordering of iwrite and dfree is important */intiupdate(Icache *ic, ulong ino, Qid qid){ Ibuf *b; Imap *m; Dptr d; if(statson) cfsstat.nupdate++; b = iread(ic, ino); if(b == 0) return -1; /* * update inode and map */ b->inode.qid = qid; b->inode.length = 0x7fffffffffffffffLL; /* Set to maximum */ m = &ic->map[ino]; m->qid = qid; /* * the free is not done if the write fails! * this is important */ d = b->inode.ptr; b->inode.ptr.bno = Notabno; if(iwrite(ic, b) < 0) return -1; dfree(ic, &d); return 0;} /* * remove an inode * * N.B: ordering of iwrite and dfree is important */intiremove(Icache *ic, ulong ino){ Ibuf *b; Imap *m; if(statson) cfsstat.ndelete++; m = &ic->map[ino]; /* * read in inode */ b = iread(ic, ino); if(b == 0) return -1; /* * mark it unused on disk */ b->inode.inuse = 0; if(iwrite(ic, b) < 0) return -1; /* * throw out it's data pages */ dfree(ic, &b->inode.ptr); /* * free the inode buffer */ ifree(ic, b); /* * make map entry least recently used */ lruderef(&ic->mlru, m); return 0;} /* * increment our version number */voidiinc(Icache *ic, Ibuf *b){ b->inode.qid.vers++; ic->map[b->ino].qid = b->inode.qid; iwrite(ic, b);}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "cformat.h"
#include "lru.h"
#include "bcache.h"
#include "disk.h"
#include "inode.h"
#include "stats.h"
/*
* read the inode blocks and make sure they
* haven't been trashed.
*
* make the in-core table of qid to inode mappings.
* N.B. this is just an array. we need a linear search to find
* a particular inode. this could be done faster.
*
* nab is the first inode block.
*/
int
iinit(Icache *ic, int f, int psize, char* name)
{
Ibuf *b;
Imap *m;
ulong ino;
Bbuf *bb;
Dinode *bi;
/*
* get basic sizes and allocation info from disk
*/
if(dinit(ic, f, psize, name) < 0)
return -1;
/*
* read first inode block to get number of inodes
*/
bb = bcread(ic, ic->nab);
if(bb == 0){
fprint(2, "iinit: can't read disk\n");
return -1;
}
bi = (Dinode*)bb->data;
if(bi->nino==0 || bi->nino>2048){
fprint(2, "iinit: bad nino\n");
return -1;
}
ic->nino = bi->nino;
/*
* set up sizing constants
*/
ic->i2b = (ic->bsize - sizeof(Dihdr))/sizeof(Inode);
ic->nib = (ic->nino + ic->i2b - 1)/ic->i2b;
/*
* allocate the in-core qid/inode map, build it's lru
*/
if(ic->map)
free(ic->map);
ic->map = malloc(sizeof(Imap)*ic->nino);
if(ic->map == 0){
fprint(2, "iinit: can't alloc map\n");
return -1;
}
lruinit(&ic->mlru);
for(m = ic->map; m < &ic->map[ic->nino]; m++){
m->inuse = 0;
m->b = 0;
lruadd(&ic->mlru, m);
}
/*
* mark all cache buffers as empty, put them on the lru list
*/
lruinit(&ic->blru);
for(b = ic->ib; b < &ic->ib[Nicache]; b++){
b->inuse = 0;
lruadd(&ic->blru, b);
}
/*
* Read all inodes and
* build the in-core qid/inode map
*/
for(ino = 0; ino < ic->nino; ino++){
b = iread(ic, ino);
if(b == 0){
fprint(2, "iinit: can't read inode %ld\n", ino);
return -1;
}
if(b->inode.inuse){
m = &ic->map[ino];
m->inuse = 1;
m->qid = b->inode.qid;
lruref(&ic->mlru, m);
}
}
return 0;
}
/*
* format the inode blocks
*/
int
iformat(Icache *ic, int f, ulong nino, char *name, int bsize, int psize)
{
int nib;
ulong bno, i2b, i;
Bbuf *bb;
Dinode *bi;
/*
* first format disk allocation
*/
if(dformat(ic, f, name, bsize, psize) < 0)
return -1;
fprint(2, "formatting inodes\n");
i2b = (bsize - sizeof(Dihdr))/sizeof(Inode);
nib = (nino + i2b - 1)/i2b;
for(bno = ic->nab; bno < ic->nab + nib; bno++){
if(dalloc(ic, 0) == Notabno){
fprint(2, "iformat: balloc failed\n");
return -1;
}
bb = bcalloc(ic, bno);
if(bb == 0){
fprint(2, "iformat: bcalloc failed\n");
return -1;
}
bi = (Dinode*)bb->data;
bi->magic = Imagic;
bi->nino = nino;
for(i = 0; i < i2b; i++)
bi->inode[i].inuse = 0;
bcmark(ic, bb);
}
bcsync(ic);
return iinit(ic, f, psize, name);
}
/*
* allocate a cache buffer, use least recently used
*/
Ibuf*
ialloc(Icache *ic, ulong ino)
{
Imap *m;
Ibuf *b;
b = (Ibuf*)ic->blru.lnext;
if(b->inuse)
ic->map[b->ino].b = 0;
b->ino = ino;
b->inuse = 1;
m = &ic->map[ino];
m->b = b;
return b;
}
/*
* free a cache buffer
*/
void
ifree(Icache *ic, Ibuf *b)
{
b->inuse = 0;
if(b->inuse)
ic->map[b->ino].b = 0;
lruderef(&ic->blru, b);
}
/*
* get an inode into the cache. if no inode exists for this qid, create one
* from an unused qid/inode map.
*/
Ibuf *
iget(Icache *ic, Qid qid)
{
Imap *m, *me;
Ibuf *b;
/*
* find map entry with same qid.path
*/
for(m = ic->map, me = &ic->map[ic->nino]; m < me; m++)
if(m->inuse && m->qid.path==qid.path){
if(m->qid.vers != qid.vers){
/*
* our info is old, forget it
*/
DPRINT(2, "updating old file %llud.%lud\n",
qid.path, qid.vers);
m->qid = qid;
iupdate(ic, m - ic->map, qid);
}
break;
}
/*
* if an already existing inode, just get it
*/
if(m != me)
return iread(ic, m - ic->map);
/*
* create a new inode, throw out the least recently used inode
* if necessary
*/
m = (Imap*)ic->mlru.lnext;
if(m->inuse){
DPRINT(2, "superceding file %llud.%ld by %llud.%ld\n",
m->qid.path, m->qid.vers, qid.path, qid.vers);
if(iremove(ic, m - ic->map) < 0)
return 0;
}
if(statson)
cfsstat.ninsert++;
/*
* init inode and write to disk
*/
DPRINT(2, "new file %llud.%ld ino %ld\n",
qid.path, qid.vers, m - ic->map);
b = ialloc(ic, m - ic->map);
b->inode.inuse = m->inuse = 1;
b->inode.qid = qid;
b->inode.length = 0x7fffffffffffffffLL;
m->qid = qid;
b->inode.ptr.bno = Notabno;
iwrite(ic, b);
return b;
}
/*
* read an inode into the cache
*
* ASSUMPTION: the inode is valid
*/
Ibuf*
iread(Icache *ic, ulong ino)
{
Ibuf *b;
Imap *m;
ulong bno;
Bbuf *bb;
Dinode *bi;
/*
* first see if we already have it in a cache entry
*/
m = &ic->map[ino];
if(m->inuse && m->b){
b = m->b;
goto out;
}
/*
* read it
*/
b = ialloc(ic, ino);
bno = ic->nab + ino/ic->i2b;
bb = bcread(ic, bno);
if(bb == 0){
ifree(ic, b);
return 0;
}
bi = (Dinode*)bb->data;
b->inode = bi->inode[ino % ic->i2b];
/*
* consistency check
*/
if(bi->nino!=ic->nino || bi->magic!=Imagic){
fprint(2, "iread: inconsistent inode block\n");
ifree(ic, b);
return 0;
}
out:
b->inuse = 1;
m->b = b;
if(b->inode.inuse)
lruref(&ic->mlru, m);
lruref(&ic->blru, b);
return b;
}
/*
* write an inode back to disk
*/
int
iwrite(Icache *ic, Ibuf *b)
{
ulong bno;
Bbuf *bb;
Dinode *bi;
bno = ic->nab + b->ino/ic->i2b;
bb = bcread(ic, bno);
if(bb == 0)
return 0;
bi = (Dinode*)bb->data;
bi->inode[b->ino % ic->i2b] = b->inode;
bcmark(ic, bb);
lruref(&ic->mlru, &ic->map[b->ino]);
lruref(&ic->blru, b);
return 0;
}
/*
* Forget what we know about an inode without removing it
*
* N.B: ordering of iwrite and dfree is important
*/
int
iupdate(Icache *ic, ulong ino, Qid qid)
{
Ibuf *b;
Imap *m;
Dptr d;
if(statson)
cfsstat.nupdate++;
b = iread(ic, ino);
if(b == 0)
return -1;
/*
* update inode and map
*/
b->inode.qid = qid;
b->inode.length = 0x7fffffffffffffffLL; /* Set to maximum */
m = &ic->map[ino];
m->qid = qid;
/*
* the free is not done if the write fails!
* this is important
*/
d = b->inode.ptr;
b->inode.ptr.bno = Notabno;
if(iwrite(ic, b) < 0)
return -1;
dfree(ic, &d);
return 0;
}
/*
* remove an inode
*
* N.B: ordering of iwrite and dfree is important
*/
int
iremove(Icache *ic, ulong ino)
{
Ibuf *b;
Imap *m;
if(statson)
cfsstat.ndelete++;
m = &ic->map[ino];
/*
* read in inode
*/
b = iread(ic, ino);
if(b == 0)
return -1;
/*
* mark it unused on disk
*/
b->inode.inuse = 0;
if(iwrite(ic, b) < 0)
return -1;
/*
* throw out it's data pages
*/
dfree(ic, &b->inode.ptr);
/*
* free the inode buffer
*/
ifree(ic, b);
/*
* make map entry least recently used
*/
lruderef(&ic->mlru, m);
return 0;
}
/*
* increment our version number
*/
void
iinc(Icache *ic, Ibuf *b)
{
b->inode.qid.vers++;
ic->map[b->ino].qid = b->inode.qid;
iwrite(ic, b);
}