Esempio n. 1
0
File: source.c Progetto: npe9/harvey
/*
 * Change the depth of the source r.
 * The entry e for r is contained in block p.
 */
static int
sourceGrowDepth(Source *r, Block *p, Entry *e, int depth)
{
    Block *b, *bb;
    uint32_t tag;
    int type;
    Entry oe;

    assert(sourceIsLocked(r));
    assert(depth <= VtPointerDepth);

    type = entryType(e);
    b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
    if(b == nil)
        return 0;

    tag = e->tag;
    if(tag == 0)
        tag = tagGen();

    oe = *e;

    /*
     * Keep adding layers until we get to the right depth
     * or an error occurs.
     */
    while(e->depth < depth) {
        bb = cacheAllocBlock(r->fs->cache, type+1, tag, r->fs->ehi, r->fs->elo);
        if(bb == nil)
            break;
//fprint(2, "alloc %lux grow %V\n", bb->addr, b->score);
        memmove(bb->data, b->score, VtScoreSize);
        memmove(e->score, bb->score, VtScoreSize);
        e->depth++;
        type++;
        e->tag = tag;
        e->flags |= VtEntryLocal;
        blockDependency(bb, b, 0, vtZeroScore, nil);
        blockPut(b);
        b = bb;
        blockDirty(b);
    }

    entryPack(e, p->data, r->offset % r->epb);
    blockDependency(p, b, r->offset % r->epb, nil, &oe);
    blockPut(b);
    blockDirty(p);

    return e->depth == depth;
}
Esempio n. 2
0
/*
 * 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;
}
Esempio n. 3
0
/* 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;
}
Esempio n. 4
0
File: fs.c Progetto: bhanug/harvey
static int
bumpEpoch(Fs *fs, int doarchive)
{
	uint8_t oscore[VtScoreSize];
	uint32_t oldaddr;
	Block *b, *bs;
	Entry e;
	Source *r;
	Super super;

	/*
	 * Duplicate the root block.
	 *
	 * As a hint to flchk, the garbage collector,
	 * and any (human) debuggers, store a pointer
	 * to the old root block in entry 1 of the new root block.
	 */
	r = fs->source;
	b = cacheGlobal(fs->cache, r->score, BtDir, RootTag, OReadOnly);
	if(b == nil)
		return 0;

	memset(&e, 0, sizeof e);
	e.flags = VtEntryActive | VtEntryLocal | VtEntryDir;
	memmove(e.score, b->score, VtScoreSize);
	e.tag = RootTag;
	e.snap = b->l.epoch;

	b = blockCopy(b, RootTag, fs->ehi+1, fs->elo);
	if(b == nil){
		fprint(2, "%s: bumpEpoch: blockCopy: %R\n", argv0);
		return 0;
	}

	if(0) fprint(2, "%s: snapshot root from %d to %d\n", argv0, oldaddr, b->addr);
	entryPack(&e, b->data, 1);
	blockDirty(b);

	/*
	 * Update the superblock with the new root and epoch.
	 */
	if((bs = superGet(fs->cache, &super)) == nil)
		return 0;

	fs->ehi++;
	memmove(r->score, b->score, VtScoreSize);
	r->epoch = fs->ehi;

	super.epochHigh = fs->ehi;
	oldaddr = super.active;
	super.active = b->addr;
	if(doarchive)
		super.next = oldaddr;

	/*
	 * Record that the new super.active can't get written out until
	 * the new b gets written out.  Until then, use the old value.
	 */
	localToGlobal(oldaddr, oscore);
	blockDependency(bs, b, 0, oscore, nil);
	blockPut(b);

	/*
	 * We force the super block to disk so that super.epochHigh gets updated.
	 * Otherwise, if we crash and come back, we might incorrectly treat as active
	 * some of the blocks that making up the snapshot we just created.
	 * Basically every block in the active file system and all the blocks in
	 * the recently-created snapshot depend on the super block now.
	 * Rather than record all those dependencies, we just force the block to disk.
	 *
	 * Note that blockWrite might actually (will probably) send a slightly outdated
	 * super.active to disk.  It will be the address of the most recent root that has
	 * gone to disk.
	 */
	superWrite(bs, &super, 1);
	blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0);
	blockPut(bs);

	return 1;
}
Esempio n. 5
0
File: fs.c Progetto: bhanug/harvey
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;
}
Esempio n. 6
0
File: source.c Progetto: npe9/harvey
static int
sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
{
    Block *b, *nb, *ob, *rb;
    uint32_t tag;
    int type, d;
    Entry oe;

    assert(sourceIsLocked(r));
    assert(depth <= VtPointerDepth);

    type = entryType(e);
    rb = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
    if(rb == nil)
        return 0;

    tag = e->tag;
    if(tag == 0)
        tag = tagGen();

    /*
     * Walk down to the new root block.
     * We may stop early, but something is better than nothing.
     */
    oe = *e;

    ob = nil;
    b = rb;
    /* BUG: explain type++.  i think it is a real bug */
    for(d=e->depth; d > depth; d--, type++) {
        nb = cacheGlobal(r->fs->cache, b->data, type-1, tag, OReadWrite);
        if(nb == nil)
            break;
        if(ob!=nil && ob!=rb)
            blockPut(ob);
        ob = b;
        b = nb;
    }

    if(b == rb) {
        blockPut(rb);
        return 0;
    }

    /*
     * Right now, e points at the root block rb, b is the new root block,
     * and ob points at b.  To update:
     *
     *	(i) change e to point at b
     *	(ii) zero the pointer ob -> b
     *	(iii) free the root block
     *
     * p (the block containing e) must be written before
     * anything else.
     */

    /* (i) */
    e->depth = d;
    /* might have been local and now global; reverse cannot happen */
    if(globalToLocal(b->score) == NilBlock)
        e->flags &= ~VtEntryLocal;
    memmove(e->score, b->score, VtScoreSize);
    entryPack(e, p->data, r->offset % r->epb);
    blockDependency(p, b, r->offset % r->epb, nil, &oe);
    blockDirty(p);

    /* (ii) */
    memmove(ob->data, vtZeroScore, VtScoreSize);
    blockDependency(ob, p, 0, b->score, nil);
    blockDirty(ob);

    /* (iii) */
    if(rb->addr != NilBlock)
        blockRemoveLink(p, rb->addr, rb->l.type, rb->l.tag, 1);

    blockPut(rb);
    if(ob!=nil && ob!=rb)
        blockPut(ob);
    blockPut(b);

    return d == depth;
}
Esempio n. 7
0
File: source.c Progetto: npe9/harvey
static Block *
blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e)
{
    Block *b;
    Cache *c;
    uint32_t addr;
    int type;
    uint8_t oscore[VtScoreSize], score[VtScoreSize];
    Entry oe;

    c = fs->cache;

    if((p->l.type & BtLevelMask) == 0) {
        assert(p->l.type == BtDir);
        type = entryType(e);
        b = cacheGlobal(c, e->score, type, e->tag, mode);
    } else {
        type = p->l.type - 1;
        b = cacheGlobal(c, p->data + index*VtScoreSize, type, e->tag, mode);
    }

    if(b)
        b->pc = getcallerpc(&p);

    if(b == nil || mode == OReadOnly)
        return b;

    if(p->l.epoch != fs->ehi) {
        fprint(2, "blockWalk: parent not writable\n");
        abort();
    }
    if(b->l.epoch == fs->ehi)
        return b;

    oe = *e;

    /*
     * Copy on write.
     */
    if(e->tag == 0) {
        assert(p->l.type == BtDir);
        e->tag = tagGen();
        e->flags |= VtEntryLocal;
    }

    addr = b->addr;
    b = blockCopy(b, e->tag, fs->ehi, fs->elo);
    if(b == nil)
        return nil;

    b->pc = getcallerpc(&p);
    assert(b->l.epoch == fs->ehi);

    blockDirty(b);
    memmove(score, b->score, VtScoreSize);
    if(p->l.type == BtDir) {
        memmove(e->score, b->score, VtScoreSize);
        entryPack(e, p->data, index);
        blockDependency(p, b, index, nil, &oe);
    } else {
        memmove(oscore, p->data+index*VtScoreSize, VtScoreSize);
        memmove(p->data+index*VtScoreSize, b->score, VtScoreSize);
        blockDependency(p, b, index, oscore, nil);
    }
    blockDirty(p);

    if(addr != NilBlock)
        blockRemoveLink(p, addr, type, e->tag, 0);

    return b;
}