📄 check.c
字号:
#include "stdinc.h"#include "dat.h"#include "fns.h"static void error(Fsck*, char*, ...);static void setBit(uchar*, u32int);static int getBit(uchar*, u32int);static int walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize], int type, u32int tag, u32int epoch);static void warn(Fsck*, char*, ...);static void checkLeak(Fsck*);static void clrenop(Fsck*, Block*, int);static void closenop(Fsck*, Block*, u32int);static void clrinop(Fsck*, char*, MetaBlock*, int, Block*);static int printnop(char*, ...);static void checkEpochs(Fsck*);static void checkDirs(Fsck*);#pragma varargck argpos error 2#pragma varargck argpos warn 2static Fsck*checkInit(Fsck *chk){ chk->cache = chk->fs->cache; chk->nblocks = cacheLocalSize(chk->cache, PartData);; chk->bsize = chk->fs->blockSize; chk->walkdepth = 0; chk->hint = 0; chk->quantum = chk->nblocks/100; if(chk->quantum == 0) chk->quantum = 1; if(chk->print == nil) chk->print = printnop; if(chk->clre == nil) chk->clre = clrenop; if(chk->close == nil) chk->close = closenop; if(chk->clri == nil) chk->clri = clrinop; return chk;}/* * BUG: Should merge checkEpochs and checkDirs so that * bad blocks are only reported once, and so that errors in checkEpochs * can have the affected file names attached, and so that the file system * is only read once. * * Also should summarize the errors instead of printing for every one * (e.g., XXX bad or unreachable blocks in /active/usr/rsc/foo). */voidfsCheck(Fsck *chk){ Block *b; Super super; checkInit(chk); b = superGet(chk->cache, &super); if(b == nil){ chk->print("could not load super block: %R"); return; } blockPut(b); chk->hint = super.active; checkEpochs(chk); chk->smap = vtMemAllocZ(chk->nblocks/8+1); checkDirs(chk); vtMemFree(chk->smap);}static void checkEpoch(Fsck*, u32int);/* * Walk through all the blocks in the write buffer. * Then we can look for ones we missed -- those are leaks. */static voidcheckEpochs(Fsck *chk){ u32int e; uint nb; nb = chk->nblocks; chk->amap = vtMemAllocZ(nb/8+1); chk->emap = vtMemAllocZ(nb/8+1); chk->xmap = vtMemAllocZ(nb/8+1); chk->errmap = vtMemAllocZ(nb/8+1); for(e=chk->fs->ehi; e >= chk->fs->elo; e--){ memset(chk->emap, 0, chk->nblocks/8+1); memset(chk->xmap, 0, chk->nblocks/8+1); checkEpoch(chk, e); } checkLeak(chk); vtMemFree(chk->amap); vtMemFree(chk->emap); vtMemFree(chk->xmap); vtMemFree(chk->errmap);}static voidcheckEpoch(Fsck *chk, u32int epoch){ u32int a; Block *b; Entry e; Label l; chk->print("checking epoch %ud...\n", epoch); for(a=0; a<chk->nblocks; a++){ if(!readLabel(chk->cache, &l, (a+chk->hint)%chk->nblocks)){ error(chk, "could not read label for addr %.8#ux", a); continue; } if(l.tag == RootTag && l.epoch == epoch) break; } if(a == chk->nblocks){ chk->print("could not find root block for epoch %ud", epoch); return; } a = (a+chk->hint)%chk->nblocks; b = cacheLocalData(chk->cache, a, BtDir, RootTag, OReadOnly, 0); if(b == nil){ error(chk, "could not read root block %.8#ux: %R", a); return; } /* no one should point at root blocks */ setBit(chk->amap, a); setBit(chk->emap, a); setBit(chk->xmap, a); /* * First entry is the rest of the file system. * Second entry is link to previous epoch root, * just a convenience to help the search. */ if(!entryUnpack(&e, b->data, 0)){ error(chk, "could not unpack root block %.8#ux: %R", a); blockPut(b); return; } walkEpoch(chk, b, e.score, BtDir, e.tag, epoch); if(entryUnpack(&e, b->data, 1)) chk->hint = globalToLocal(e.score); blockPut(b);}/* * When b points at bb, need to check: * * (i) b.e in [bb.e, bb.eClose) * (ii) if b.e==bb.e, then no other b' in e points at bb. * (iii) if !(b.state&Copied) and b.e==bb.e then no other b' points at bb. * (iv) if b is active then no other active b' points at bb. * (v) if b is a past life of b' then only one of b and b' is active (too hard to check) */static intwalkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize], int type, u32int tag, u32int epoch){ int i, ret; u32int addr, ep; Block *bb; Entry e; if(b && chk->walkdepth == 0 && chk->printblocks) chk->print("%V %d %#.8ux %#.8ux\n", b->score, b->l.type, b->l.tag, b->l.epoch); if(!chk->useventi && globalToLocal(score) == NilBlock) return 1; chk->walkdepth++; bb = cacheGlobal(chk->cache, score, type, tag, OReadOnly); if(bb == nil){ error(chk, "could not load block %V type %d tag %ux: %R", score, type, tag); chk->walkdepth--; return 0; } if(chk->printblocks) chk->print("%*s%V %d %#.8ux %#.8ux\n", chk->walkdepth*2, "", score, type, tag, bb->l.epoch); ret = 0; addr = globalToLocal(score); if(addr == NilBlock){ ret = 1; goto Exit; } if(b){ /* (i) */ if(b->l.epoch < bb->l.epoch || bb->l.epochClose <= b->l.epoch){ error(chk, "walk: block %#ux [%ud, %ud) points at %#ux [%ud, %ud)", b->addr, b->l.epoch, b->l.epochClose, bb->addr, bb->l.epoch, bb->l.epochClose); goto Exit; } /* (ii) */ if(b->l.epoch == epoch && bb->l.epoch == epoch){ if(getBit(chk->emap, addr)){ error(chk, "walk: epoch join detected: addr %#ux %L", bb->addr, &bb->l); goto Exit; } setBit(chk->emap, addr); } /* (iii) */ if(!(b->l.state&BsCopied) && b->l.epoch == bb->l.epoch){ if(getBit(chk->xmap, addr)){ error(chk, "walk: copy join detected; addr %#ux %L", bb->addr, &bb->l); goto Exit; } setBit(chk->xmap, addr); } } /* (iv) */ if(epoch == chk->fs->ehi){ /* since epoch==fs->ehi is first, amap is same as ``have seen active'' */ if(getBit(chk->amap, addr)){ error(chk, "walk: active join detected: addr %#ux %L", bb->addr, &bb->l); goto Exit; } if(bb->l.state&BsClosed) error(chk, "walk: addr %#ux: block is in active tree but is closed", addr); }else{ if(!getBit(chk->amap, addr)){ if(!(bb->l.state&BsClosed)){ // error(chk, "walk: addr %#ux: block is not in active tree, not closed (%d)", addr, bb->l.epochClose); chk->close(chk, bb, epoch+1); chk->nclose++; } } } if(getBit(chk->amap, addr)){ ret = 1; goto Exit; } setBit(chk->amap, addr); if(chk->nseen++%chk->quantum == 0) chk->print("check: visited %d/%d blocks (%.0f%%)\n", chk->nseen, chk->nblocks, chk->nseen*100./chk->nblocks); b = nil; /* make sure no more refs to parent */ USED(b); switch(type){ default: /* pointer block */ for(i=0; i<chk->bsize/VtScoreSize; i++) if(!walkEpoch(chk, bb, bb->data + i*VtScoreSize, type-1, tag, epoch)){ setBit(chk->errmap, bb->addr); chk->clrp(chk, bb, i); chk->nclrp++; } break; case BtData: break; case BtDir: for(i=0; i<chk->bsize/VtEntrySize; i++){ if(!entryUnpack(&e, bb->data, i)){ // error(chk, "walk: could not unpack entry: %ux[%d]: %R", addr, i); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } if(!(e.flags & VtEntryActive)) continue;//fprint(2, "%x[%d] tag=%x snap=%d score=%V\n", addr, i, e.tag, e.snap, e.score); ep = epoch; if(e.snap != 0){ if(e.snap >= epoch){ // error(chk, "bad snap in entry: %ux[%d] snap = %ud: epoch = %ud", // addr, i, e.snap, epoch); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } continue; } if(e.flags & VtEntryLocal){ if(e.tag < UserTag) if(e.tag != RootTag || tag != RootTag || i != 1){ // error(chk, "bad tag in entry: %ux[%d] tag = %ux", addr, i, e.tag); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } }else{ if(e.tag != 0){ // error(chk, "bad tag in entry: %ux[%d] tag = %ux", addr, i, e.tag); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } } if(!walkEpoch(chk, bb, e.score, entryType(&e), e.tag, ep)){ setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; } } break; } ret = 1;Exit: chk->walkdepth--; blockPut(bb); return ret;}/* * We've just walked the whole write buffer. Notice blocks that * aren't marked available but that we didn't visit. They are lost. */static voidcheckLeak(Fsck *chk){ u32int a; Label l; u32int nfree; u32int nlost; Block *b; nfree = 0; nlost = 0; for(a=0; a<chk->nblocks; a++){ if(!readLabel(chk->cache, &l, a)){ error(chk, "could not read label: addr %ux %d %d: %R", a, l.type, l.state); continue; } if(getBit(chk->amap, a)) continue; if(l.state == BsFree || l.epochClose <= chk->fs->elo || l.epochClose == l.epoch){ nfree++; setBit(chk->amap, a); continue; } if(l.state&BsClosed) continue; nlost++; // warn(chk, "unreachable block: addr %ux type %d tag %ux state %s epoch %ud close %ud", // a, l.type, l.tag, bsStr(l.state), l.epoch, l.epochClose); b = cacheLocal(chk->cache, PartData, a, OReadOnly); if(b == nil){ error(chk, "could not read block %#.8ux", a); continue; } chk->close(chk, b, 0); chk->nclose++; setBit(chk->amap, a); blockPut(b); } chk->print("fsys blocks: total=%ud used=%ud(%.1f%%) free=%ud(%.1f%%) lost=%ud(%.1f%%)\n", chk->nblocks, chk->nblocks-nfree-nlost, 100.*(chk->nblocks-nfree-nlost)/chk->nblocks, nfree, 100.*nfree/chk->nblocks, nlost, 100.*nlost/chk->nblocks);}/* * Check that all sources in the tree are accessible. */static Source *openSource(Fsck *chk, Source *s, char *name, uchar *bm, u32int offset, u32int gen, int dir, MetaBlock *mb, int i, Block *b){ Source *r;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -