sweep.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "logfsos.h"
  2. #include "logfs.h"
  3. #include "local.h"
  4. enum {
  5. ThrowAway,
  6. Keep,
  7. Repack,
  8. Error,
  9. };
  10. #define setaction(a) if(*actionp < (a)) *actionp = a
  11. #define REPACK setaction(Repack)
  12. #define KEEP setaction(Keep)
  13. #define OPTCOPYEX(name, etag, stag) \
  14. if(e->etag != s->stag) { \
  15. s->stag = e->etag; \
  16. REPACK; \
  17. }
  18. #define OPTSTRCOPYEX(name, etag, stag) \
  19. if(strcmp(e->etag, s->stag) != 0) { \
  20. s->stag = e->etag; \
  21. REPACK; \
  22. }
  23. #define OPTCOPY(name, tag, sunion) OPTCOPYEX(name, tag, u.sunion.tag)
  24. #define OPTSTRCOPY(name, tag, sunion) OPTSTRCOPYEX(name, tag, u.sunion.tag)
  25. static char *
  26. sweepcreate(LogfsServer *server, LogMessage *s, int *actionp)
  27. {
  28. Entry *pe, *e;
  29. e = logfspathmapfinde(server->pathmap, s->u.create.newpath);
  30. if(e == nil)
  31. /* file no longer exists */
  32. return nil;
  33. pe = logfspathmapfinde(server->pathmap, s->path);
  34. if(pe == nil)
  35. /* file exists but parent doesn't - not good, but can continue */
  36. return "parent missing";
  37. if((pe->perm & DMDIR) == 0 || (e->perm & DMDIR) != (s->u.create.perm & DMDIR))
  38. /* parent must be a directory, and
  39. * the directory mode cannot change
  40. */
  41. return logfseinternal;
  42. if((e->perm & DMDIR) == 0) {
  43. OPTCOPYEX("cvers", u.file.cvers, u.create.cvers);
  44. }
  45. OPTSTRCOPY("name", name, create);
  46. OPTCOPY("mtime", mtime, create);
  47. OPTCOPY("perm", perm, create);
  48. OPTSTRCOPY("uid", uid, create);
  49. OPTSTRCOPY("gid", gid, create);
  50. KEEP;
  51. return nil;
  52. }
  53. static char *
  54. sweepwrite(LogfsServer *server, LogMessage *s, int readoffset, Entry **ep, int *trimp, int *actionp)
  55. {
  56. Entry *e;
  57. Extent extent;
  58. Extent *ext;
  59. *ep = nil;
  60. e = logfspathmapfinde(server->pathmap, s->path);
  61. if(e == nil)
  62. /* gone, gone */
  63. return nil;
  64. if(e->perm & DMDIR)
  65. return logfseinternal;
  66. if(e->u.file.cvers != s->u.write.cvers)
  67. /* trunced more recently */
  68. return nil;
  69. extent.min = s->u.write.offset;
  70. extent.max = extent.min + s->u.write.count;
  71. extent.flashaddr = s->u.write.flashaddr;
  72. ext = logfsextentlistmatch(e->u.file.extent, &extent);
  73. if(ext == nil)
  74. return nil;
  75. if(s->u.write.data) {
  76. /*
  77. * trim the front of the data so that when fixing up extents,
  78. * flashaddr refers to the first byte
  79. */
  80. int offset;
  81. logfsflashaddr2o(server, ext->flashaddr, &offset);
  82. *trimp = offset - readoffset;
  83. *ep = e;
  84. }
  85. KEEP;
  86. return nil;
  87. }
  88. typedef struct FixupState {
  89. LogfsServer *server;
  90. int oldoffset;
  91. u32int newflashaddr;
  92. } FixupState;
  93. static int
  94. fixup(void *magic, Extent *e)
  95. {
  96. FixupState *state = magic;
  97. int offset;
  98. logfsflashaddr2o(state->server, e->flashaddr, &offset);
  99. e->flashaddr = state->newflashaddr + (offset - state->oldoffset);
  100. return 1;
  101. }
  102. static char *
  103. sweepblock(LogfsServer *server, uchar *buf)
  104. {
  105. char *errmsg;
  106. LogSegment *active = server->activelog;
  107. LogSegment *swept = server->sweptlog;
  108. int pagesize, ppb, page;
  109. LogfsLowLevel *ll = server->ll;
  110. LogfsLowLevelReadResult llrr;
  111. int markedbad;
  112. long oblock;
  113. if(active == nil)
  114. return nil;
  115. if(swept == nil) {
  116. errmsg = logfslogsegmentnew(server, loggensucc(active->gen), &server->sweptlog);
  117. if(errmsg)
  118. return errmsg;
  119. swept = server->sweptlog;
  120. }
  121. /*
  122. * if this is last block in the active log, flush it, so that the read of the last page works
  123. */
  124. if(active->unsweptblockindex == active->curblockindex)
  125. logfslogsegmentflush(server, 1);
  126. ppb = (1 << ll->l2pagesperblock);
  127. pagesize = (1 << ll->l2pagesize);
  128. for(page = 0; page < ppb; page++) {
  129. uchar *p, *bufend;
  130. errmsg = (*ll->readpagerange)(ll, buf, active->blockmap[active->unsweptblockindex], page, 0, pagesize, &llrr);
  131. if(errmsg)
  132. goto fail;
  133. if(llrr != LogfsLowLevelReadResultOk)
  134. logfsserverreplacelogblock(server, active, active->unsweptblockindex);
  135. p = buf;
  136. if(*p == 0xff)
  137. break;
  138. bufend = p + pagesize;
  139. while(p < bufend) {
  140. int action;
  141. uint size;
  142. LogMessage s;
  143. Entry *e;
  144. int trim;
  145. size = logfsconvM2S(p, bufend - p, &s);
  146. if(size == 0)
  147. return "parse failure";
  148. if(server->trace > 1) {
  149. print("A>> ");
  150. logfsdumpS(&s);
  151. print("\n");
  152. }
  153. if(s.type == LogfsLogTend)
  154. break;
  155. action = ThrowAway;
  156. switch(s.type) {
  157. case LogfsLogTstart:
  158. break;
  159. case LogfsLogTcreate:
  160. errmsg = sweepcreate(server, &s, &action);
  161. break;
  162. case LogfsLogTremove:
  163. /* always obsolete; might check that path really doesn't exist */
  164. break;
  165. case LogfsLogTtrunc:
  166. /* always obsolete, unless collecting out of order */
  167. break;
  168. case LogfsLogTwrite:
  169. errmsg = sweepwrite(server, &s, s.u.write.data ? s.u.write.data - buf : 0, &e, &trim, &action);
  170. break;
  171. case LogfsLogTwstat:
  172. /* always obsolete, unless collecting out of order */
  173. break;
  174. default:
  175. return "bad tag in log page";
  176. }
  177. if(action == Error)
  178. return errmsg;
  179. if(errmsg)
  180. print("bad sweep: %s\n", errmsg);
  181. if(action == Keep)
  182. action = Repack; /* input buffer has been wrecked, so can't just copy it */
  183. if(action == Keep) {
  184. /* write 'size' bytes to log */
  185. errmsg = logfslogbytes(server, 0, p, size);
  186. if(errmsg)
  187. goto fail;
  188. }
  189. else if(action == Repack) {
  190. /* TODO - handle writes */
  191. if(s.type == LogfsLogTwrite && s.u.write.data) {
  192. FixupState state;
  193. errmsg = logfslogwrite(server, 0, s.path, s.u.write.offset + trim, s.u.write.count - trim,
  194. s.u.write.mtime, s.u.write.cvers,
  195. s.u.write.muid, s.u.write.data + trim, &state.newflashaddr);
  196. if(errmsg == nil && s.u.write.data != nil) {
  197. Extent extent;
  198. /* TODO - deal with a failure to write the changes */
  199. state.oldoffset = s.u.write.data - buf + trim;
  200. state.server = server;
  201. extent.min = s.u.write.offset;
  202. extent.max = extent.min + s.u.write.count;
  203. extent.flashaddr = s.u.write.flashaddr;
  204. logfsextentlistmatchall(e->u.file.extent, fixup, &state, &extent);
  205. }
  206. }
  207. else
  208. errmsg = logfslog(server, 0, &s);
  209. if(errmsg)
  210. goto fail;
  211. }
  212. p += size;
  213. }
  214. }
  215. /*
  216. * this log block is no longer needed
  217. */
  218. oblock = active->blockmap[active->unsweptblockindex++];
  219. errmsg = logfsbootfettleblock(server->lb, oblock, LogfsTnone, ~0, &markedbad);
  220. if(errmsg)
  221. goto fail;
  222. if(active->unsweptblockindex > active->curblockindex) {
  223. /*
  224. * the activelog is now empty, so make the sweptlog the active one
  225. */
  226. logfslogsegmentfree(&active);
  227. server->activelog = swept;
  228. server->sweptlog = nil;
  229. swept->dirty = 0;
  230. }
  231. return nil;
  232. fail:
  233. return errmsg;
  234. }
  235. char *
  236. logfsserverlogsweep(LogfsServer *server, int justone, int *didsomething)
  237. {
  238. uchar *buf;
  239. char *errmsg;
  240. /*
  241. * TODO - is it even worth doing?
  242. */
  243. *didsomething = 0;
  244. if(!server->activelog->dirty)
  245. return nil;
  246. buf = logfsrealloc(nil, (1 << server->ll->l2pagesize));
  247. if(buf == nil)
  248. return Enomem;
  249. errmsg = nil;
  250. while(server->activelog->unsweptblockindex <= server->activelog->curblockindex) {
  251. errmsg = sweepblock(server, buf);
  252. if(errmsg)
  253. break;
  254. if(server->sweptlog == nil || justone)
  255. break;
  256. }
  257. logfsfreemem(buf);
  258. *didsomething = 1;
  259. return errmsg;
  260. }