123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- #include "logfsos.h"
- #include "logfs.h"
- #include "local.h"
- #include "fcall.h"
- static void
- maxpath(LogfsServer *server, ulong p)
- {
- if(p > server->path)
- server->path = p;
- }
- static char *
- recreate(LogfsServer *server, LogMessage *s, int *ok)
- {
- Entry *parent;
- char *errmsg;
- Entry *e;
- Path *p;
- parent = logfspathmapfinde(server->pathmap, s->path);
- if(parent == nil)
- return "can't find parent";
- if(logfspathmapfindentry(server->pathmap, s->u.create.newpath) != nil){
- Entry *d = logfspathmapfinde(server->pathmap, s->u.create.newpath);
- if(d == nil)
- print("existing was nil\n");
- else{
- print("existing: name=%q d=%d path=%8.8llux uid=%q gid=%q perm=%#uo\n",
- d->name, d->deadandgone, d->qid.path, d->uid, d->gid, d->perm);
- }
- return "duplicate path";
- }
- if((parent->qid.type & QTDIR) == 0)
- return Enotdir;
- errmsg = logfsentrynew(server, 1, s->u.create.newpath, parent,
- s->u.create.name, s->u.create.uid, s->u.create.gid, s->u.create.mtime, s->u.create.uid,
- s->u.create.perm, s->u.create.cvers, 0, &e);
- if(errmsg) {
- *ok = 0;
- return errmsg;
- }
- /* p guaranteed to be non null */
- errmsg = logfspathmapnewentry(server->pathmap, s->u.create.newpath, e, &p);
- if(errmsg) {
- logfsfreemem(e);
- *ok = 0;
- return errmsg;
- }
- e->next = parent->u.dir.list;
- parent->u.dir.list = e;
- return nil;
- }
- static char *
- reremove(LogfsServer *server, LogMessage *s, int *ok)
- {
- Entry *oe;
- Entry *parent;
- Entry **ep;
- Entry *e;
- char *ustmuid;
- USED(ok);
- oe = logfspathmapfinde(server->pathmap, s->path);
- if(oe == nil)
- return logfseunknownpath;
- parent = oe->parent;
- if(parent == oe)
- return "tried to remove root";
- if((parent->qid.type & QTDIR) == 0)
- return Enotdir;
- if((oe->qid.type & QTDIR) != 0 && oe->u.dir.list)
- return logfsenotempty;
- for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
- if(e == oe)
- break;
- if(e == nil)
- return logfseinternal;
- ustmuid = logfsisustadd(server->is, s->u.remove.muid);
- if(ustmuid == nil)
- return Enomem;
- parent->mtime = s->u.remove.mtime;
- parent->muid = ustmuid;
- logfspathmapdeleteentry(server->pathmap, s->path);
- *ep = e->next;
- if(e->inuse > 1) {
- print("replay: entry inuse > 1\n");
- e->inuse = 1;
- }
- logfsentryclunk(e);
- return nil;
- }
- static char *
- retrunc(LogfsServer *server, LogMessage *s, int *ok)
- {
- Entry *e;
- char *ustmuid;
- USED(ok);
- e = logfspathmapfinde(server->pathmap, s->path);
- if(e == nil)
- return logfseunknownpath;
- if((e->qid.type & QTDIR) != 0)
- return Eperm;
- if(e->u.file.cvers >= s->u.trunc.cvers)
- return "old news";
- ustmuid = logfsisustadd(server->is, s->u.trunc.muid);
- if(ustmuid == nil)
- return Enomem;
- e->muid = ustmuid;
- e->mtime = s->u.trunc.mtime;
- e->qid.vers++;
- e->u.file.cvers = s->u.trunc.cvers;
- /*
- * zap all extents
- */
- logfsextentlistreset(e->u.file.extent);
- e->u.file.length = 0;
- return nil;
- }
- static char *
- rewrite(LogfsServer *server, LogMessage *s, int *ok)
- {
- Entry *e;
- char *ustmuid;
- Extent extent;
- char *errmsg;
- USED(ok);
- e = logfspathmapfinde(server->pathmap, s->path);
- if(e == nil)
- return logfseunknownpath;
- if((e->qid.type & QTDIR) != 0)
- return Eperm;
- if(e->u.file.cvers != s->u.write.cvers)
- return nil;
- ustmuid = logfsisustadd(server->is, s->u.write.muid);
- if(ustmuid == nil)
- return Enomem;
- extent.min = s->u.write.offset;
- extent.max = s->u.write.offset + s->u.write.count;
- extent.flashaddr = s->u.write.flashaddr;
- errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil);
- if(errmsg)
- return errmsg;
- e->mtime = s->u.write.mtime;
- e->muid = ustmuid;
- if(extent.max > e->u.file.length)
- e->u.file.length = extent.max;
- /* TODO forsyth increments vers here; not sure whether necessary */
- return nil;
- }
- static char *
- rewstat(LogfsServer *server, LogMessage *s, int *ok)
- {
- Entry *e;
- char *errmsg;
- char *cname, *ustgid, *ustmuid;
- char *ustuid;
- USED(ok);
- e = logfspathmapfinde(server->pathmap, s->path);
- if(e == nil)
- return logfseunknownpath;
- cname = nil;
- ustuid = nil;
- ustgid = nil;
- ustmuid = nil;
- if(s->u.wstat.name) {
- cname = logfsstrdup(s->u.wstat.name);
- if(cname == nil) {
- memerror:
- errmsg = Enomem;
- goto fail;
- }
- }
- if(s->u.wstat.uid) {
- ustuid = logfsisustadd(server->is, s->u.wstat.uid);
- if(ustuid == nil)
- goto memerror;
- }
- if(s->u.wstat.gid) {
- ustgid = logfsisustadd(server->is, s->u.wstat.gid);
- if(ustgid == nil)
- goto memerror;
- }
- if(s->u.wstat.muid) {
- ustmuid = logfsisustadd(server->is, s->u.wstat.muid);
- if(ustmuid == nil)
- goto memerror;
- }
- if(cname) {
- logfsfreemem(e->name);
- e->name = cname;
- cname = nil;
- }
- if(ustuid)
- e->uid = ustuid;
- if(ustgid)
- e->gid = ustgid;
- if(ustmuid)
- e->muid = ustmuid;
- if(s->u.wstat.perm != ~0)
- e->perm = (e->perm & DMDIR) | (s->u.wstat.perm & ~DMDIR);
- if(s->u.wstat.mtime != ~0)
- e->mtime = s->u.wstat.mtime;
- errmsg = nil;
- fail:
- logfsfreemem(cname);
- return errmsg;
- }
- static char *
- replayblock(LogfsServer *server, LogSegment *seg, uchar *buf, long i, int *pagep, int disableerrors)
- {
- int page;
- LogfsLowLevel *ll = server->ll;
- LogfsLowLevelReadResult llrr;
- ushort size;
- LogMessage s;
- int ppb = 1 << ll->l2pagesperblock;
- int pagesize = 1 << ll->l2pagesize;
- for(page = 0; page < ppb; page++) {
- uchar *p, *bufend;
- char *errmsg = (*ll->readpagerange)(ll, buf, seg->blockmap[i], page, 0, pagesize, &llrr);
- if(errmsg)
- return errmsg;
- if(llrr != LogfsLowLevelReadResultOk)
- logfsserverreplacelogblock(server, seg, i);
- /* ignore failure to replace block */
- if(server->trace > 1)
- print("replaying seq %ld block %ld page %d\n", i, seg->blockmap[i], page);
- p = buf;
- if(*p == 0xff)
- break;
- bufend = p + pagesize;
- while(p < bufend) {
- int ok = 1;
- size = logfsconvM2S(p, bufend - p, &s);
- if(size == 0)
- return "parse failure";
- if(server->trace > 1) {
- print(">> ");
- logfsdumpS(&s);
- print("\n");
- }
- if(s.type == LogfsLogTend)
- break;
- switch(s.type) {
- case LogfsLogTstart:
- break;
- case LogfsLogTcreate:
- maxpath(server, s.path);
- maxpath(server, s.u.create.newpath);
- errmsg = recreate(server, &s, &ok);
- break;
- case LogfsLogTtrunc:
- maxpath(server, s.path);
- errmsg = retrunc(server, &s, &ok);
- break;
- case LogfsLogTremove:
- maxpath(server, s.path);
- errmsg = reremove(server, &s, &ok);
- break;
- case LogfsLogTwrite:
- maxpath(server, s.path);
- errmsg = rewrite(server, &s, &ok);
- break;
- case LogfsLogTwstat:
- maxpath(server, s.path);
- errmsg = rewstat(server, &s, &ok);
- break;
- default:
- return "bad tag in log page";
- }
- if(!ok)
- return errmsg;
- if(errmsg && !disableerrors){
- print("bad replay: %s\n", errmsg);
- print("on: "); logfsdumpS(&s); print("\n");
- }
- p += size;
- }
- }
- *pagep = page;
- return nil;
- }
- static int
- map(void *magic, Extent *x, int hole)
- {
- LogfsServer *server;
- LogfsLowLevel *ll;
- long seq;
- int page;
- int offset;
- Pageset mask;
- DataBlock *db;
- if(hole || (x->flashaddr & LogAddr) != 0)
- return 1;
- server = magic;
- ll = server->ll;
- logfsflashaddr2spo(server, x->flashaddr, &seq, &page, &offset);
- if(seq >= server->ndatablocks || (db = server->datablock + seq)->block < 0) {
- print("huntfordata: seq %ld invalid\n", seq);
- return 1;
- }
- mask = logfsdatapagemask((x->max - x->min + offset + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize, page);
- //print("mask 0x%.8ux free 0x%.8ux dirty 0x%.8ux\n", mask, db->free, db->dirty);
- if((db->free & mask) != mask)
- print("huntfordata: data referenced more than once: block %ld(%ld) free 0x%.8llux mask 0x%.8llux\n",
- seq, db->block, (u64int)db->free, (u64int)mask);
- db->free &= ~mask;
- db->dirty |= mask;
- return 1;
- }
- static void
- huntfordatainfile(LogfsServer *server, Entry *e)
- {
- logfsextentlistwalk(e->u.file.extent, map, server);
- }
- static void
- huntfordataindir(LogfsServer *server, Entry *pe)
- {
- Entry *e;
- for(e = pe->u.dir.list; e; e = e->next)
- if(e->qid.type & QTDIR)
- huntfordataindir(server, e);
- else
- huntfordatainfile(server, e);
- }
- char *
- logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock)
- {
- uchar *buf;
- long i;
- int page;
- char *errmsg;
- if(seg == nil || seg->curblockindex < 0)
- return nil;
- buf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
- if(buf == nil)
- return Enomem;
- for(i = 0; i <= seg->curblockindex; i++) {
- errmsg = replayblock(server, seg, buf, i, &page, disableerrorsforfirstblock);
- disableerrorsforfirstblock = 0;
- if(errmsg) {
- print("logfsreplay: error: %s\n", errmsg);
- goto fail;
- }
- }
- /*
- * if the last block ended early, restart at the first free page
- */
- if(page < (1 << server->ll->l2pagesperblock))
- seg->curpage = page;
- errmsg = nil;
- fail:
- logfsfreemem(buf);
- return errmsg;
- }
- void
- logfsreplayfinddata(LogfsServer *server)
- {
- huntfordataindir(server, &server->root);
- if(server->trace > 0) {
- long i;
- DataBlock *db;
- for(i = 0, db = server->datablock; i < server->ndatablocks; i++, db++) {
- logfsfreeanddirtydatablockcheck(server, i);
- if(db->block >= 0)
- print("%4ld: free 0x%.8llux dirty 0x%.8llux\n", i, (u64int)server->datablock[i].free, (u64int)server->datablock[i].dirty);
- }
- }
- }
|