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 + -
显示快捷键?