/* * 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); }
Block* superGet(Cache *c, Super* super) { Block *b; if((b = cacheLocal(c, PartSuper, 0, OReadWrite)) == nil){ fprint(2, "%s: superGet: cacheLocal failed: %R\n", argv0); return nil; } if(!superUnpack(super, b->data)){ fprint(2, "%s: superGet: superUnpack failed: %R\n", argv0); blockPut(b); return nil; } return b; }
/* * caller must lock f->source and f->msource * caller must NOT lock the source and msource * referenced by dir. */ static u32int fileMetaAlloc(File *f, DirEntry *dir, u32int start) { u32int nb, bo; Block *b, *bb; MetaBlock mb; int nn; uchar *p; int i, n, epb; MetaEntry me; Source *s, *ms; s = f->source; ms = f->msource; n = deSize(dir); nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize; b = nil; if(start > nb) start = nb; for(bo=start; bo<nb; bo++){ b = sourceBlock(ms, bo, OReadWrite); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, ms->dsize)) goto Err; nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; if(n <= nn && mb.nindex < mb.maxindex) break; blockPut(b); b = nil; } /* add block to meta file */ if(b == nil){ b = sourceBlock(ms, bo, OReadWrite); if(b == nil) goto Err; sourceSetSize(ms, (nb+1)*ms->dsize); mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); } p = mbAlloc(&mb, n); if(p == nil){ /* mbAlloc might have changed block */ mbPack(&mb); blockDirty(b); vtSetError(EBadMeta); goto Err; } mbSearch(&mb, dir->elem, &i, &me); assert(me.p == nil); me.p = p; me.size = n; dePack(dir, &me); mbInsert(&mb, i, &me); mbPack(&mb); /* meta block depends on super block for qid ... */ bb = cacheLocal(b->c, PartSuper, 0, OReadOnly); blockDependency(b, bb, -1, nil, nil); blockPut(bb); /* ... and one or two dir entries */ epb = s->dsize/VtEntrySize; bb = sourceBlock(s, dir->entry/epb, OReadOnly); blockDependency(b, bb, -1, nil, nil); blockPut(bb); if(dir->mode & ModeDir){ bb = sourceBlock(s, dir->mentry/epb, OReadOnly); blockDependency(b, bb, -1, nil, nil); blockPut(bb); } blockDirty(b); blockPut(b); return bo; Err: blockPut(b); return NilBlock; }
Fs * fsOpen(char *file, VtSession *z, int32_t ncache, int mode) { int fd, m; uint8_t oscore[VtScoreSize]; Block *b, *bs; Disk *disk; Fs *fs; Super super; switch(mode){ default: vtSetError(EBadMode); return nil; case OReadOnly: m = OREAD; break; case OReadWrite: m = ORDWR; break; } fd = open(file, m); if(fd < 0){ vtSetError("open %s: %r", file); return nil; } bwatchInit(); disk = diskAlloc(fd); if(disk == nil){ vtSetError("diskAlloc: %R"); close(fd); return nil; } fs = vtMemAllocZ(sizeof(Fs)); fs->mode = mode; fs->name = vtStrDup(file); fs->blockSize = diskBlockSize(disk); fs->elk = vtLockAlloc(); fs->cache = cacheAlloc(disk, z, ncache, mode); if(mode == OReadWrite && z) fs->arch = archInit(fs->cache, disk, fs, z); fs->z = z; b = cacheLocal(fs->cache, PartSuper, 0, mode); if(b == nil) goto Err; if(!superUnpack(&super, b->data)){ blockPut(b); vtSetError("bad super block"); goto Err; } blockPut(b); fs->ehi = super.epochHigh; fs->elo = super.epochLow; //fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ /* * Perhaps it failed because the block is copy-on-write. * Do the copy and try again. */ if(mode == OReadOnly || strcmp(vtGetError(), EBadRoot) != 0) goto Err; b = cacheLocalData(fs->cache, super.active, BtDir, RootTag, OReadWrite, 0); if(b == nil){ vtSetError("cacheLocalData: %R"); goto Err; } if(b->l.epoch == fs->ehi){ blockPut(b); vtSetError("bad root source block"); goto Err; } b = blockCopy(b, RootTag, fs->ehi, fs->elo); if(b == nil) goto Err; localToGlobal(super.active, oscore); super.active = b->addr; bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite); if(bs == nil){ blockPut(b); vtSetError("cacheLocal: %R"); goto Err; } superPack(&super, bs->data); blockDependency(bs, b, 0, oscore, nil); blockPut(b); blockDirty(bs); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ vtSetError("sourceRoot: %R"); goto Err; } } //fprint(2, "%s: got fs source\n", argv0); vtRLock(fs->elk); fs->file = fileRoot(fs->source); fs->source->file = fs->file; /* point back */ vtRUnlock(fs->elk); if(fs->file == nil){ vtSetError("fileRoot: %R"); goto Err; } //fprint(2, "%s: got file root\n", argv0); if(mode == OReadWrite){ fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000); fs->snap = snapInit(fs); } return fs; Err: fprint(2, "%s: fsOpen error\n", argv0); fsClose(fs); return nil; }