📄 file.c
字号:
f->dir.qidMax = max; ret = fileMetaFlush2(f, nil)>=0; fileMetaUnlock(f); fileUnlock(f); return ret;}uvlongfileGetId(File *f){ /* immutable */ return f->dir.qid;}ulongfileGetMcount(File *f){ ulong mcount; fileMetaLock(f); mcount = f->dir.mcount; fileMetaUnlock(f); return mcount;}ulongfileGetMode(File *f){ ulong mode; fileMetaLock(f); mode = f->dir.mode; fileMetaUnlock(f); return mode;}intfileIsDir(File *f){ /* immutable */ return (f->dir.mode & ModeDir) != 0;}intfileIsRoot(File *f){ return f == f->fs->file;}intfileIsRoFs(File *f){ return f->fs->mode == OReadOnly;}intfileGetSize(File *f, uvlong *size){ if(!fileRLock(f)) return 0; if(!sourceLock(f->source, OReadOnly)){ fileRUnlock(f); return 0; } *size = sourceGetSize(f->source); sourceUnlock(f->source); fileRUnlock(f); return 1;}intfileMetaFlush(File *f, int rec){ File **kids, *p; int nkids; int i, rv; fileMetaLock(f); rv = fileMetaFlush2(f, nil); fileMetaUnlock(f); if(!rec || !fileIsDir(f)) return rv; if(!fileLock(f)) return rv; nkids = 0; for(p=f->down; p; p=p->next) nkids++; kids = vtMemAlloc(nkids*sizeof(File*)); i = 0; for(p=f->down; p; p=p->next){ kids[i++] = p; p->ref++; } fileUnlock(f); for(i=0; i<nkids; i++){ rv |= fileMetaFlush(kids[i], 1); fileDecRef(kids[i]); } vtMemFree(kids); return rv;}/* assumes metaLock is held */static intfileMetaFlush2(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;}static intfileMetaRemove(File *f, char *uid){ Block *b; MetaBlock mb; MetaEntry me; int i; File *up; up = f->up; fileWAccess(up, uid); fileMetaLock(f); sourceLock(up->msource, OReadWrite); b = sourceBlock(up->msource, f->boff, OReadWrite); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, up->msource->dsize)){fprint(2, "U\n"); goto Err;} if(!mbSearch(&mb, f->dir.elem, &i, &me)){fprint(2, "S\n"); goto Err;} mbDelete(&mb, i); mbPack(&mb); sourceUnlock(up->msource); blockDirty(b); blockPut(b); f->removed = 1; f->boff = NilBlock; f->dirty = 0; fileMetaUnlock(f); return 1;Err: sourceUnlock(up->msource); blockPut(b); fileMetaUnlock(f); return 0;}/* assume file is locked, assume f->msource is locked */static intfileCheckEmpty(File *f){ u32int i, n; Block *b; MetaBlock mb; Source *r; r = f->msource; n = (sourceGetSize(r)+r->dsize-1)/r->dsize; for(i=0; i<n; i++){ b = sourceBlock(r, i, OReadOnly); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, r->dsize)) goto Err; if(mb.nindex > 0){ vtSetError(ENotEmpty); goto Err; } blockPut(b); } return 1;Err: blockPut(b); return 0;}intfileRemove(File *f, char *uid){ File *ff; /* can not remove the root */ if(fileIsRoot(f)){ vtSetError(ERoot); return 0; } if(!fileLock(f)) return 0; if(f->source->mode != OReadWrite){ vtSetError(EReadOnly); goto Err1; } if(!sourceLock2(f->source, f->msource, -1)) goto Err1; if(fileIsDir(f) && !fileCheckEmpty(f)) goto Err; for(ff=f->down; ff; ff=ff->next) assert(ff->removed); sourceRemove(f->source); f->source = nil; if(f->msource){ sourceRemove(f->msource); f->msource = nil; } fileUnlock(f); if(!fileMetaRemove(f, uid)) return 0; return 1;Err: sourceUnlock(f->source); if(f->msource) sourceUnlock(f->msource);Err1: fileUnlock(f); return 0;}static intclri(File *f, char *uid){ int r; if(f == nil) return 0; if(f->up->source->mode != OReadWrite){ vtSetError(EReadOnly); fileDecRef(f); return 0; } r = fileMetaRemove(f, uid); fileDecRef(f); return r;}intfileClriPath(Fs *fs, char *path, char *uid){ return clri(_fileOpen(fs, path, 1), uid);}intfileClri(File *dir, char *elem, char *uid){ return clri(_fileWalk(dir, elem, 1), uid);}File *fileIncRef(File *vf){ fileMetaLock(vf); assert(vf->ref > 0); vf->ref++; fileMetaUnlock(vf); return vf;}intfileDecRef(File *f){ File *p, *q, **qq; if(f->up == nil){ /* never linked in */ assert(f->ref == 1); fileFree(f); return 1; } fileMetaLock(f); f->ref--; if(f->ref > 0){ fileMetaUnlock(f); return 0; } assert(f->ref == 0); assert(f->down == nil); fileMetaFlush2(f, nil); p = f->up; qq = &p->down; for(q = *qq; q; q = *qq){ if(q == f) break; qq = &q->next; } assert(q != nil); *qq = f->next; fileMetaUnlock(f); fileFree(f); fileDecRef(p); return 1;}File *fileGetParent(File *f){ if(fileIsRoot(f)) return fileIncRef(f); return fileIncRef(f->up);}DirEntryEnum *deeOpen(File *f){ DirEntryEnum *dee; File *p; if(!fileIsDir(f)){ vtSetError(ENotDir); fileDecRef(f); return nil; } /* flush out meta data */ if(!fileLock(f)) return nil; for(p=f->down; p; p=p->next) fileMetaFlush2(p, nil); fileUnlock(f); dee = vtMemAllocZ(sizeof(DirEntryEnum)); dee->file = fileIncRef(f); return dee;}static intdirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size){ Block *b; ulong bn; Entry e; int epb; epb = s->dsize/VtEntrySize; bn = elem/epb; elem -= bn*epb; b = sourceBlock(s, bn, OReadOnly); if(b == nil) goto Err; if(!entryUnpack(&e, b->data, elem)) goto Err; /* hanging entries are returned as zero size */ if(!(e.flags & VtEntryActive) || e.gen != gen) *size = 0; else *size = e.size; blockPut(b); return 1;Err: blockPut(b); return 0;}static intdeeFill(DirEntryEnum *dee){ int i, n; Source *meta, *source; MetaBlock mb; MetaEntry me; File *f; Block *b; DirEntry *de; /* clean up first */ for(i=dee->i; i<dee->n; i++) deCleanup(dee->buf+i); vtMemFree(dee->buf); dee->buf = nil; dee->i = 0; dee->n = 0; f = dee->file; source = f->source; meta = f->msource; b = sourceBlock(meta, dee->boff, OReadOnly); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, meta->dsize)) goto Err; n = mb.nindex; dee->buf = vtMemAlloc(n * sizeof(DirEntry)); for(i=0; i<n; i++){ de = dee->buf + i; meUnpack(&me, &mb, i); if(!deUnpack(de, &me)) goto Err; dee->n++; if(!(de->mode & ModeDir)) if(!dirEntrySize(source, de->entry, de->gen, &de->size)) goto Err; } dee->boff++; blockPut(b); return 1;Err: blockPut(b); return 0;}intdeeRead(DirEntryEnum *dee, DirEntry *de){ int ret, didread; File *f; u32int nb; if(dee == nil){ vtSetError("cannot happen in deeRead"); return -1; } f = dee->file; if(!fileRLock(f)) return -1; if(!sourceLock2(f->source, f->msource, OReadOnly)){ fileRUnlock(f); return -1; } nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize; didread = 0; while(dee->i >= dee->n){ if(dee->boff >= nb){ ret = 0; goto Return; } didread = 1; if(!deeFill(dee)){ ret = -1; goto Return; } } memmove(de, dee->buf + dee->i, sizeof(DirEntry)); dee->i++; ret = 1;Return: sourceUnlock(f->source); sourceUnlock(f->msource); fileRUnlock(f); if(didread) fileRAccess(f); return ret;}voiddeeClose(DirEntryEnum *dee){ int i; if(dee == nil) return; for(i=dee->i; i<dee->n; i++) deCleanup(dee->buf+i); vtMemFree(dee->buf); fileDecRef(dee->file); vtMemFree(dee);}/* * caller must lock f->source and f->msource * caller must NOT lock the source and msource * referenced by dir. */static u32intfileMetaAlloc(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;}static intchkSource(File *f){ if(f->partial) return 1; if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ vtSetError(ERemoved); return 0; } return 1;}static intfileRLock(File *f){ assert(!vtCanLock(f->fs->elk)); vtRLock(f->lk); if(!chkSource(f)){ fileRUnlock(f); return 0; } return 1;}static voidfileRUnlock(File *f){ vtRUnlock(f->lk);}static intfileLock(File *f){ assert(!vtCanLock(f->fs->elk)); vtLock(f->lk); if(!chkSource(f)){ fileUnlock(f); return 0; } return 1;}static voidfileUnlock(File *f){ vtUnlock(f->lk);}/* * f->source and f->msource must NOT be locked. * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). * We have to respect that ordering. */static voidfileMetaLock(File *f){if(f->up == nil)fprint(2, "f->elem = %s\n", f->dir.elem); assert(f->up != nil); assert(!vtCanLock(f->fs->elk)); vtLock(f->up->lk);}static voidfileMetaUnlock(File *f){ vtUnlock(f->up->lk);}/* * f->source and f->msource must NOT be locked. * see fileMetaLock. */static voidfileRAccess(File* f){ if(f->mode == OReadOnly) return; fileMetaLock(f); f->dir.atime = time(0L); f->dirty = 1; fileMetaUnlock(f);}/* * f->source and f->msource must NOT be locked. * see fileMetaLock. */static voidfileWAccess(File* f, char *mid){ if(f->mode == OReadOnly) return; fileMetaLock(f); f->dir.atime = f->dir.mtime = time(0L); if(strcmp(f->dir.mid, mid) != 0){ vtMemFree(f->dir.mid); f->dir.mid = vtStrDup(mid); } f->dir.mcount++; f->dirty = 1; fileMetaUnlock(f);/*RSC: let's try this *//*presotto - lets not if(f->up) fileWAccess(f->up, mid);*/}static intgetEntry(Source *r, Entry *e, int checkepoch){ u32int epoch; Block *b; if(r == nil){ memset(&e, 0, sizeof e); return 1; } b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly); if(b == nil) return 0; if(!entryUnpack(e, b->data, r->offset % r->epb)){ blockPut(b); return 0; } epoch = b->l.epoch; blockPut(b); if(checkepoch){ b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly); if(b){ if(b->l.epoch >= epoch) fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n", r, b->addr, b->l.epoch, r->score, epoch); blockPut(b); } } return 1;}static intsetEntry(Source *r, Entry *e){ Block *b; Entry oe; b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); if(b == nil) return 0; if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ blockPut(b); return 0; } e->gen = oe.gen; entryPack(e, b->data, r->offset % r->epb); /* BUG b should depend on the entry pointer */ blockDirty(b); blockPut(b); return 1;}/* assumes hold elk */intfileSnapshot(File *dst, File *src, u32int epoch, int doarchive){ Entry e, ee; /* add link to snapshot */ if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) return 0; e.snap = epoch; e.archive = doarchive; ee.snap = epoch; ee.archive = doarchive; if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) return 0; return 1;}intfileGetSources(File *f, Entry *e, Entry *ee){ if(!getEntry(f->source, e, 0) || !getEntry(f->msource, ee, 0)) return 0; return 1;} /* * Walk down to the block(s) containing the Entries * for f->source and f->msource, copying as we go. */intfileWalkSources(File *f){ if(f->mode == OReadOnly){ fprint(2, "readonly in fileWalkSources\n"); return 1; } if(!sourceLock2(f->source, f->msource, OReadWrite)){ fprint(2, "sourceLock2 failed in fileWalkSources\n"); return 0; } sourceUnlock(f->source); sourceUnlock(f->msource); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -