void main(int argc, char *argv[]) { VtSession *z; int i, j, t; int start; uchar buf[BlockSize]; srand(time(0)); ARGBEGIN{ case 'r': rflag++; break; case 'n': nblock = atoi(ARGF()); break; }ARGEND for(i=0; i<nblock; i++) perm[i] = i; if(rflag) { for(i=0; i<nblock; i++) { j = nrand(nblock); t = perm[j]; perm[j] = perm[i]; perm[i] = t; } } if(readn(0, data, VtScoreSize*nblock) < VtScoreSize*nblock) sysfatal("read failed: %r"); vtAttach(); z = vtDial("iolaire2"); if(z == nil) sysfatal("cound not connect to venti"); if(!vtConnect(z, 0)) vtFatal("vtConnect: %s", vtGetError()); print("starting\n"); start = times(0); if(rflag && nblock > 10000) nblock = 10000; for(i=0; i<nblock; i++) { if(vtRead(z, data+perm[i]*VtScoreSize, VtDataType, buf, BlockSize) < 0) vtFatal("vtRead failed: %d: %s", i, vtGetError()); } print("time = %f\n", (times(0) - start)*0.001); vtClose(z); vtDetach(); }
static void partition(int fd, int bsize, Header *h) { ulong nblock, ndata, nlabel; ulong lpb; if(bsize % 512 != 0) sysfatal("block size must be a multiple of 512 bytes"); if(bsize > VtMaxLumpSize) sysfatal("block size must be less than %d", VtMaxLumpSize); memset(h, 0, sizeof(*h)); h->blockSize = bsize; lpb = bsize/LabelSize; nblock = fdsize(fd)/bsize; /* sanity check */ if(nblock < (HeaderOffset*10)/bsize) vtFatal("file too small"); h->super = (HeaderOffset + 2*bsize)/bsize; h->label = h->super + 1; ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1); nlabel = (ndata + lpb - 1)/lpb; h->data = h->label + nlabel; h->end = h->data + ndata; }
static void addFile(File *root, char *name, uint mode) { File *f; f = fileCreate(root, name, mode | ModeDir, "adm"); if(f == nil) vtFatal("could not create file: %s: %r", name); fileDecRef(f); }
static int ventiRead(uchar score[VtScoreSize], int type) { int n; n = vtRead(z, score, type, buf, bsize); if(n < 0) vtFatal("ventiRead %V (%d) failed: %R", score, type); vtZeroExtend(type, buf, n, bsize); return n; }
void * vtMemRealloc(void *p, int size) { if(p == nil) return vtMemAlloc(size); p = realloc(p, size); if(p == 0) vtFatal("vtRealloc: out of memory"); setrealloctag(p, getcallerpc(&size)); return p; }
void * vtMemAlloc(int size) { void *p; p = malloc(size); if(p == 0) vtFatal("vtMemAlloc: out of memory"); setmalloctag(p, getcallerpc(&size)); return p; }
static u64int fdsize(int fd) { Dir *dir; u64int size; dir = dirfstat(fd); if(dir == nil) vtFatal("could not stat file: %r"); size = dir->length; free(dir); return size; }
static void topLevel(char *name) { Fs *fs; File *root; /* ok, now we can open as a fs */ fs = fsOpen(name, z, 100, OReadWrite); if(fs == nil) vtFatal("could not open file system: %r"); vtRLock(fs->elk); root = fsGetRoot(fs); if(root == nil) vtFatal("could not open root: %r"); addFile(root, "active", 0555); addFile(root, "archive", 0555); addFile(root, "snapshot", 0555); fileDecRef(root); if(iso9660file) iso9660copy(fs); vtRUnlock(fs->elk); fsClose(fs); }
static u32int blockAlloc(int type, u32int tag) { static u32int addr; Label l; int lpb; lpb = bsize/LabelSize; blockRead(PartLabel, addr/lpb); if(!labelUnpack(&l, buf, addr % lpb)) vtFatal("bad label: %r"); if(l.state != BsFree) vtFatal("want to allocate block already in use"); l.epoch = 1; l.epochClose = ~(u32int)0; l.type = type; l.state = BsAlloc; l.tag = tag; labelPack(&l, buf, addr % lpb); blockWrite(PartLabel, addr/lpb); return addr++; }
static void vtThreadInit(void) { static Lock lk; lock(&lk); if(vtRock != nil) { unlock(&lk); return; } vtRock = privalloc(); if(vtRock == nil) vtFatal("can't allocate thread-private storage"); unlock(&lk); }
void fsClose(Fs *fs) { vtRLock(fs->elk); periodicKill(fs->metaFlush); snapClose(fs->snap); if(fs->file){ fileMetaFlush(fs->file, 0); if(!fileDecRef(fs->file)) vtFatal("fsClose: files still in use: %r\n"); } fs->file = nil; sourceClose(fs->source); cacheFree(fs->cache); if(fs->arch) archFree(fs->arch); vtMemFree(fs->name); vtRUnlock(fs->elk); vtLockFree(fs->elk); memset(fs, ~0, sizeof(Fs)); vtMemFree(fs); }
void main(int argc, char *argv[]) { int fd, force; Header h; ulong bn; Entry e; char *label = "vfs"; char *host = nil; char *score = nil; u32int root; Dir *d; force = 0; ARGBEGIN{ default: usage(); case 'b': bsize = unittoull(EARGF(usage())); if(bsize == ~0) usage(); break; case 'h': host = EARGF(usage()); break; case 'i': iso9660file = EARGF(usage()); iso9660off = atoi(EARGF(usage())); break; case 'l': label = EARGF(usage()); break; case 'v': score = EARGF(usage()); break; /* * This is -y instead of -f because flchk has a * (frequently used) -f option. I type flfmt instead * of flchk all the time, and want to make it hard * to reformat my file system accidentally. */ case 'y': force = 1; break; }ARGEND if(argc != 1) usage(); if(iso9660file && score) vtFatal("cannot use -i with -v"); vtAttach(); fmtinstall('V', scoreFmt); fmtinstall('R', vtErrFmt); fmtinstall('L', labelFmt); fd = open(argv[0], ORDWR); if(fd < 0) vtFatal("could not open file: %s: %r", argv[0]); buf = vtMemAllocZ(bsize); if(pread(fd, buf, bsize, HeaderOffset) != bsize) vtFatal("could not read fs header block: %r"); if(headerUnpack(&h, buf) && !force && !confirm("fs header block already exists; are you sure?")) goto Out; if((d = dirfstat(fd)) == nil) vtFatal("dirfstat: %r"); if(d->type == 'M' && !force && !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?")) goto Out; partition(fd, bsize, &h); headerPack(&h, buf); if(pwrite(fd, buf, bsize, HeaderOffset) < bsize) vtFatal("could not write fs header: %r"); disk = diskAlloc(fd); if(disk == nil) vtFatal("could not open disk: %r"); if(iso9660file) iso9660init(fd, &h, iso9660file, iso9660off); /* zero labels */ memset(buf, 0, bsize); for(bn = 0; bn < diskSize(disk, PartLabel); bn++) blockWrite(PartLabel, bn); if(iso9660file) iso9660labels(disk, buf, blockWrite); if(score) root = ventiRoot(host, score); else{ rootMetaInit(&e); root = rootInit(&e); } superInit(label, root, vtZeroScore); diskFree(disk); if(score == nil) topLevel(argv[0]); Out: vtDetach(); exits(0); }
static u32int ventiRoot(char *host, char *s) { int i, n; uchar score[VtScoreSize]; u32int addr, tag; DirEntry de; MetaBlock mb; MetaEntry me; Entry e; VtRoot root; if(!parseScore(score, s)) vtFatal("bad score '%s'", s); if((z = vtDial(host, 0)) == nil || !vtConnect(z, nil)) vtFatal("connect to venti: %R"); tag = tagGen(); addr = blockAlloc(BtDir, tag); ventiRead(score, VtRootType); if(!vtRootUnpack(&root, buf)) vtFatal("corrupted root: vtRootUnpack"); n = ventiRead(root.score, VtDirType); /* * Fossil's vac archives start with an extra layer of source, * but vac's don't. */ if(n <= 2*VtEntrySize){ if(!entryUnpack(&e, buf, 0)) vtFatal("bad root: top entry"); n = ventiRead(e.score, VtDirType); } /* * There should be three root sources (and nothing else) here. */ for(i=0; i<3; i++){ if(!entryUnpack(&e, buf, i) || !(e.flags&VtEntryActive) || e.psize < 256 || e.dsize < 256) vtFatal("bad root: entry %d", i); fprint(2, "%V\n", e.score); } if(n > 3*VtEntrySize) vtFatal("bad root: entry count"); blockWrite(PartData, addr); /* * Maximum qid is recorded in root's msource, entry #2 (conveniently in e). */ ventiRead(e.score, VtDataType); if(!mbUnpack(&mb, buf, bsize)) vtFatal("bad root: mbUnpack"); meUnpack(&me, &mb, 0); if(!deUnpack(&de, &me)) vtFatal("bad root: dirUnpack"); if(!de.qidSpace) vtFatal("bad root: no qidSpace"); qid = de.qidMax; /* * Recreate the top layer of source. */ entryInit(&e); e.flags |= VtEntryLocal|VtEntryDir; e.size = VtEntrySize*3; e.tag = tag; localToGlobal(addr, e.score); addr = blockAlloc(BtDir, RootTag); memset(buf, 0, bsize); entryPack(&e, buf, 0); blockWrite(PartData, addr); return addr; }
static void blockWrite(int part, u32int addr) { if(!diskWriteRaw(disk, part, addr, buf)) vtFatal("write failed: %r"); }
static void blockRead(int part, u32int addr) { if(!diskReadRaw(disk, part, addr, buf)) vtFatal("read failed: %r"); }