replay.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #include "logfsos.h"
  2. #include "logfs.h"
  3. #include "local.h"
  4. #include "fcall.h"
  5. static void
  6. maxpath(LogfsServer *server, ulong p)
  7. {
  8. if(p > server->path)
  9. server->path = p;
  10. }
  11. static char *
  12. recreate(LogfsServer *server, LogMessage *s, int *ok)
  13. {
  14. Entry *parent;
  15. char *errmsg;
  16. Entry *e;
  17. Path *p;
  18. parent = logfspathmapfinde(server->pathmap, s->path);
  19. if(parent == nil)
  20. return "can't find parent";
  21. if(logfspathmapfindentry(server->pathmap, s->u.create.newpath) != nil){
  22. Entry *d = logfspathmapfinde(server->pathmap, s->u.create.newpath);
  23. if(d == nil)
  24. print("existing was nil\n");
  25. else{
  26. print("existing: name=%q d=%d path=%8.8llux uid=%q gid=%q perm=%#uo\n",
  27. d->name, d->deadandgone, d->qid.path, d->uid, d->gid, d->perm);
  28. }
  29. return "duplicate path";
  30. }
  31. if((parent->qid.type & QTDIR) == 0)
  32. return Enotdir;
  33. errmsg = logfsentrynew(server, 1, s->u.create.newpath, parent,
  34. s->u.create.name, s->u.create.uid, s->u.create.gid, s->u.create.mtime, s->u.create.uid,
  35. s->u.create.perm, s->u.create.cvers, 0, &e);
  36. if(errmsg) {
  37. *ok = 0;
  38. return errmsg;
  39. }
  40. /* p guaranteed to be non null */
  41. errmsg = logfspathmapnewentry(server->pathmap, s->u.create.newpath, e, &p);
  42. if(errmsg) {
  43. logfsfreemem(e);
  44. *ok = 0;
  45. return errmsg;
  46. }
  47. e->next = parent->u.dir.list;
  48. parent->u.dir.list = e;
  49. return nil;
  50. }
  51. static char *
  52. reremove(LogfsServer *server, LogMessage *s, int *ok)
  53. {
  54. Entry *oe;
  55. Entry *parent;
  56. Entry **ep;
  57. Entry *e;
  58. char *ustmuid;
  59. USED(ok);
  60. oe = logfspathmapfinde(server->pathmap, s->path);
  61. if(oe == nil)
  62. return logfseunknownpath;
  63. parent = oe->parent;
  64. if(parent == oe)
  65. return "tried to remove root";
  66. if((parent->qid.type & QTDIR) == 0)
  67. return Enotdir;
  68. if((oe->qid.type & QTDIR) != 0 && oe->u.dir.list)
  69. return logfsenotempty;
  70. for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
  71. if(e == oe)
  72. break;
  73. if(e == nil)
  74. return logfseinternal;
  75. ustmuid = logfsisustadd(server->is, s->u.remove.muid);
  76. if(ustmuid == nil)
  77. return Enomem;
  78. parent->mtime = s->u.remove.mtime;
  79. parent->muid = ustmuid;
  80. logfspathmapdeleteentry(server->pathmap, s->path);
  81. *ep = e->next;
  82. if(e->inuse > 1) {
  83. print("replay: entry inuse > 1\n");
  84. e->inuse = 1;
  85. }
  86. logfsentryclunk(e);
  87. return nil;
  88. }
  89. static char *
  90. retrunc(LogfsServer *server, LogMessage *s, int *ok)
  91. {
  92. Entry *e;
  93. char *ustmuid;
  94. USED(ok);
  95. e = logfspathmapfinde(server->pathmap, s->path);
  96. if(e == nil)
  97. return logfseunknownpath;
  98. if((e->qid.type & QTDIR) != 0)
  99. return Eperm;
  100. if(e->u.file.cvers >= s->u.trunc.cvers)
  101. return "old news";
  102. ustmuid = logfsisustadd(server->is, s->u.trunc.muid);
  103. if(ustmuid == nil)
  104. return Enomem;
  105. e->muid = ustmuid;
  106. e->mtime = s->u.trunc.mtime;
  107. e->qid.vers++;
  108. e->u.file.cvers = s->u.trunc.cvers;
  109. /*
  110. * zap all extents
  111. */
  112. logfsextentlistreset(e->u.file.extent);
  113. e->u.file.length = 0;
  114. return nil;
  115. }
  116. static char *
  117. rewrite(LogfsServer *server, LogMessage *s, int *ok)
  118. {
  119. Entry *e;
  120. char *ustmuid;
  121. Extent extent;
  122. char *errmsg;
  123. USED(ok);
  124. e = logfspathmapfinde(server->pathmap, s->path);
  125. if(e == nil)
  126. return logfseunknownpath;
  127. if((e->qid.type & QTDIR) != 0)
  128. return Eperm;
  129. if(e->u.file.cvers != s->u.write.cvers)
  130. return nil;
  131. ustmuid = logfsisustadd(server->is, s->u.write.muid);
  132. if(ustmuid == nil)
  133. return Enomem;
  134. extent.min = s->u.write.offset;
  135. extent.max = s->u.write.offset + s->u.write.count;
  136. extent.flashaddr = s->u.write.flashaddr;
  137. errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil);
  138. if(errmsg)
  139. return errmsg;
  140. e->mtime = s->u.write.mtime;
  141. e->muid = ustmuid;
  142. if(extent.max > e->u.file.length)
  143. e->u.file.length = extent.max;
  144. /* TODO forsyth increments vers here; not sure whether necessary */
  145. return nil;
  146. }
  147. static char *
  148. rewstat(LogfsServer *server, LogMessage *s, int *ok)
  149. {
  150. Entry *e;
  151. char *errmsg;
  152. char *cname, *ustgid, *ustmuid;
  153. char *ustuid;
  154. USED(ok);
  155. e = logfspathmapfinde(server->pathmap, s->path);
  156. if(e == nil)
  157. return logfseunknownpath;
  158. cname = nil;
  159. ustuid = nil;
  160. ustgid = nil;
  161. ustmuid = nil;
  162. if(s->u.wstat.name) {
  163. cname = logfsstrdup(s->u.wstat.name);
  164. if(cname == nil) {
  165. memerror:
  166. errmsg = Enomem;
  167. goto fail;
  168. }
  169. }
  170. if(s->u.wstat.uid) {
  171. ustuid = logfsisustadd(server->is, s->u.wstat.uid);
  172. if(ustuid == nil)
  173. goto memerror;
  174. }
  175. if(s->u.wstat.gid) {
  176. ustgid = logfsisustadd(server->is, s->u.wstat.gid);
  177. if(ustgid == nil)
  178. goto memerror;
  179. }
  180. if(s->u.wstat.muid) {
  181. ustmuid = logfsisustadd(server->is, s->u.wstat.muid);
  182. if(ustmuid == nil)
  183. goto memerror;
  184. }
  185. if(cname) {
  186. logfsfreemem(e->name);
  187. e->name = cname;
  188. cname = nil;
  189. }
  190. if(ustuid)
  191. e->uid = ustuid;
  192. if(ustgid)
  193. e->gid = ustgid;
  194. if(ustmuid)
  195. e->muid = ustmuid;
  196. if(s->u.wstat.perm != ~0)
  197. e->perm = (e->perm & DMDIR) | (s->u.wstat.perm & ~DMDIR);
  198. if(s->u.wstat.mtime != ~0)
  199. e->mtime = s->u.wstat.mtime;
  200. errmsg = nil;
  201. fail:
  202. logfsfreemem(cname);
  203. return errmsg;
  204. }
  205. static char *
  206. replayblock(LogfsServer *server, LogSegment *seg, uchar *buf, long i, int *pagep, int disableerrors)
  207. {
  208. int page;
  209. LogfsLowLevel *ll = server->ll;
  210. LogfsLowLevelReadResult llrr;
  211. ushort size;
  212. LogMessage s;
  213. int ppb = 1 << ll->l2pagesperblock;
  214. int pagesize = 1 << ll->l2pagesize;
  215. for(page = 0; page < ppb; page++) {
  216. uchar *p, *bufend;
  217. char *errmsg = (*ll->readpagerange)(ll, buf, seg->blockmap[i], page, 0, pagesize, &llrr);
  218. if(errmsg)
  219. return errmsg;
  220. if(llrr != LogfsLowLevelReadResultOk)
  221. logfsserverreplacelogblock(server, seg, i);
  222. /* ignore failure to replace block */
  223. if(server->trace > 1)
  224. print("replaying seq %ld block %ld page %d\n", i, seg->blockmap[i], page);
  225. p = buf;
  226. if(*p == 0xff)
  227. break;
  228. bufend = p + pagesize;
  229. while(p < bufend) {
  230. int ok = 1;
  231. size = logfsconvM2S(p, bufend - p, &s);
  232. if(size == 0)
  233. return "parse failure";
  234. if(server->trace > 1) {
  235. print(">> ");
  236. logfsdumpS(&s);
  237. print("\n");
  238. }
  239. if(s.type == LogfsLogTend)
  240. break;
  241. switch(s.type) {
  242. case LogfsLogTstart:
  243. break;
  244. case LogfsLogTcreate:
  245. maxpath(server, s.path);
  246. maxpath(server, s.u.create.newpath);
  247. errmsg = recreate(server, &s, &ok);
  248. break;
  249. case LogfsLogTtrunc:
  250. maxpath(server, s.path);
  251. errmsg = retrunc(server, &s, &ok);
  252. break;
  253. case LogfsLogTremove:
  254. maxpath(server, s.path);
  255. errmsg = reremove(server, &s, &ok);
  256. break;
  257. case LogfsLogTwrite:
  258. maxpath(server, s.path);
  259. errmsg = rewrite(server, &s, &ok);
  260. break;
  261. case LogfsLogTwstat:
  262. maxpath(server, s.path);
  263. errmsg = rewstat(server, &s, &ok);
  264. break;
  265. default:
  266. return "bad tag in log page";
  267. }
  268. if(!ok)
  269. return errmsg;
  270. if(errmsg && !disableerrors){
  271. print("bad replay: %s\n", errmsg);
  272. print("on: "); logfsdumpS(&s); print("\n");
  273. }
  274. p += size;
  275. }
  276. }
  277. *pagep = page;
  278. return nil;
  279. }
  280. static int
  281. map(void *magic, Extent *x, int hole)
  282. {
  283. LogfsServer *server;
  284. LogfsLowLevel *ll;
  285. long seq;
  286. int page;
  287. int offset;
  288. Pageset mask;
  289. DataBlock *db;
  290. if(hole || (x->flashaddr & LogAddr) != 0)
  291. return 1;
  292. server = magic;
  293. ll = server->ll;
  294. logfsflashaddr2spo(server, x->flashaddr, &seq, &page, &offset);
  295. if(seq >= server->ndatablocks || (db = server->datablock + seq)->block < 0) {
  296. print("huntfordata: seq %ld invalid\n", seq);
  297. return 1;
  298. }
  299. mask = logfsdatapagemask((x->max - x->min + offset + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize, page);
  300. //print("mask 0x%.8ux free 0x%.8ux dirty 0x%.8ux\n", mask, db->free, db->dirty);
  301. if((db->free & mask) != mask)
  302. print("huntfordata: data referenced more than once: block %ld(%ld) free 0x%.8llux mask 0x%.8llux\n",
  303. seq, db->block, (u64int)db->free, (u64int)mask);
  304. db->free &= ~mask;
  305. db->dirty |= mask;
  306. return 1;
  307. }
  308. static void
  309. huntfordatainfile(LogfsServer *server, Entry *e)
  310. {
  311. logfsextentlistwalk(e->u.file.extent, map, server);
  312. }
  313. static void
  314. huntfordataindir(LogfsServer *server, Entry *pe)
  315. {
  316. Entry *e;
  317. for(e = pe->u.dir.list; e; e = e->next)
  318. if(e->qid.type & QTDIR)
  319. huntfordataindir(server, e);
  320. else
  321. huntfordatainfile(server, e);
  322. }
  323. char *
  324. logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock)
  325. {
  326. uchar *buf;
  327. long i;
  328. int page;
  329. char *errmsg;
  330. if(seg == nil || seg->curblockindex < 0)
  331. return nil;
  332. buf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
  333. if(buf == nil)
  334. return Enomem;
  335. for(i = 0; i <= seg->curblockindex; i++) {
  336. errmsg = replayblock(server, seg, buf, i, &page, disableerrorsforfirstblock);
  337. disableerrorsforfirstblock = 0;
  338. if(errmsg) {
  339. print("logfsreplay: error: %s\n", errmsg);
  340. goto fail;
  341. }
  342. }
  343. /*
  344. * if the last block ended early, restart at the first free page
  345. */
  346. if(page < (1 << server->ll->l2pagesperblock))
  347. seg->curpage = page;
  348. errmsg = nil;
  349. fail:
  350. logfsfreemem(buf);
  351. return errmsg;
  352. }
  353. void
  354. logfsreplayfinddata(LogfsServer *server)
  355. {
  356. huntfordataindir(server, &server->root);
  357. if(server->trace > 0) {
  358. long i;
  359. DataBlock *db;
  360. for(i = 0, db = server->datablock; i < server->ndatablocks; i++, db++) {
  361. logfsfreeanddirtydatablockcheck(server, i);
  362. if(db->block >= 0)
  363. print("%4ld: free 0x%.8llux dirty 0x%.8llux\n", i, (u64int)server->datablock[i].free, (u64int)server->datablock[i].dirty);
  364. }
  365. }
  366. }