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/cfs/disk.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cfs/disk.c')
-rwxr-xr-x | sys/src/cmd/cfs/disk.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/sys/src/cmd/cfs/disk.c b/sys/src/cmd/cfs/disk.c new file mode 100755 index 000000000..2a39271eb --- /dev/null +++ b/sys/src/cmd/cfs/disk.c @@ -0,0 +1,361 @@ +#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, char *expname) +{ + ulong i; + uvlong length; + char buf[1024]; + Bbuf *b; + Dalloc *ba; + Dir *dir; + + /* + * 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, # of inodes, + * and # 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); + + if (expname != nil && strncmp(d->name, expname, sizeof d->name) != 0) { + /* Mismatch with recorded name; fail here to force a format */ + fprint(2, "cfs: name mismatch\n"); + return -1; + } + + /* + * 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; + uvlong length; + Bbuf *b; + Dalloc *ba; + Dir *dir; + 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) +{ + int len; /* number of valid words */ + ulong i; /* bit position in long */ + ulong m; /* 1<<i */ + ulong v; /* old value of long */ + ulong *p, *e; + + /* + * 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, max, rv; + Bbuf *b; + Dalloc *ba; + + 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, *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 bno, m; + ulong *p; + Bbuf *b; + Dalloc *ba; + + /* + * 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) +{ + ulong bno; + Dptr *sp, *ep; + Bbuf *b; + + 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 if there 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; +} |