ref: 5c21eca829380c28769f79beabb7cc51f1787f97
dir: /free.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "fns.h" #include "extents.h" /* go through the contents of Bfrees and write out the list of free blocks used by reconcile.c to identify discrepancies */ Extents frees; int chatty9p = 0; char *devfile = nil; void walkdentry(u64 blkno); int checkblock(u64 blkno, s16 tag, u64 qpath); void getfrees(u64 dblkno); static void usage(void) { fprint(2, "usage: free [-D ] fsfile\n"); exits("usage"); } void main(int argc, char *argv[]) { u64 size; ARGBEGIN{ default: usage(); case 'D': chatty9p++; break; }ARGEND if(argc != 1) usage(); devfile = argv[0]; if(devfile == nil) sysfatal("no disk file"); if (access(devfile, AREAD) == -1) sysfatal("%s cannot access device", devfile); size = devinit(devfile); if(size == 0) panic("null size %s", devfile); if(chatty9p) print("%s %llud bytes %llud blocks\n", devfile, size, size/Rawblocksize); checkblock(Bdfrees, Tdentry, Qpfrees); getfrees(Bdfrees); // showextents("after getfrees", &frees); showblocknos(&frees); exits(0); } int checkvalid(u64 blkno, Tag *t, s16 tag, u64 qpath) { if(t->type != tag || t->path != qpath){ /* if(chatty9p) */ fprint(2, "check invalid %llud tag/path expected %s/%llud actual %s/%llud\n", blkno, tagnames[tag], qpath, tagnames[t->type], t->path); fprint(2, "free: %llud\n", blkno); return 0; } if(chatty9p) print("%llud\n", blkno); return 1; } int checkblock(u64 blkno, s16 tag, u64 qpath) { u8 buf[Rawblocksize]; Tag *t; devread(blkno, buf, 1); t = (Tag*)buf; return checkvalid(blkno, t, tag, qpath); } void loadfreeextents(u64 blkno, u16 len) { s8 *buf; buf = emalloc(len*Rawblocksize); devread(blkno, buf, len); loadextents(&frees, buf+sizeof(Tag), (len*Rawblocksize)-sizeof(Tag)); free(buf); } void walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath) { u8 buf[Rawblocksize], cbuf[Rawblocksize]; Tag *t; u64 cblkno, *bufa; Spanid *s; u16 len; int i; devread(blkno, buf, 1); t = (Tag*)buf; if(checkvalid(blkno, t, tag, qpath)){ if(t->type == Tind0){ s = (Spanid*)(buf+sizeof(Tag)); for(i = 0; i<Nspanidperblock; i++){ cblkno = s[i].blkno; len = s[i].len; if(cblkno == 0) return; loadfreeextents(cblkno, len); } }else{ bufa = (u64*)(buf+sizeof(Tag)); for(i = 0; i<Nindperblock; i++){ cblkno = bufa[i]; if(cblkno == 0) return; devread(cblkno, cbuf, 1); /* check tag */ walkindir(cblkno, tag-1, bottomtag, qpath); } } } } void getfrees(u64 dblkno) { u64 size; u8 buf[Rawblocksize], cbuf[Rawblocksize]; Dentry *d; Tag *t; u64 cblkno; int i; u16 len; devread(dblkno, buf, 1); t = (Tag*)buf; d = (Dentry*)(buf+sizeof(Tag)); size = d->size; if(size == 0) panic("loadfreeextents size == 0"); if(checkvalid(dblkno, t, Tdentry, d->qid.path)){ for(i = 0; i<Ndspanid; i++){ cblkno = d->dspans[i].blkno; len = d->dspans[i].len; if(cblkno == 0) return; loadfreeextents(cblkno, len); } for(i = Tind0; i<Niblock+Tind0; i++){ cblkno = d->iblocks[i]; if(cblkno == 0) return; devread(cblkno, cbuf, 1); walkindir(cblkno, i, Tdata, Qpfrees); } } }