10 * locking order is upwards. A thread can hold the lock for a VacFile
11 * and then acquire the lock of its parent
15 VacFs *fs; /* immutable */
17 /* meta data for file: protected by the lk in the parent */
18 int ref; /* holds this data structure up */
20 int partial; /* file was never really open */
21 int removed; /* file has been removed */
22 int dirty; /* dir is dirty with respect to meta data in block */
23 u32int boff; /* block offset within msource for this file's metadata */
24 VacDir dir; /* metadata for this file */
25 VacFile *up; /* parent file */
26 VacFile *next; /* sibling */
28 RWLock lk; /* lock for the following */
29 VtFile *source; /* actual data */
30 VtFile *msource; /* metadata for children in a directory */
31 VacFile *down; /* children */
35 static int filelock(VacFile*);
36 static u32int filemetaalloc(VacFile*, VacDir*, u32int);
37 static int filemetaflush2(VacFile*, char*);
38 static void filemetalock(VacFile*);
39 static void filemetaunlock(VacFile*);
40 static void fileraccess(VacFile*);
41 static int filerlock(VacFile*);
42 static void filerunlock(VacFile*);
43 static void fileunlock(VacFile*);
44 static void filewaccess(VacFile*, char*);
46 void mbinit(MetaBlock*, u8int*, uint, uint);
47 int mbsearch(MetaBlock*, char*, int*, MetaEntry*);
48 int mbresize(MetaBlock*, MetaEntry*, int);
49 VacFile *vdlookup(VacFile*, char*);
56 f = vtmallocz(sizeof(VacFile));
67 vtfileclose(f->source);
68 vtfileclose(f->msource);
70 memset(f, ~0, sizeof *f); /* paranoia */
75 * the file is locked already
76 * f->msource is unlocked
79 dirlookup(VacFile *f, char *elem)
91 if(vtfilelock(meta, -1) < 0)
93 nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
94 for(bo=0; bo<nb; bo++){
95 b = vtfileblock(meta, bo, VtOREAD);
98 if(mbunpack(&mb, b->data, meta->dsize) < 0)
100 if(mbsearch(&mb, elem, &i, &me) >= 0){
101 ff = filealloc(f->fs);
102 if(vdunpack(&ff->dir, &me) < 0){
125 _vacfileroot(VacFs *fs, VtFile *r)
130 VtFile *r0, *r1, *r2;
143 if(vtfilelock(r, -1) < 0)
145 r0 = vtfileopen(r, 0, fs->mode);
147 fprint(2, "r0 %p\n", r0);
150 r2 = vtfileopen(r, 2, fs->mode);
152 fprint(2, "r2 %p\n", r2);
155 * some vac files (e.g., from fossil)
156 * have an extra layer of indirection.
158 rerrstr(err, sizeof err);
159 if(!redirected && strstr(err, "not active")){
167 r1 = vtfileopen(r, 1, fs->mode);
169 fprint(2, "r1 %p\n", r1);
177 root = filealloc(fs);
187 if(vtfilelock(mr->msource, -1) < 0)
189 b = vtfileblock(mr->msource, 0, VtOREAD);
190 vtfileunlock(mr->msource);
194 if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
197 meunpack(&me, &mb, 0);
198 if(vdunpack(&root->dir, &me) < 0)
223 fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
227 if(vtfilelock(f->source, mode) < 0)
229 r = vtfileopen(f->source, offset, mode);
230 vtfileunlock(f->source);
237 if(r->dir != dir && r->mode != -1){
238 fprint(2, "fileopensource: dir mismatch %d %d\n", r->dir, dir);
249 _filewalk(VacFile *f, char *elem, int partial)
260 if(!vacfileisdir(f)){
265 if(strcmp(elem, ".") == 0){
266 return vacfileincref(f);
269 if(strcmp(elem, "..") == 0){
271 return vacfileincref(f);
272 return vacfileincref(f->up);
278 for(ff = f->down; ff; ff=ff->next){
279 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
285 ff = dirlookup(f, elem);
289 if(ff->dir.mode & ModeSnapshot)
294 * Do nothing. We're opening this file only so we can clri it.
295 * Usually the sources can't be opened, hence we won't even bother.
296 * Be VERY careful with the returned file. If you hand it to a routine
297 * expecting ff->source and/or ff->msource to be non-nil, we're
298 * likely to dereference nil. FileClri should be the only routine
302 }else if(ff->dir.mode & ModeDir){
303 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
304 ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
305 if(ff->source == nil || ff->msource == nil)
308 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
309 if(ff->source == nil)
313 /* link in and up parent ref count */
329 vacfilewalk(VacFile *f, char *elem)
331 return _filewalk(f, elem, 0);
335 _fileopen(VacFs *fs, char *path, int partial)
338 char *p, elem[VtMaxStringSize], *opath;
345 for(p = path; *p && *p != '/'; p++)
349 if(n > VtMaxStringSize){
350 werrstr("%s: element too long", EBadPath);
353 memmove(elem, path, n);
355 ff = _filewalk(f, elem, partial && *p=='\0');
357 werrstr("%.*s: %R", utfnlen(opath, p-opath), opath);
374 vacfileopen(VacFs *fs, char *path)
376 return _fileopen(fs, path, 0);
381 filesettmp(VacFile *f, int istmp)
394 if(vtfilegetentry(r, &e) < 0){
395 fprint(2, "vtfilegetentry failed (cannot happen): %r\n");
399 e.flags |= VtEntryNoArchive;
401 e.flags &= ~VtEntryNoArchive;
402 if(vtfilesetentry(r, &e) < 0){
403 fprint(2, "vtfilesetentry failed (cannot happen): %r\n");
411 vacfilecreate(VacFile *f, char *elem, ulong mode, char *uid)
423 for(ff = f->down; ff; ff=ff->next){
424 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
431 ff = dirlookup(f, elem);
438 if(pr->mode != VtORDWR){
443 if(vtfilelock2(f->source, f->msource, -1) < 0)
446 ff = filealloc(f->fs);
447 isdir = mode & ModeDir;
449 r = vtfilecreate(pr, pr->psize, pr->dsize, isdir ? VtDirType : VtDataType);
453 mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType);
459 dir->elem = vtstrdup(elem);
460 dir->entry = r->offset;
463 dir->mentry = mr->offset;
467 if(_vacfsnextqid(f->fs, &dir->qid) < 0)
469 dir->uid = vtstrdup(uid);
470 dir->gid = vtstrdup(f->dir.gid);
471 dir->mid = vtstrdup(uid);
472 dir->mtime = time(0L);
474 dir->ctime = dir->mtime;
475 dir->atime = dir->mtime;
478 ff->boff = filemetaalloc(f, dir, 0);
479 if(ff->boff == NilBlock)
482 vtfileunlock(f->source);
483 vtfileunlock(f->msource);
489 if(mode&ModeTemporary){
490 if(vtfilelock2(r, mr, -1) < 0)
501 /* link in and up parent ref count */
513 vtfileunlock(f->source);
514 vtfileunlock(f->msource);
531 vacfileblockscore(VacFile *f, u32int bn, u8int *score)
541 if(vtfilelock(f->source, VtOREAD) < 0)
546 size = vtfilegetsize(s);
547 if((uvlong)bn*dsize >= size)
549 ret = vtfileblockscore(f->source, bn, score);
552 vtfileunlock(f->source);
558 vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
563 int off, dsize, n, nn;
567 if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);
579 if(vtfilelock(f->source, VtOREAD) < 0)
584 size = vtfilegetsize(s);
589 if(cnt > size-offset)
595 b = vtfileblock(s, bn, OREAD);
604 memmove(p, b->data+off, nn);
605 memset(p+nn, 0, nn-n);
614 return p-(uchar*)buf;
625 * Changes the file block bn to be the given block score.
626 * Very sneaky. Only used by flfmt.
629 filemapblock(VacFile *f, ulong bn, uchar score[VtScoreSize], ulong tag)
639 if(f->dir.mode & ModeDir){
644 if(f->source->mode != VtORDWR){
649 if(vtfilelock(f->source, -1) < 0)
653 b = _vtfileblock(s, bn, VtORDWR, 1, tag);
657 if(vtfilegetentry(s, &e) < 0)
659 if(b->l.type == BtDir){
660 memmove(e.score, score, VtScoreSize);
661 assert(e.tag == tag || e.tag == 0);
663 e.flags |= VtEntryLocal;
664 vtentrypack(&e, b->data, f->source->offset % f->source->epb);
666 memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize);
667 /* vtblockdirty(b); */
682 vacfilesetsize(VacFile *f, uvlong size)
689 if(f->dir.mode & ModeDir){
693 if(f->source->mode != VtORDWR){
697 if(vtfilelock(f->source, -1) < 0)
699 r = vtfilesetsize(f->source, size);
700 vtfileunlock(f->source);
707 filewrite(VacFile *f, void *buf, int cnt, vlong offset, char *uid)
716 if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);
722 if(f->dir.mode & ModeDir){
727 if(f->source->mode != VtORDWR){
738 if(vtfilelock(f->source, -1) < 0)
743 eof = vtfilegetsize(s);
744 if(f->dir.mode & ModeAppend)
753 b = vtfileblock(s, bn, n<dsize?VtORDWR:VtOWRITE);
756 vtfilesetsize(s, offset);
759 memmove(b->data+off, p, n);
765 /* vtblockdirty(b); */
768 if(offset > eof && vtfilesetsize(s, offset) < 0)
772 return p-(uchar*)buf;
781 vacfilegetdir(VacFile *f, VacDir *dir)
787 vdcopy(dir, &f->dir);
790 if(!vacfileisdir(f)){
791 if(vtfilelock(f->source, VtOREAD) < 0){
795 dir->size = vtfilegetsize(f->source);
796 vtfileunlock(f->source);
804 vacfiletruncate(VacFile *f, char *uid)
814 if(f->source->mode != VtORDWR){
819 if(vtfilelock(f->source, -1) < 0){
823 if(vtfiletruncate(f->source) < 0){
824 vtfileunlock(f->source);
828 vtfileunlock(f->source);
837 vacfilesetdir(VacFile *f, VacDir *dir, char *uid)
844 /* can not set permissions for the root */
845 if(vacfileisroot(f)){
853 if(f->source->mode != VtORDWR){
861 /* check new name does not already exist */
862 if(strcmp(f->dir.elem, dir->elem) != 0){
863 for(ff = f->up->down; ff; ff=ff->next){
864 if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
870 ff = dirlookup(f->up, dir->elem);
878 if(vtfilelock2(f->source, f->msource, -1) < 0)
880 if(!vacfileisdir(f)){
881 size = vtfilegetsize(f->source);
882 if(size != dir->size){
883 if(vtfilesetsize(f->source, dir->size) < 0){
884 vtfileunlock(f->source);
886 vtfileunlock(f->msource);
889 /* commited to changing it now */
892 /* commited to changing it now */
894 if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary))
895 filesettmp(f, dir->mode&ModeTemporary);
897 vtfileunlock(f->source);
899 vtfileunlock(f->msource);
902 if(strcmp(f->dir.elem, dir->elem) != 0){
904 f->dir.elem = vtstrdup(dir->elem);
907 if(strcmp(f->dir.uid, dir->uid) != 0){
909 f->dir.uid = vtstrdup(dir->uid);
912 if(strcmp(f->dir.gid, dir->gid) != 0){
914 f->dir.gid = vtstrdup(dir->gid);
917 f->dir.mtime = dir->mtime;
918 f->dir.atime = dir->atime;
920 /*fprint(2, "mode %x %x ", f->dir.mode, dir->mode); */
921 mask = ~(ModeDir|ModeSnapshot);
922 f->dir.mode &= ~mask;
923 f->dir.mode |= mask & dir->mode;
925 /*fprint(2, "->%x\n", f->dir.mode); */
927 filemetaflush2(f, oelem);
933 filewaccess(f->up, uid);
943 vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
951 f->dir.qidoffset = offset;
953 ret = filemetaflush2(f, nil);
960 vacfilegetid(VacFile *f)
967 vacfilegetmcount(VacFile *f)
972 mcount = f->dir.mcount;
978 vacfilegetmode(VacFile *f)
989 vacfileisdir(VacFile *f)
992 return (f->dir.mode & ModeDir) != 0;
996 vacfileisroot(VacFile *f)
998 return f == f->fs->root;
1002 vacfilegetsize(VacFile *f, uvlong *size)
1004 if(filerlock(f) < 0)
1006 if(vtfilelock(f->source, VtOREAD) < 0){
1010 *size = vtfilegetsize(f->source);
1011 vtfileunlock(f->source);
1018 vacfilegetvtentry(VacFile *f, VtEntry *e)
1020 if(filerlock(f) < 0)
1022 if(vtfilelock(f->source, VtOREAD) < 0){
1026 vtfilegetentry(f->source, e);
1027 vtfileunlock(f->source);
1034 vacfilemetaflush(VacFile *f, int rec)
1041 filemetaflush2(f, nil);
1044 if(!rec || !vacfileisdir(f))
1050 for(p=f->down; p; p=p->next)
1052 kids = vtmalloc(nkids*sizeof(VacFile*));
1054 for(p=f->down; p; p=p->next){
1060 for(i=0; i<nkids; i++){
1061 vacfilemetaflush(kids[i], 1);
1062 vacfiledecref(kids[i]);
1067 /* assumes metaLock is held */
1069 filemetaflush2(VacFile *f, char *oelem)
1082 oelem = f->dir.elem;
1086 if(vtfilelock(fp->msource, -1) < 0)
1088 /* can happen if source is clri'ed out from under us */
1089 if(f->boff == NilBlock)
1091 b = vtfileblock(fp->msource, f->boff, VtORDWR);
1095 if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1097 if(mbsearch(&mb, oelem, &i, &me) < 0)
1100 n = vdsize(&f->dir);
1101 if(0)fprint(2, "old size %d new size %d\n", me.size, n);
1103 if(mbresize(&mb, &me, n) >= 0){
1104 /* fits in the block */
1105 mbdelete(&mb, i, &me);
1106 if(strcmp(f->dir.elem, oelem) != 0)
1107 mbsearch(&mb, f->dir.elem, &i, &me2);
1108 vdpack(&f->dir, &me);
1109 mbinsert(&mb, i, &me);
1111 /* vtblockdirty(b); */
1113 vtfileunlock(fp->msource);
1119 * moving entry to another block
1120 * it is feasible for the fs to crash leaving two copies
1121 * of the directory entry. This is just too much work to
1122 * fix. Given that entries are only allocated in a block that
1123 * is less than PercentageFull, most modifications of meta data
1124 * will fit within the block. i.e. this code should almost
1125 * never be executed.
1127 boff = filemetaalloc(fp, &f->dir, f->boff+1);
1128 if(boff == NilBlock){
1129 /* mbResize might have modified block */
1131 /* vtblockdirty(b); */
1134 fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
1137 /* make sure deletion goes to disk after new entry */
1138 bb = vtfileblock(fp->msource, f->boff, VtORDWR);
1139 mbdelete(&mb, i, &me);
1141 /* blockDependency(b, bb, -1, nil, nil); */
1143 /* vtblockdirty(b); */
1145 vtfileunlock(fp->msource);
1154 vtfileunlock(fp->msource);
1159 filemetaremove(VacFile *f, char *uid)
1169 filewaccess(up, uid);
1172 if(vtfilelock(up->msource, VtORDWR) < 0)
1174 b = vtfileblock(up->msource, f->boff, VtORDWR);
1178 if(mbunpack(&mb, b->data, up->msource->dsize) < 0)
1180 if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
1182 mbdelete(&mb, i, &me);
1184 vtfileunlock(up->msource);
1186 /* vtblockdirty(b); */
1197 vtfileunlock(up->msource);
1203 /* assume file is locked, assume f->msource is locked */
1205 filecheckempty(VacFile *f)
1213 n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
1215 b = vtfileblock(r, i, VtORDWR);
1218 if(mbunpack(&mb, b->data, r->dsize) < 0)
1233 vacfileremove(VacFile *f, char *muid)
1237 /* can not remove the root */
1238 if(vacfileisroot(f)){
1246 if(f->source->mode != VtORDWR){
1250 if(vtfilelock2(f->source, f->msource, -1) < 0)
1252 if(vacfileisdir(f) && filecheckempty(f)<0)
1255 for(ff=f->down; ff; ff=ff->next)
1256 assert(ff->removed);
1258 vtfileremove(f->source);
1261 vtfileremove(f->msource);
1267 if(filemetaremove(f, muid) < 0)
1273 vtfileunlock(f->source);
1275 vtfileunlock(f->msource);
1282 clri(VacFile *f, char *uid)
1288 if(f->up->source->mode != VtORDWR){
1293 r = filemetaremove(f, uid);
1299 vacfileclripath(VacFs *fs, char *path, char *uid)
1301 return clri(_fileopen(fs, path, 1), uid);
1305 vacfileclri(VacFile *dir, char *elem, char *uid)
1307 return clri(_filewalk(dir, elem, 1), uid);
1311 vacfileincref(VacFile *vf)
1314 assert(vf->ref > 0);
1321 vacfiledecref(VacFile *f)
1323 VacFile *p, *q, **qq;
1326 /* never linked in */
1327 assert(f->ref == 1);
1338 assert(f->ref == 0);
1339 assert(f->down == nil);
1341 filemetaflush2(f, nil);
1345 for(q = *qq; q; q = *qq){
1360 vacfilegetparent(VacFile *f)
1362 if(vacfileisroot(f))
1363 return vacfileincref(f);
1364 return vacfileincref(f->up);
1368 vacfilewrite(VacFile *file, void *buf, int n, vlong offset, char *muid)
1370 werrstr("read only file system");
1380 if(!vacfileisdir(f)){
1385 /* flush out meta data */
1388 for(p=f->down; p; p=p->next)
1389 filemetaflush2(p, nil);
1392 vde = vtmallocz(sizeof(VacDirEnum));
1393 vde->file = vacfileincref(f);
1399 direntrysize(VtFile *s, ulong elem, ulong gen, uvlong *size)
1406 epb = s->dsize/VtEntrySize;
1410 b = vtfileblock(s, bn, VtOREAD);
1413 if(vtentryunpack(&e, b->data, elem) < 0)
1416 /* hanging entries are returned as zero size */
1417 if(!(e.flags & VtEntryActive) || e.gen != gen)
1430 vdefill(VacDirEnum *vde)
1433 VtFile *meta, *source;
1440 /* clean up first */
1441 for(i=vde->i; i<vde->n; i++)
1442 vdcleanup(vde->buf+i);
1453 b = vtfileblock(meta, vde->boff, VtOREAD);
1456 if(mbunpack(&mb, b->data, meta->dsize) < 0)
1460 vde->buf = vtmalloc(n * sizeof(VacDir));
1464 meunpack(&me, &mb, i);
1465 if(vdunpack(de, &me) < 0)
1468 if(!(de->mode & ModeDir))
1469 if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
1481 vderead(VacDirEnum *vde, VacDir *de)
1488 if(filerlock(f) < 0)
1491 if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
1496 nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
1499 while(vde->i >= vde->n){
1500 if(vde->boff >= nb){
1505 if(vdefill(vde) < 0){
1511 memmove(de, vde->buf + vde->i, sizeof(VacDir));
1516 vtfileunlock(f->source);
1517 vtfileunlock(f->msource);
1526 vdeclose(VacDirEnum *vde)
1531 for(i=vde->i; i<vde->n; i++)
1532 vdcleanup(vde->buf+i);
1534 vacfiledecref(vde->file);
1539 * caller must lock f->source and f->msource
1540 * caller must NOT lock the source and msource
1541 * referenced by dir.
1544 filemetaalloc(VacFile *f, VacDir *dir, u32int start)
1559 nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
1563 for(bo=start; bo<nb; bo++){
1564 b = vtfileblock(ms, bo, VtORDWR);
1567 if(mbunpack(&mb, b->data, ms->dsize) < 0)
1569 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
1570 if(n <= nn && mb.nindex < mb.maxindex)
1576 /* add block to meta file */
1578 b = vtfileblock(ms, bo, VtORDWR);
1581 vtfilesetsize(ms, (nb+1)*ms->dsize);
1582 mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
1585 p = mballoc(&mb, n);
1587 /* mbAlloc might have changed block */
1589 /* vtblockdirty(b); */
1594 mbsearch(&mb, dir->elem, &i, &me);
1595 assert(me.p == nil);
1599 mbinsert(&mb, i, &me);
1602 #ifdef notdef /* XXX */
1603 /* meta block depends on super block for qid ... */
1604 bb = cacheLocal(b->c, PartSuper, 0, VtOREAD);
1605 blockDependency(b, bb, -1, nil, nil);
1608 /* ... and one or two dir entries */
1609 epb = s->dsize/VtEntrySize;
1610 bb = vtfileblock(s, dir->entry/epb, VtOREAD);
1611 blockDependency(b, bb, -1, nil, nil);
1613 if(dir->mode & ModeDir){
1614 bb = sourceBlock(s, dir->mentry/epb, VtOREAD);
1615 blockDependency(b, bb, -1, nil, nil);
1620 /* vtblockdirty(b); */
1629 chksource(VacFile *f)
1634 if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){
1642 filerlock(VacFile *f)
1644 /* assert(!canwlock(&f->fs->elk)); */
1646 if(chksource(f) < 0){
1654 filerunlock(VacFile *f)
1660 filelock(VacFile *f)
1662 /* assert(!canwlock(&f->fs->elk)); */
1664 if(chksource(f) < 0){
1672 fileunlock(VacFile *f)
1678 * f->source and f->msource must NOT be locked.
1679 * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
1680 * We have to respect that ordering.
1683 filemetalock(VacFile *f)
1685 assert(f->up != nil);
1686 /* assert(!canwlock(&f->fs->elk)); */
1691 filemetaunlock(VacFile *f)
1693 wunlock(&f->up->lk);
1697 * f->source and f->msource must NOT be locked.
1701 fileraccess(VacFile* f)
1703 if(f->mode == VtOREAD)
1707 f->dir.atime = time(0L);
1713 * f->source and f->msource must NOT be locked.
1717 filewaccess(VacFile* f, char *mid)
1719 if(f->mode == VtOREAD)
1723 f->dir.atime = f->dir.mtime = time(0L);
1724 if(strcmp(f->dir.mid, mid) != 0){
1726 f->dir.mid = vtstrdup(mid);
1732 /*RSC: let's try this */
1733 /*presotto - lets not
1735 filewaccess(f->up, mid);
1741 markCopied(Block *b)
1746 if(globalToLocal(b->score) == NilBlock)
1749 if(!(b->l.state & BsCopied)){
1751 * We need to record that there are now pointers in
1752 * b that are not unique to b. We do this by marking
1753 * b as copied. Since we don't return the label block,
1754 * the caller can't get the dependencies right. So we have
1755 * to flush the block ourselves. This is a rare occurrence.
1758 l.state |= BsCopied;
1759 lb = _blockSetLabel(b, &l);
1761 while(!blockWrite(lb)){
1762 fprint(2, "getEntry: could not write label block\n");
1765 while(lb->iostate != BioClean && lb->iostate != BioDirty){
1766 assert(lb->iostate == BioWriting);
1767 vtSleep(lb->ioready);
1769 if(lb->iostate == BioDirty)
1776 getEntry(VtFile *r, Entry *e, int mark)
1781 memset(&e, 0, sizeof e);
1785 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtOREAD);
1788 if(!entryUnpack(e, b->data, r->offset % r->epb)){
1800 setEntry(Source *r, Entry *e)
1805 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtORDWR);
1806 if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
1809 if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
1814 entryPack(e, b->data, r->offset % r->epb);
1816 /* BUG b should depend on the entry pointer */
1819 /* vtblockdirty(b); */
1824 /* assumes hold elk */
1826 fileSnapshot(VacFile *dst, VacFile *src, u32int epoch, int doarchive)
1830 /* add link to snapshot */
1831 if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
1835 e.archive = doarchive;
1837 ee.archive = doarchive;
1839 if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
1845 fileGetSources(VacFile *f, Entry *e, Entry *ee, int mark)
1847 if(!getEntry(f->source, e, mark)
1848 || !getEntry(f->msource, ee, mark))
1854 fileWalkSources(VacFile *f)
1856 if(f->mode == VtOREAD)
1858 if(!sourceLock2(f->source, f->msource, VtORDWR))
1860 vtfileunlock(f->source);
1861 vtfileunlock(f->msource);