123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799 |
- #include "stdinc.h"
- #include "dat.h"
- #include "fns.h"
- static void checkDirs(Fsck*);
- static void checkEpochs(Fsck*);
- static void checkLeak(Fsck*);
- static void closenop(Fsck*, Block*, u32int);
- static void clrenop(Fsck*, Block*, int);
- static void clrinop(Fsck*, char*, MetaBlock*, int, Block*);
- static void error(Fsck*, char*, ...);
- static int getBit(uchar*, u32int);
- static int printnop(char*, ...);
- static void setBit(uchar*, u32int);
- static int walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize],
- int type, u32int tag, u32int epoch);
- static void warn(Fsck*, char*, ...);
- #pragma varargck argpos error 2
- #pragma varargck argpos printnop 1
- #pragma varargck argpos warn 2
- static 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).
- */
- void
- fsCheck(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 void
- checkEpochs(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 void
- checkEpoch(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 0x%.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 0x%.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 0x%.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 int
- walkEpoch(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;
- if(0) 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 void
- checkLeak(Fsck *chk)
- {
- u32int a, nfree, nlost;
- Block *b;
- Label l;
- nfree = 0;
- nlost = 0;
- for(a = 0; a < chk->nblocks; a++){
- if(!readLabel(chk->cache, &l, a)){
- error(chk, "could not read label: addr 0x%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 0x%ux type %d tag 0x%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 0x%#.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;
- r = nil;
- if(getBit(bm, offset)){
- warn(chk, "multiple references to source: %s -> %d",
- name, offset);
- goto Err;
- }
- setBit(bm, offset);
- r = sourceOpen(s, offset, OReadOnly, 0);
- if(r == nil){
- warn(chk, "could not open source: %s -> %d: %R", name, offset);
- goto Err;
- }
- if(r->gen != gen){
- warn(chk, "source has been removed: %s -> %d", name, offset);
- goto Err;
- }
- if(r->dir != dir){
- warn(chk, "dir mismatch: %s -> %d", name, offset);
- goto Err;
- }
- return r;
- Err:
- chk->clri(chk, name, mb, i, b);
- chk->nclri++;
- if(r)
- sourceClose(r);
- return nil;
- }
- typedef struct MetaChunk MetaChunk;
- struct MetaChunk {
- ushort offset;
- ushort size;
- ushort index;
- };
- static int
- offsetCmp(void *s0, void *s1)
- {
- MetaChunk *mc0, *mc1;
- mc0 = s0;
- mc1 = s1;
- if(mc0->offset < mc1->offset)
- return -1;
- if(mc0->offset > mc1->offset)
- return 1;
- return 0;
- }
- /*
- * Fsck that MetaBlock has reasonable header, sorted entries,
- */
- static int
- chkMetaBlock(MetaBlock *mb)
- {
- MetaChunk *mc;
- int oo, o, n, i;
- uchar *p;
- mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
- p = mb->buf + MetaHeaderSize;
- for(i = 0; i < mb->nindex; i++){
- mc[i].offset = p[0]<<8 | p[1];
- mc[i].size = p[2]<<8 | p[3];
- mc[i].index = i;
- p += MetaIndexSize;
- }
- qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
- /* check block looks ok */
- oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
- o = oo;
- n = 0;
- for(i = 0; i < mb->nindex; i++){
- o = mc[i].offset;
- n = mc[i].size;
- if(o < oo)
- goto Err;
- oo += n;
- }
- if(o+n > mb->size || mb->size - oo != mb->free)
- goto Err;
- vtMemFree(mc);
- return 1;
- Err:
- if(0){
- fprint(2, "metaChunks failed!\n");
- oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
- for(i=0; i<mb->nindex; i++){
- fprint(2, "\t%d: %d %d\n", i, mc[i].offset,
- mc[i].offset + mc[i].size);
- oo += mc[i].size;
- }
- fprint(2, "\tused=%d size=%d free=%d free2=%d\n",
- oo, mb->size, mb->free, mb->size - oo);
- }
- vtMemFree(mc);
- return 0;
- }
- static void
- scanSource(Fsck *chk, char *name, Source *r)
- {
- u32int a, nb, o;
- Block *b;
- Entry e;
- if(!chk->useventi && globalToLocal(r->score)==NilBlock)
- return;
- if(!sourceGetEntry(r, &e)){
- error(chk, "could not get entry for %s", name);
- return;
- }
- a = globalToLocal(e.score);
- if(!chk->useventi && a==NilBlock)
- return;
- if(getBit(chk->smap, a))
- return;
- setBit(chk->smap, a);
- nb = (sourceGetSize(r) + r->dsize-1) / r->dsize;
- for(o = 0; o < nb; o++){
- b = sourceBlock(r, o, OReadOnly);
- if(b == nil){
- error(chk, "could not read block in data file %s", name);
- continue;
- }
- if(b->addr != NilBlock && getBit(chk->errmap, b->addr)){
- warn(chk, "previously reported error in block %ux is in file %s",
- b->addr, name);
- }
- blockPut(b);
- }
- }
- /*
- * Walk the source tree making sure that the BtData
- * sources containing directory entries are okay.
- */
- static void
- chkDir(Fsck *chk, char *name, Source *source, Source *meta)
- {
- int i;
- u32int a1, a2, nb, o;
- char *s, *nn;
- uchar *bm;
- Block *b, *bb;
- DirEntry de;
- Entry e1, e2;
- MetaBlock mb;
- MetaEntry me;
- Source *r, *mr;
- if(!chk->useventi && globalToLocal(source->score)==NilBlock &&
- globalToLocal(meta->score)==NilBlock)
- return;
- if(!sourceLock2(source, meta, OReadOnly)){
- warn(chk, "could not lock sources for %s: %R", name);
- return;
- }
- if(!sourceGetEntry(source, &e1) || !sourceGetEntry(meta, &e2)){
- warn(chk, "could not load entries for %s: %R", name);
- return;
- }
- a1 = globalToLocal(e1.score);
- a2 = globalToLocal(e2.score);
- if((!chk->useventi && a1==NilBlock && a2==NilBlock)
- || (getBit(chk->smap, a1) && getBit(chk->smap, a2))){
- sourceUnlock(source);
- sourceUnlock(meta);
- return;
- }
- setBit(chk->smap, a1);
- setBit(chk->smap, a2);
- bm = vtMemAllocZ(sourceGetDirSize(source)/8 + 1);
- nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize;
- for(o = 0; o < nb; o++){
- b = sourceBlock(meta, o, OReadOnly);
- if(b == nil){
- error(chk, "could not read block in meta file: %s[%ud]: %R",
- name, o);
- continue;
- }
- if(0) fprint(2, "source %V:%d block %d addr %d\n", source->score,
- source->offset, o, b->addr);
- if(b->addr != NilBlock && getBit(chk->errmap, b->addr))
- warn(chk, "previously reported error in block %ux is in %s",
- b->addr, name);
- if(!mbUnpack(&mb, b->data, meta->dsize)){
- error(chk, "could not unpack meta block: %s[%ud]: %R",
- name, o);
- blockPut(b);
- continue;
- }
- if(!chkMetaBlock(&mb)){
- error(chk, "bad meta block: %s[%ud]: %R", name, o);
- blockPut(b);
- continue;
- }
- s = nil;
- for(i=mb.nindex-1; i>=0; i--){
- meUnpack(&me, &mb, i);
- if(!deUnpack(&de, &me)){
- error(chk,
- "could not unpack dir entry: %s[%ud][%d]: %R",
- name, o, i);
- continue;
- }
- if(s && strcmp(s, de.elem) <= 0)
- error(chk,
- "dir entry out of order: %s[%ud][%d] = %s last = %s",
- name, o, i, de.elem, s);
- vtMemFree(s);
- s = vtStrDup(de.elem);
- nn = smprint("%s/%s", name, de.elem);
- if(nn == nil){
- error(chk, "out of memory");
- continue;
- }
- if(chk->printdirs)
- if(de.mode&ModeDir)
- chk->print("%s/\n", nn);
- if(chk->printfiles)
- if(!(de.mode&ModeDir))
- chk->print("%s\n", nn);
- if(!(de.mode & ModeDir)){
- r = openSource(chk, source, nn, bm, de.entry,
- de.gen, 0, &mb, i, b);
- if(r != nil){
- if(sourceLock(r, OReadOnly)){
- scanSource(chk, nn, r);
- sourceUnlock(r);
- }
- sourceClose(r);
- }
- deCleanup(&de);
- free(nn);
- continue;
- }
- r = openSource(chk, source, nn, bm, de.entry,
- de.gen, 1, &mb, i, b);
- if(r == nil){
- deCleanup(&de);
- free(nn);
- continue;
- }
- mr = openSource(chk, source, nn, bm, de.mentry,
- de.mgen, 0, &mb, i, b);
- if(mr == nil){
- sourceClose(r);
- deCleanup(&de);
- free(nn);
- continue;
- }
- if(!(de.mode&ModeSnapshot) || chk->walksnapshots)
- chkDir(chk, nn, r, mr);
- sourceClose(mr);
- sourceClose(r);
- deCleanup(&de);
- free(nn);
- deCleanup(&de);
- }
- vtMemFree(s);
- blockPut(b);
- }
- nb = sourceGetDirSize(source);
- for(o=0; o<nb; o++){
- if(getBit(bm, o))
- continue;
- r = sourceOpen(source, o, OReadOnly, 0);
- if(r == nil)
- continue;
- warn(chk, "non referenced entry in source %s[%d]", name, o);
- if((bb = sourceBlock(source, o/(source->dsize/VtEntrySize),
- OReadOnly)) != nil){
- if(bb->addr != NilBlock){
- setBit(chk->errmap, bb->addr);
- chk->clre(chk, bb, o%(source->dsize/VtEntrySize));
- chk->nclre++;
- }
- blockPut(bb);
- }
- sourceClose(r);
- }
- sourceUnlock(source);
- sourceUnlock(meta);
- vtMemFree(bm);
- }
- static void
- checkDirs(Fsck *chk)
- {
- Source *r, *mr;
- sourceLock(chk->fs->source, OReadOnly);
- r = sourceOpen(chk->fs->source, 0, OReadOnly, 0);
- mr = sourceOpen(chk->fs->source, 1, OReadOnly, 0);
- sourceUnlock(chk->fs->source);
- chkDir(chk, "", r, mr);
- sourceClose(r);
- sourceClose(mr);
- }
- static void
- setBit(uchar *bmap, u32int addr)
- {
- if(addr == NilBlock)
- return;
- bmap[addr>>3] |= 1 << (addr & 7);
- }
- static int
- getBit(uchar *bmap, u32int addr)
- {
- if(addr == NilBlock)
- return 0;
- return (bmap[addr>>3] >> (addr & 7)) & 1;
- }
- static void
- error(Fsck *chk, char *fmt, ...)
- {
- char buf[256];
- va_list arg;
- static int nerr;
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof buf, fmt, arg);
- va_end(arg);
- chk->print("error: %s\n", buf);
- // if(nerr++ > 20)
- // vtFatal("too many errors");
- }
- static void
- warn(Fsck *chk, char *fmt, ...)
- {
- char buf[256];
- va_list arg;
- static int nerr;
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof buf, fmt, arg);
- va_end(arg);
- chk->print("error: %s\n", buf);
- }
- static void
- clrenop(Fsck*, Block*, int)
- {
- }
- static void
- closenop(Fsck*, Block*, u32int)
- {
- }
- static void
- clrinop(Fsck*, char*, MetaBlock*, int, Block*)
- {
- }
- static int
- printnop(char*, ...)
- {
- return 0;
- }
|