⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "stdinc.h"#include "dat.h"#include "fns.h"#include "error.h"static void fsMetaFlush(void *a);static Snap *snapInit(Fs*);static void snapClose(Snap*);Fs *fsOpen(char *file, VtSession *z, long ncache, int mode){	Fs *fs;	Disk *disk;	int fd;	Block *b, *bs;	Super super;	int m;	uchar oscore[VtScoreSize];	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->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, "fs->ehi %d fs->elo %d active=%d\n", 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, "got fs source\n");	vtRLock(fs->elk);	fs->file = fileRoot(fs->source);	vtRUnlock(fs->elk);	if(fs->file == nil){		vtSetError("fileRoot: %R");		goto Err;	}//fprint(2, "got file root\n");	if(mode == OReadWrite){		fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000);		fs->snap = snapInit(fs);	}	return fs;Err:fprint(2, "fsOpen error\n");	fsClose(fs);	return nil;}voidfsClose(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);	vtRUnlock(fs->elk);	vtLockFree(fs->elk);	memset(fs, ~0, sizeof(Fs));	vtMemFree(fs);}intfsRedial(Fs *fs, char *host){	if(!vtRedial(fs->z, host))		return 0;	if(!vtConnect(fs->z, 0))		return 0;	return 1;}File *fsGetRoot(Fs *fs){	return fileIncRef(fs->file);}intfsGetBlockSize(Fs *fs){	return fs->blockSize;}Block*superGet(Cache *c, Super* super){	Block *b;	if((b = cacheLocal(c, PartSuper, 0, OReadWrite)) == nil){		fprint(2, "superGet: cacheLocal failed: %R");		return nil;	}	if(!superUnpack(super, b->data)){		fprint(2, "superGet: superUnpack failed: %R");		blockPut(b);		return nil;	}	return b;}voidsuperWrite(Block* b, Super* super, int forceWrite){	superPack(super, b->data);	blockDirty(b);	if(forceWrite){		while(!blockWrite(b)){			/* BUG: what should really happen here? */			fprint(2, "could not write super block; waiting 10 seconds\n");			sleep(10*1000);		}		while(b->iostate != BioClean && b->iostate != BioDirty){			assert(b->iostate == BioWriting);			vtSleep(b->ioready);		}		/*		 * it's okay that b might still be dirty.		 * that means it got written out but with an old root pointer,		 * but the other fields went out, and those are the ones		 * we really care about.  (specifically, epochHigh; see fsSnapshot).		 */	}}/* * Prepare the directory to store a snapshot. * Temporary snapshots go into /snapshot/yyyy/mmdd/hhmm[.#] * Archival snapshots go into /archive/yyyy/mmdd[.#]. * * TODO This should be rewritten to eliminate most of the duplication. */static File*fileOpenSnapshot(Fs *fs, char *dstpath, int doarchive){	int n;	char buf[30], *s, *p, *elem;	File *dir, *f;	Tm now;	if(dstpath){		if((p = strrchr(dstpath, '/')) != nil){			*p++ = '\0';			elem = p;			p = dstpath;			if(*p == '\0')				p = "/";		}else{			p = "/";			elem = dstpath;		}		if((dir = fileOpen(fs, p)) == nil)			return nil;		f = fileCreate(dir, elem, ModeDir|ModeSnapshot|0555, "adm");		fileDecRef(dir);		return f;	}else if(doarchive){		/*		 * a snapshot intended to be archived to venti.		 */		dir = fileOpen(fs, "/archive");		if(dir == nil)			return nil;		now = *localtime(time(0));		/* yyyy */		snprint(buf, sizeof(buf), "%d", now.year+1900);		f = fileWalk(dir, buf);		if(f == nil)			f = fileCreate(dir, buf, ModeDir|0555, "adm");		fileDecRef(dir);		if(f == nil)			return nil;		dir = f;		/* mmdd[#] */		snprint(buf, sizeof(buf), "%02d%02d", now.mon+1, now.mday);		s = buf+strlen(buf);		for(n=0;; n++){			if(n)				seprint(s, buf+sizeof(buf), ".%d", n);			f = fileWalk(dir, buf);			if(f != nil){				fileDecRef(f);				continue;			}			f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm");			break;		}		fileDecRef(dir);		return f;	}else{		/*		 * Just a temporary snapshot		 * We'll use /snapshot/yyyy/mmdd/hhmm.		 * There may well be a better naming scheme.		 * (I'd have used hh:mm but ':' is reserved in Microsoft file systems.)		 */		dir = fileOpen(fs, "/snapshot");		if(dir == nil)			return nil;		now = *localtime(time(0));		/* yyyy */		snprint(buf, sizeof(buf), "%d", now.year+1900);		f = fileWalk(dir, buf);		if(f == nil)			f = fileCreate(dir, buf, ModeDir|0555, "adm");		fileDecRef(dir);		if(f == nil)			return nil;		dir = f;		/* mmdd */		snprint(buf, sizeof(buf), "%02d%02d", now.mon+1, now.mday);		f = fileWalk(dir, buf);		if(f == nil)			f = fileCreate(dir, buf, ModeDir|0555, "adm");		fileDecRef(dir);		if(f == nil)			return nil;		dir = f;		/* hhmm[.#] */		snprint(buf, sizeof buf, "%02d%02d", now.hour, now.min);		s = buf+strlen(buf);		for(n=0;; n++){			if(n)				seprint(s, buf+sizeof(buf), ".%d", n);			f = fileWalk(dir, buf);			if(f != nil){				fileDecRef(f);				continue;			}			f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm");			break;		}		fileDecRef(dir);		return f;	}}static intfsNeedArch(Fs *fs, uint archMinute){	int need;	File *f;	char buf[100];	Tm now;	ulong then;	then = time(0);	now = *localtime(then);	/* back up to yesterday if necessary */	if(now.hour < archMinute/60	|| now.hour == archMinute/60 && now.min < archMinute%60)		now = *localtime(then-86400);	snprint(buf, sizeof buf, "/archive/%d/%02d%02d",		now.year+1900, now.mon+1, now.mday);	need = 1;	vtRLock(fs->elk);	f = fileOpen(fs, buf);	if(f){		need = 0;		fileDecRef(f);	}	vtRUnlock(fs->elk);	return need;}intfsEpochLow(Fs *fs, u32int 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;}static intbumpEpoch(Fs *fs, int doarchive){	uchar oscore[VtScoreSize];	u32int 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, "bumpEpoch: blockCopy: %R\n");		return 0;	}	if(0) fprint(2, "snapshot root from %d to %d\n", 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;}intsaveQid(Fs *fs){	Block *b;	Super super;	u64int 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;}intfsSnapshot(Fs *fs, char *srcpath, char *dstpath, int doarchive){	File *src, *dst;	assert(fs->mode == OReadWrite);	dst = nil;	if(fs->halted){		vtSetError("file system is halted");		return 0;	}	/*	 * Freeze file system activity.	 */	vtLock(fs->elk);	/*	 * Get the root of the directory we're going to save.	 */	if(srcpath == nil)		srcpath = "/active";	src = fileOpen(fs, srcpath);	if(src == nil)		goto Err;	/*	 * It is important that we maintain the invariant that:	 *	if both b and bb are marked as Active with start epoch e	 *	and b points at bb, then no other pointers to bb exist.	 * 	 * When bb is unlinked from b, its close epoch is set to b's epoch.	 * A block with epoch == close epoch is	 * treated as free by cacheAllocBlock; this aggressively	 * reclaims blocks after they have been stored to Venti.	 *	 * Let's say src->source is block sb, and src->msource is block	 * mb.  Let's also say that block b holds the Entry structures for	 * both src->source and src->msource (their Entry structures might	 * be in different blocks, but the argument is the same).	 * That is, right now we have:	 *	 *	b	Active w/ epoch e, holds ptrs to sb and mb.	 *	sb	Active w/ epoch e.	 *	mb	Active w/ epoch e.	 *	 * With things as they are now, the invariant requires that	 * b holds the only pointers to sb and mb.  We want to record	 * pointers to sb and mb in new Entries corresponding to dst,	 * which breaks the invariant.  Thus we need to do something

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -