fs.c

来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 1,093 行 · 第 1/2 页

C
1,093
字号
	 * about b.  Specifically, we bump the file system's epoch and	 * then rewalk the path from the root down to and including b.	 * This will copy-on-write as we walk, so now the state will be:	 *	 *	b	Snap w/ epoch e, holds ptrs to sb and mb.	 *	new-b	Active w/ epoch e+1, holds ptrs to sb and mb.	 *	sb	Active w/ epoch e.	 *	mb	Active w/ epoch e.	 *	 * In this state, it's perfectly okay to make more pointers to sb and mb.	 */	if(!bumpEpoch(fs, 0) || !fileWalkSources(src))		goto Err;	/*	 * Sync to disk.  I'm not sure this is necessary, but better safe than sorry.	 */	cacheFlush(fs->cache, 1);	/*	 * Create the directory where we will store the copy of src.	 */	dst = fileOpenSnapshot(fs, dstpath, doarchive);	if(dst == nil)		goto Err;	/*	 * Actually make the copy by setting dst's source and msource	 * to be src's.	 */	if(!fileSnapshot(dst, src, fs->ehi-1, doarchive))		goto Err;	fileDecRef(src);	fileDecRef(dst);	src = nil;	dst = nil;	/*	 * Make another copy of the file system.  This one is for the	 * archiver, so that the file system we archive has the recently	 * added snapshot both in /active and in /archive/yyyy/mmdd[.#].	 */	if(doarchive){		if(!saveQid(fs))			goto Err;		if(!bumpEpoch(fs, 1))			goto Err;	}	vtUnlock(fs->elk);	/* BUG? can fs->arch fall out from under us here? */	if(doarchive && fs->arch)		archKick(fs->arch);	return 1;Err:	fprint(2, "fsSnapshot: %R\n");	if(src)		fileDecRef(src);	if(dst)		fileDecRef(dst);	vtUnlock(fs->elk);	return 0;}intfsVac(Fs *fs, char *name, uchar score[VtScoreSize]){	int r;	DirEntry de;	Entry e, ee;	File *f;	vtRLock(fs->elk);	f = fileOpen(fs, name);	if(f == nil){		vtRUnlock(fs->elk);		return 0;	}	if(!fileGetSources(f, &e, &ee) || !fileGetDir(f, &de)){		fileDecRef(f);		vtRUnlock(fs->elk);		return 0;	}	fileDecRef(f);	r = mkVac(fs->z, fs->blockSize, &e, &ee, &de, score);	vtRUnlock(fs->elk);	return r;}static intvtWriteBlock(VtSession *z, uchar *buf, uint n, uint type, uchar score[VtScoreSize]){	if(!vtWrite(z, score, type, buf, n))		return 0;	if(!vtSha1Check(score, buf, n))		return 0;	return 1;}intmkVac(VtSession *z, uint blockSize, Entry *pe, Entry *pee, DirEntry *pde, uchar score[VtScoreSize]){	uchar buf[8192];	int i;	uchar *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;	eee.dsize = 8192;	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;}intfsSync(Fs *fs){	vtLock(fs->elk);	fileMetaFlush(fs->file, 1);	cacheFlush(fs->cache, 1);	vtUnlock(fs->elk);	return 1;}intfsHalt(Fs *fs){	vtLock(fs->elk);	fs->halted = 1;	fileMetaFlush(fs->file, 1);	cacheFlush(fs->cache, 1);	return 1;}intfsUnhalt(Fs *fs){	if(!fs->halted)		return 0;	fs->halted = 0;	vtUnlock(fs->elk);	return 1;}intfsNextQid(Fs *fs, u64int *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;}static voidfsMetaFlush(void *a){	int rv;	Fs *fs = a;	vtRLock(fs->elk);	rv = fileMetaFlush(fs->file, 1);	vtRUnlock(fs->elk);	if(rv > 0)		cacheFlush(fs->cache, 0);}static intfsEsearch1(File *f, char *path, u32int savetime, u32int *plo){	int n, r;	DirEntry de;	DirEntryEnum *dee;	File *ff;	Entry e, ee;	char *t;	dee = deeOpen(f);	if(dee == nil)		return 0;	n = 0;	for(;;){		r = deeRead(dee, &de);		if(r <= 0)			break;		if(de.mode & ModeSnapshot){			if((ff = fileWalk(f, de.elem)) != nil){				if(fileGetSources(ff, &e, &ee))					if(de.mtime >= savetime && e.snap != 0)						if(e.snap < *plo)							*plo = e.snap;				fileDecRef(ff);			}		}		else if(de.mode & ModeDir){			if((ff = fileWalk(f, de.elem)) != nil){				t = smprint("%s/%s", path, de.elem);				n += fsEsearch1(ff, t, savetime, plo);				vtMemFree(t);				fileDecRef(ff);			}		}		deCleanup(&de);		if(r < 0)			break;	}	deeClose(dee);	return n;}static intfsEsearch(Fs *fs, char *path, u32int savetime, u32int *plo){	int n;	File *f;	DirEntry de;	f = fileOpen(fs, path);	if(f == nil)		return 0;	if(!fileGetDir(f, &de)){		fileDecRef(f);		return 0;	}	if((de.mode & ModeDir) == 0){		fileDecRef(f);		deCleanup(&de);		return 0;	}	deCleanup(&de);	n = fsEsearch1(f, path, savetime, plo);	fileDecRef(f);	return n;}voidfsSnapshotCleanup(Fs *fs, u32int age){	u32int lo;	/*	 * Find the best low epoch we can use,	 * given that we need to save all the unventied archives	 * and all the snapshots younger than age.	 */	vtRLock(fs->elk);	lo = fs->ehi;	fsEsearch(fs, "/archive", 0, &lo);	fsEsearch(fs, "/snapshot", time(0)-age*60, &lo);	vtRUnlock(fs->elk);	fsEpochLow(fs, lo);	fsSnapshotRemove(fs);}/* remove all snapshots that have expired *//* return number of directory entries remaining */static intfsRsearch1(File *f, char *s){	int n, r;	DirEntry de;	DirEntryEnum *dee;	File *ff;	char *t;	dee = deeOpen(f);	if(dee == nil)		return 0;	n = 0;	for(;;){		r = deeRead(dee, &de);		if(r <= 0)			break;		n++;		if(de.mode & ModeSnapshot){			if((ff = fileWalk(f, de.elem)) != nil)				fileDecRef(ff);			else if(strcmp(vtGetError(), ESnapOld) == 0){				if(fileClri(f, de.elem, "adm"))					n--;			}		}		else if(de.mode & ModeDir){			if((ff = fileWalk(f, de.elem)) != nil){				t = smprint("%s/%s", s, de.elem);				if(fsRsearch1(ff, t) == 0)					if(fileRemove(ff, "adm"))						n--;				vtMemFree(t);				fileDecRef(ff);			}		}		deCleanup(&de);		if(r < 0)			break;	}	deeClose(dee);	return n;}static intfsRsearch(Fs *fs, char *path){	File *f;	DirEntry de;	f = fileOpen(fs, path);	if(f == nil)		return 0;	if(!fileGetDir(f, &de)){		fileDecRef(f);		return 0;	}	if((de.mode & ModeDir) == 0){		fileDecRef(f);		deCleanup(&de);		return 0;	}	deCleanup(&de);	fsRsearch1(f, path);	fileDecRef(f);	return 1;}voidfsSnapshotRemove(Fs *fs){	vtRLock(fs->elk);	fsRsearch(fs, "/snapshot");	vtRUnlock(fs->elk);}struct Snap{	Fs *fs;	Periodic *tick;	VtLock *lk;	uint snapMinutes;	uint archMinute;	uint snapLife;	u32int lastSnap;	u32int lastArch;	u32int lastCleanup;	uint ignore;};static voidsnapEvent(void *v){	Snap *s;	u32int now, min;	Tm tm;	int need;	s = v;	now = time(0)/60;	vtLock(s->lk);	/*	 * Snapshots happen every snapMinutes minutes.	 * If we miss a snapshot (for example, because we	 * were down), we wait for the next one.	 */	if(s->snapMinutes != ~0 && s->snapMinutes != 0	&& now%s->snapMinutes==0 && now != s->lastSnap){		if(!fsSnapshot(s->fs, nil, nil, 0))			fprint(2, "fsSnapshot snap: %R\n");		s->lastSnap = now;	}	/*	 * Archival snapshots happen at archMinute.	 * If we miss an archive (for example, because we	 * were down), we do it as soon as possible.	 */	tm = *localtime(now*60);	min = tm.hour*60+tm.min;	if(s->archMinute != ~0){		need = 0;		if(min == s->archMinute && now != s->lastArch)			need = 1;		if(s->lastArch == 0){			s->lastArch = 1;			if(fsNeedArch(s->fs, s->archMinute))				need = 1;		}		if(need){			fsSnapshot(s->fs, nil, nil, 1);			s->lastArch = now;		}	}	/*	 * Snapshot cleanup happens every snaplife or every day.	 */	if(s->snapLife != ~0	&& (s->lastCleanup+s->snapLife < now || s->lastCleanup+24*60 < now)){		fsSnapshotCleanup(s->fs, s->snapLife);		s->lastCleanup = now;	}	vtUnlock(s->lk);}static Snap*snapInit(Fs *fs){	Snap *s;	s = vtMemAllocZ(sizeof(Snap));	s->fs = fs;	s->tick = periodicAlloc(snapEvent, s, 10*1000);	s->lk = vtLockAlloc();	s->snapMinutes = -1;	s->archMinute = -1;	s->snapLife = -1;	s->ignore = 5*2;	/* wait five minutes for clock to stabilize */	return s;}voidsnapGetTimes(Snap *s, u32int *arch, u32int *snap, u32int *snaplen){	if(s == nil){		*snap = -1;		*arch = -1;		*snaplen = -1;		return;	}	vtLock(s->lk);	*snap = s->snapMinutes;	*arch = s->archMinute;	*snaplen = s->snapLife;	vtUnlock(s->lk);}voidsnapSetTimes(Snap *s, u32int arch, u32int snap, u32int snaplen){	if(s == nil)		return;	vtLock(s->lk);	s->snapMinutes = snap;	s->archMinute = arch;	s->snapLife = snaplen;	vtUnlock(s->lk);}static voidsnapClose(Snap *s){	if(s == nil)		return;	periodicKill(s->tick);	vtMemFree(s);}

⌨️ 快捷键说明

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