Пример #1
0
Файл: fs.c Проект: bhanug/harvey
int
fsEpochLow(Fs *fs, uint32_t low)
{
	Block *bs;
	Super super;

	vtLock(fs->elk);
	if(low > fs->ehi){
		vtSetError("bad low epoch (must be <= %ud)", fs->ehi);
		vtUnlock(fs->elk);
		return 0;
	}

	if((bs = superGet(fs->cache, &super)) == nil){
		vtUnlock(fs->elk);
		return 0;
	}

	super.epochLow = low;
	fs->elo = low;
	superWrite(bs, &super, 1);
	blockPut(bs);
	vtUnlock(fs->elk);

	return 1;
}
Пример #2
0
Файл: fs.c Проект: bhanug/harvey
int
saveQid(Fs *fs)
{
	Block *b;
	Super super;
	uint64_t qidMax;

	if((b = superGet(fs->cache, &super)) == nil)
		return 0;
	qidMax = super.qid;
	blockPut(b);

	if(!fileSetQidSpace(fs->file, 0, qidMax))
		return 0;

	return 1;
}
Пример #3
0
Файл: fs.c Проект: bhanug/harvey
int
fsNextQid(Fs *fs, uint64_t *qid)
{
	Block *b;
	Super super;

	if((b = superGet(fs->cache, &super)) == nil)
		return 0;

	*qid = super.qid++;

	/*
	 * It's okay if the super block doesn't go to disk immediately,
	 * since fileMetaAlloc will record a dependency between the
	 * block holding this qid and the super block.  See file.c:/^fileMetaAlloc.
	 */
	superWrite(b, &super, 0);
	blockPut(b);
	return 1;
}
Пример #4
0
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);
}
Пример #5
0
Файл: fs.c Проект: 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;
}
Пример #6
0
static void
archThread(void *v)
{
	Arch *a = v;
	Block *b;
	Param p;
	Super super;
	int ret;
	u32int addr;
	uchar rbuf[VtRootSize];
	VtRoot root;

	vtThreadSetName("arch");

	for(;;){
		/* look for work */
		vtLock(a->fs->elk);
		b = superGet(a->c, &super);
		if(b == nil){
			vtUnlock(a->fs->elk);
			fprint(2, "archThread: superGet: %R\n");
			sleep(60*1000);
			continue;
		}
		addr = super.next;
		if(addr != NilBlock && super.current == NilBlock){
			super.current = addr;
			super.next = NilBlock;
			superPack(&super, b->data);
			blockDirty(b);
		}else
			addr = super.current;
		blockPut(b);
		vtUnlock(a->fs->elk);

		if(addr == NilBlock){
			/* wait for work */
			vtLock(a->lk);
			vtSleep(a->starve);
			if(a->die != nil)
				goto Done;
			vtUnlock(a->lk);
			continue;
		}

sleep(10*1000);	/* window of opportunity to provoke races */

		/* do work */
		memset(&p, 0, sizeof p);
		p.blockSize = a->blockSize;
		p.dsize = 3*VtEntrySize;	/* root has three Entries */
		p.c = a->c;
		p.a = a;

		ret = archWalk(&p, addr, BtDir, RootTag);
		switch(ret){
		default:
			abort();
		case ArchFailure:
			fprint(2, "archiveBlock %#ux: %R\n", addr);
			sleep(60*1000);
			continue;
		case ArchSuccess:
		case ArchFaked:
			break;
		}

		if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud"
			" send %ud nfailsend %ud nvisit %ud"
			" nreclaim %ud nfake %ud nreal %ud\n",
			addr, p.maxdepth, p.nfixed,
			p.nsend, p.nfailsend, p.nvisit,
			p.nreclaim, p.nfake, p.nreal);
		if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize);

		/* tie up vac root */
		memset(&root, 0, sizeof root);
		root.version = VtRootVersion;
		strecpy(root.type, root.type+sizeof root.type, "vac");
		strecpy(root.name, root.name+sizeof root.name, "fossil");
		memmove(root.score, p.score, VtScoreSize);
		memmove(root.prev, super.last, VtScoreSize);
		root.blockSize = a->blockSize;
		vtRootPack(&root, rbuf);
		if(!vtWrite(a->z, p.score, VtRootType, rbuf, VtRootSize)
		|| !vtSha1Check(p.score, rbuf, VtRootSize)){
			fprint(2, "vtWriteBlock %#ux: %R\n", addr);
			sleep(60*1000);
			continue;
		}

		/* record success */
		vtLock(a->fs->elk);
		b = superGet(a->c, &super);
		if(b == nil){
			vtUnlock(a->fs->elk);
			fprint(2, "archThread: superGet: %R\n");
			sleep(60*1000);
			continue;
		}
		super.current = NilBlock;
		memmove(super.last, p.score, VtScoreSize);
		superPack(&super, b->data);
		blockDirty(b);
		blockPut(b);
		vtUnlock(a->fs->elk);

		consPrint("archive vac:%V\n", p.score);
	}

Done:
	a->ref--;
	vtWakeup(a->die);
	vtUnlock(a->lk);
}