123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- #include <u.h>
- #include <libc.h>
- #include "cformat.h"
- #include "lru.h"
- #include "bcache.h"
- #include "disk.h"
- int icformat(Disk*, ulong);
- /*
- * read in the disk structures, return -1 if the format
- * is inconsistent.
- */
- int
- dinit(Disk *d, int f, int psize)
- {
- Dir *dir;
- char buf[1024];
- Dalloc *ba;
- uvlong length;
- ulong i;
- Bbuf *b;
- /*
- * get disk size
- */
- dir = dirfstat(f);
- if(dir == nil){
- perror("dinit: stat");
- return -1;
- }
- length = dir->length;
- free(dir);
- /*
- * read first physical block to get logical block size, number of inodes,
- * and number of allocation blocks
- */
- if(seek(f, 0, 0) < 0){
- perror("dinit: seek");
- return -1;
- }
- if(read(f, buf, sizeof(buf)) != sizeof(buf)){
- perror("dinit: read");
- return -1;
- }
- ba = (Dalloc*)buf;
- if(ba->bsize <= 0){
- fprint(2, "dinit: bsize 0x%lux<= 0\n", ba->bsize);
- return -1;
- }
- if((ba->bsize % psize) != 0){
- fprint(2, "dinit: logical bsize (%lud) not multiple of physical (%ud)\n",
- ba->bsize, psize);
- return -1;
- }
- d->bsize = ba->bsize;
- d->nb = length/d->bsize;
- d->b2b = (d->bsize - sizeof(Dahdr))*8;
- d->nab = (d->nb+d->b2b-1)/d->b2b;
- d->p2b = d->bsize/sizeof(Dptr);
- strncpy(d->name, ba->name, sizeof(d->name));
- /*
- * check allocation blocks for consistency
- */
- if(bcinit(d, f, d->bsize) < 0){
- fprint(2, "dinit: couldn't init block cache\n");
- return -1;
- }
- for(i = 0; i < d->nab; i++){
- b = bcread(d, i);
- if(b == 0){
- perror("dinit: read");
- return -1;
- }
- ba = (Dalloc*)b->data;
- if(ba->magic != Amagic){
- fprint(2, "dinit: bad magic in alloc block %uld\n", i);
- return -1;
- }
- if(d->bsize != ba->bsize){
- fprint(2, "dinit: bad bsize in alloc block %uld\n", i);
- return -1;
- }
- if(d->nab != ba->nab){
- fprint(2, "dinit: bad nab in alloc block %uld\n", i);
- return -1;
- }
- if(strncmp(d->name, ba->name, sizeof(d->name))){
- fprint(2, "dinit: bad name in alloc block %uld\n", i);
- return -1;
- }
- }
- return 0;
- }
- /*
- * format the disk as a cache
- */
- int
- dformat(Disk *d, int f, char *name, ulong bsize, ulong psize)
- {
- int i;
- Dir *dir;
- uvlong length;
- Bbuf *b;
- Dalloc *ba;
- Dptr dptr;
- fprint(2, "formatting disk\n");
- /*
- * calculate basic numbers
- */
- dir = dirfstat(f);
- if(dir == nil)
- return -1;
- length = dir->length;
- d->bsize = bsize;
- if((d->bsize % psize) != 0){
- fprint(2, "cfs: logical bsize not multiple of physical\n");
- return -1;
- }
- d->nb = length/d->bsize;
- d->b2b = (d->bsize - sizeof(Dahdr))*8;
- d->nab = (d->nb+d->b2b-1)/d->b2b;
- d->p2b = d->bsize/sizeof(Dptr);
- /*
- * init allocation blocks
- */
- if(bcinit(d, f, d->bsize) < 0)
- return -1;
- for(i = 0; i < d->nab; i++){
- b = bcalloc(d, i);
- if(b == 0){
- perror("cfs: bcalloc");
- return -1;
- }
- memset(b->data, 0, d->bsize);
- ba = (Dalloc*)b->data;
- ba->magic = Amagic;
- ba->bsize = d->bsize;
- ba->nab = d->nab;
- strncpy(ba->name, name, sizeof(ba->name));
- bcmark(d, b);
- }
- /*
- * allocate allocation blocks
- */
- for(i = 0; i < d->nab; i++)
- if(dalloc(d, &dptr) == Notabno){
- fprint(2, "can't allocate allocation blocks\n");
- return -1;
- }
- return bcsync(d);
- }
- /*
- * allocate a block from a bit vector page
- *
- * a return value of Notabno means no blocks left
- */
- static ulong
- _balloc(Dalloc *ba, ulong max)
- {
- ulong *p;
- ulong *e;
- ulong i; /* bit position in long */
- ulong m; /* 1<<i */
- ulong v; /* old value of long */
- int len; /* number of valid words */
- /*
- * find a word with a 0 bit
- */
- len = (max+BtoUL-1)/BtoUL;
- for(p = ba->bits, e = p + len; p < e; p++)
- if(*p != 0xFFFFFFFF)
- break;
- if(p == e)
- return Notabno;
- /*
- * find the first 0 bit
- */
- v = *p;
- for(m = 1, i = 0; i<BtoUL; i++, m<<=1)
- if((m|v) != v)
- break;
- /*
- * calculate block number
- */
- i += (p - ba->bits)*BtoUL;
- if(i >= max)
- return Notabno;
- /*
- * set bit to 1
- */
- *p = v | m;
- return i;
- }
- /*
- * allocate a block
- *
- * return Notabno if none left
- */
- ulong
- dalloc(Disk *d, Dptr *p)
- {
- ulong bno;
- Bbuf *b;
- Dalloc *ba;
- ulong rv;
- ulong max;
- max = d->nb;
- for(bno = 0; bno < d->nab; bno++){
- b = bcread(d, bno);
- ba = (Dalloc*)b->data;
- rv = _balloc(ba, max > d->b2b ? d->b2b : max);
- if(rv != Notabno){
- rv = bno*d->b2b + rv;
- if(p){
- p->start = p->end = 0;
- p->bno = rv;
- }
- bcmark(d, b);
- return rv;
- }
- max -= d->b2b;
- }
- if(p)
- p->bno = Notabno;
- return Notabno;
- }
- /*
- * allocate a block of pointers
- */
- ulong
- dpalloc(Disk *d, Dptr *p)
- {
- Bbuf *b;
- Dptr *sp;
- Dptr *ep;
- if(dalloc(d, p) == Notabno)
- return Notabno;
- /*
- * allocate the page and invalidate all the
- * pointers
- */
- b = bcalloc(d, p->bno);
- if(b == 0)
- return -1;
- sp = (Dptr*)b->data;
- for(ep = sp + d->p2b; sp < ep; sp++){
- sp->bno = Notabno;
- sp->start = sp->end = 0;
- }
- p->bno |= Indbno;
- p->start = 0;
- p->end = d->bsize;
- /*
- * mark the page as dirty
- */
- bcmark(d, b);
- return 0;
- }
- /*
- * free a block
- */
- int
- _bfree(Disk *d, ulong i)
- {
- ulong *p;
- ulong m;
- Bbuf *b;
- Dalloc *ba;
- ulong bno;
- /*
- * get correct allocation block
- */
- bno = i/d->b2b;
- if(bno >= d->nab)
- return -1;
- b = bcread(d, bno);
- if(b == 0)
- return -1;
- ba = (Dalloc*)b->data;
- /*
- * change bit
- */
- i -= bno*d->b2b;
- p = ba->bits + (i/BtoUL);
- m = 1<<(i%BtoUL);
- *p &= ~m;
- bcmark(d, b);
- return 0;
- }
- /*
- * free a block (or blocks)
- */
- int
- dfree(Disk *d, Dptr *dp)
- {
- Dptr *sp;
- Dptr *ep;
- Bbuf *b;
- ulong bno;
- bno = dp->bno;
- dp->bno = Notabno;
- /*
- * nothing to free
- */
- if(bno == Notabno)
- return 0;
- /*
- * direct pointer
- */
- if((bno & Indbno) == 0)
- return _bfree(d, bno);
- /*
- * first indirect page
- */
- bno &= ~Indbno;
- _bfree(d, bno);
- /*
- * then all the pages it points to
- *
- * DANGER: this algorithm may fail is their are more
- * allocation blocks than block buffers
- */
- b = bcread(d, bno);
- if(b == 0)
- return -1;
- sp = (Dptr*)b->data;
- for(ep = sp + d->p2b; sp < ep; sp++)
- if(dfree(d, sp) < 0)
- return -1;
- return 0;
- }
|