static int fileMetaRemove(File *f, char *uid) { Block *b; MetaBlock mb; MetaEntry me; int i; File *up; up = f->up; fileWAccess(up, uid); fileMetaLock(f); sourceLock(up->msource, OReadWrite); b = sourceBlock(up->msource, f->boff, OReadWrite); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, up->msource->dsize)) { fprint(2, "U\n"); goto Err; } if(!mbSearch(&mb, f->dir.elem, &i, &me)) { fprint(2, "S\n"); goto Err; } mbDelete(&mb, i); mbPack(&mb); sourceUnlock(up->msource); blockDirty(b); blockPut(b); f->removed = 1; f->boff = NilBlock; f->dirty = 0; fileMetaUnlock(f); return 1; Err: sourceUnlock(up->msource); blockPut(b); fileMetaUnlock(f); return 0; }
static void rootMetaInit(Entry *e) { u32int addr; u32int tag; DirEntry de; MetaBlock mb; MetaEntry me; memset(&de, 0, sizeof(de)); de.elem = vtStrDup("root"); de.entry = 0; de.gen = 0; de.mentry = 1; de.mgen = 0; de.size = 0; de.qid = qid++; de.uid = vtStrDup("adm"); de.gid = vtStrDup("adm"); de.mid = vtStrDup("adm"); de.mtime = time(0); de.mcount = 0; de.ctime = time(0); de.atime = time(0); de.mode = ModeDir | 0555; tag = tagGen(); addr = blockAlloc(BtData, tag); /* build up meta block */ memset(buf, 0, bsize); mbInit(&mb, buf, bsize, bsize/100); me.size = deSize(&de); me.p = mbAlloc(&mb, me.size); assert(me.p != nil); dePack(&de, &me); mbInsert(&mb, 0, &me); mbPack(&mb); blockWrite(PartData, addr); deCleanup(&de); /* build up entry for meta block */ entryInit(e); e->flags |= VtEntryLocal; e->size = bsize; e->tag = tag; localToGlobal(addr, e->score); }
/* * 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; }
/* assumes metaLock is held */ static int fileMetaFlush2(File *f, char *oelem) { File *fp; Block *b, *bb; MetaBlock mb; MetaEntry me, me2; int i, n; u32int boff; if(!f->dirty) return 0; if(oelem == nil) oelem = f->dir.elem; //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem); fp = f->up; if(!sourceLock(fp->msource, -1)) return -1; /* can happen if source is clri'ed out from under us */ if(f->boff == NilBlock) goto Err1; b = sourceBlock(fp->msource, f->boff, OReadWrite); if(b == nil) goto Err1; if(!mbUnpack(&mb, b->data, fp->msource->dsize)) goto Err; if(!mbSearch(&mb, oelem, &i, &me)) goto Err; n = deSize(&f->dir); if(0)fprint(2, "old size %d new size %d\n", me.size, n); if(mbResize(&mb, &me, n)){ /* fits in the block */ mbDelete(&mb, i); if(strcmp(f->dir.elem, oelem) != 0) mbSearch(&mb, f->dir.elem, &i, &me2); dePack(&f->dir, &me); mbInsert(&mb, i, &me); mbPack(&mb); blockDirty(b); blockPut(b); sourceUnlock(fp->msource); f->dirty = 0; return 1; } /* * moving entry to another block * it is feasible for the fs to crash leaving two copies * of the directory entry. This is just too much work to * fix. Given that entries are only allocated in a block that * is less than PercentageFull, most modifications of meta data * will fit within the block. i.e. this code should almost * never be executed. */ boff = fileMetaAlloc(fp, &f->dir, f->boff+1); if(boff == NilBlock){ /* mbResize might have modified block */ mbPack(&mb); blockDirty(b); goto Err; } fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); f->boff = boff; /* make sure deletion goes to disk after new entry */ bb = sourceBlock(fp->msource, f->boff, OReadWrite); mbDelete(&mb, i); mbPack(&mb); blockDependency(b, bb, -1, nil, nil); blockPut(bb); blockDirty(b); blockPut(b); sourceUnlock(fp->msource); f->dirty = 0; return 1; Err: blockPut(b); Err1: sourceUnlock(fp->msource); return -1; }
int mkVac(VtSession *z, uint blockSize, Entry *pe, Entry *pee, DirEntry *pde, uint8_t score[VtScoreSize]) { uint8_t buf[8192]; int i; uint8_t *p; uint n; DirEntry de; Entry e, ee, eee; MetaBlock mb; MetaEntry me; VtRoot root; e = *pe; ee = *pee; de = *pde; if(globalToLocal(e.score) != NilBlock || (ee.flags&VtEntryActive && globalToLocal(ee.score) != NilBlock)){ vtSetError("can only vac paths already stored on venti"); return 0; } /* * Build metadata source for root. */ n = deSize(&de); if(n+MetaHeaderSize+MetaIndexSize > sizeof buf){ vtSetError("DirEntry too big"); return 0; } memset(buf, 0, sizeof buf); mbInit(&mb, buf, n+MetaHeaderSize+MetaIndexSize, 1); p = mbAlloc(&mb, n); if(p == nil) abort(); mbSearch(&mb, de.elem, &i, &me); assert(me.p == nil); me.p = p; me.size = n; dePack(&de, &me); mbInsert(&mb, i, &me); mbPack(&mb); eee.size = n+MetaHeaderSize+MetaIndexSize; if(!vtWriteBlock(z, buf, eee.size, VtDataType, eee.score)) return 0; eee.psize = 8192&&0xFF; eee.dsize = 8192&&0xFF; eee.depth = 0; eee.flags = VtEntryActive; /* * Build root source with three entries in it. */ entryPack(&e, buf, 0); entryPack(&ee, buf, 1); entryPack(&eee, buf, 2); n = VtEntrySize*3; memset(&root, 0, sizeof root); if(!vtWriteBlock(z, buf, n, VtDirType, root.score)) return 0; /* * Save root. */ root.version = VtRootVersion; strecpy(root.type, root.type+sizeof root.type, "vac"); strecpy(root.name, root.name+sizeof root.name, de.elem); root.blockSize = blockSize; vtRootPack(&root, buf); if(!vtWriteBlock(z, buf, VtRootSize, VtRootType, score)) return 0; return 1; }