ref: 0906df260dba0a482190c91103cb3041baf704fc
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 checkdentry(u64 blkno, u8 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/Blocksize); checkdentry(Bdfrees, Tdentry, Qpfrees); initextents(&frees, "frees", nil); getfrees(Bdfrees); showextents(1, "", &frees); // showblocknos(1, &frees); close(devfd); exits(0); } int checkvalid(u64 blkno, u8 dtag, u64 dpath, u8 tag, u64 qpath, u16 len) { if(dtag != tag || dpath != qpath){ /* if(chatty9p) */ fprint(2, "check invalid %llud tag/path expected %s/%llud actual %s/%llud\n", blkno, tagnames[tag], qpath, tagnames[dtag], dpath); fprint(2, "free: %llud\n", blkno); return 0; } if(chatty9p) print("%llud %d\n", blkno, len); return 1; } int checkdentry(u64 blkno, u8 tag, u64 qpath) { u8 buf[Metadatablocksize]; Dentry *t; devread(blkno, buf, Metadataunits); t = (Dentry*)buf; return checkvalid(blkno, t->tag, t->path, tag, qpath, Metadataunits); } void loadfreeextents(u64 blkno) { s8 *buf; buf = emalloc(Maxdatablocksize); devread(blkno, buf, 1); devread(blkno, buf, ((Data*)buf)->len); loadextents(&frees, buf, ((Data*)buf)->len*Blocksize); free(buf); } void walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath) { u8 buf[Metadatablocksize]; Indirect *t; u64 cblkno; int i; devread(blkno, buf, Metadataunits); t = (Indirect*)buf; if(checkvalid(blkno, t->tagi, t->path, tag, qpath, Metadataunits)){ if(t->tagi == Tind0){ for(i = 0; i<Nindperblock; i++){ cblkno = t->bufa[i]; if(cblkno == 0) return; loadfreeextents(cblkno); } }else{ for(i = 0; i<Nindperblock; i++){ cblkno = t->bufa[i]; if(cblkno == 0) return; /* check tag */ walkindir(cblkno, tag-1, bottomtag, qpath); } } } } void getfrees(u64 dblkno) { u64 size; u8 buf[Metadatablocksize]; Dentry *d; u64 cblkno; int i; devread(dblkno, buf, Metadataunits); recentmetadata(buf, &d, nil); size = d->size; if(size == 0) return; if(d->size <= Ddatasize){ loadextents(&frees, d->buf, d->size); return; } if(checkvalid(dblkno, d->tag, d->path, Tdentry, Qpfrees, Metadataunits)){ for(i = 0; i<Ndblock; i++){ cblkno = d->dblocks[i]; if(cblkno == 0) return; loadfreeextents(cblkno); } for(i = Tind0; i<Niblock+Tind0; i++){ cblkno = d->iblocks[i]; if(cblkno == 0) return; walkindir(cblkno, i, Tdata, Qpfrees); } } }