replace.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #include "logfsos.h"
  2. #include "logfs.h"
  3. #include "local.h"
  4. #include "fcall.h"
  5. static char *
  6. copypages(LogfsServer *server, long newb, long oldb, Pageset copymask, LogfsLowLevelReadResult *llrrp, int *markedbadp)
  7. {
  8. char *errmsg;
  9. int page;
  10. LogfsLowLevel *ll;
  11. int ppb;
  12. int pagesize;
  13. uchar *buf;
  14. if(copymask == 0)
  15. return nil;
  16. ll = server->ll;
  17. ppb = 1 << ll->l2pagesperblock;
  18. pagesize = 1 << ll->l2pagesize;
  19. *markedbadp = 0;
  20. *llrrp = LogfsLowLevelReadResultOk;
  21. errmsg = nil;
  22. buf = logfsrealloc(nil, 1 << ll->l2pagesize);
  23. if(buf == nil)
  24. return Enomem;
  25. for(page = ppb - 1; page >= 0; page--) {
  26. Pageset m;
  27. m = logfsdatapagemask(1, page);
  28. if(copymask & m) {
  29. LogfsLowLevelReadResult llrr;
  30. if(server->trace > 1)
  31. print("copypages read page %d\n", page);
  32. errmsg = (*ll->readpagerange)(ll, buf, oldb, page, 0, pagesize, &llrr);
  33. if(errmsg != nil)
  34. break;
  35. if(llrr > *llrrp)
  36. *llrrp = llrr;
  37. if(server->trace > 1)
  38. print("copypages write page %d\n", page);
  39. errmsg = (*ll->writepage)(ll, buf, newb, page);
  40. if(errmsg) {
  41. if(strcmp(errmsg, Eio) == 0) {
  42. (*ll->markblockbad)(ll, newb);
  43. *markedbadp = 1;
  44. }
  45. break;
  46. }
  47. if(server->trace > 1)
  48. print("copypages end page %d\n", page);
  49. }
  50. }
  51. logfsfreemem(buf);
  52. return errmsg;
  53. }
  54. char *
  55. logfsservercopyactivedata(LogfsServer *server, long newb, long oldblockindex, int forcepage0, LogfsLowLevelReadResult *llrrp, int *markedbadp)
  56. {
  57. LogfsLowLevel *ll = server->ll;
  58. ulong newpath;
  59. DataBlock *ob;
  60. char *errmsg;
  61. Pageset copymask;
  62. ob = server->datablock + oldblockindex;
  63. copymask = ~ob->free;
  64. if(forcepage0)
  65. copymask |= logfsdatapagemask(1, 0);
  66. if(server->trace > 1)
  67. print("copyactivedata %ld: (%ld -> %ld)\n", oldblockindex, ob->block, newb);
  68. newpath = mkdatapath(dataseqof(ob->path), copygensucc(copygenof(ob->path)));
  69. (*ll->setblocktag)(ll, newb, LogfsTdata);
  70. (*ll->setblockpath)(ll, newb, newpath);
  71. errmsg = copypages(server, newb, ob->block, copymask, llrrp, markedbadp);
  72. if(errmsg)
  73. return errmsg;
  74. /*
  75. * anything not copied is now not dirty
  76. */
  77. ob->dirty &= copymask;
  78. ob->block = newb;
  79. ob->path = newpath;
  80. return nil;
  81. }
  82. /*
  83. * unconditionally replace a datablock, and mark the old one bad
  84. * NB: if page 0 is apparently unused, force it to be copied, and mark
  85. * it free and dirty afterwards
  86. */
  87. char *
  88. logfsserverreplacedatablock(LogfsServer *server, long index)
  89. {
  90. long newb;
  91. LogfsLowLevel *ll = server->ll;
  92. newb = logfsfindfreeblock(ll, AllocReasonReplace);
  93. /* TODO - recover space by scavenging other blocks, or recycling the log */
  94. while(newb >= 0) {
  95. char *errmsg;
  96. LogfsLowLevelReadResult llrr;
  97. long oldblock;
  98. int markedbad;
  99. DataBlock *db;
  100. db = server->datablock + index;
  101. oldblock = db->block;
  102. errmsg = logfsservercopyactivedata(server, newb, index, 1, &llrr, &markedbad);
  103. if(errmsg) {
  104. if(!markedbad)
  105. return errmsg;
  106. newb = logfsfindfreeblock(ll, AllocReasonReplace);
  107. continue;
  108. }
  109. (*ll->markblockbad)(ll, oldblock);
  110. return nil;
  111. }
  112. return logfsefullreplacing;
  113. }
  114. char *
  115. logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index)
  116. {
  117. ulong opath;
  118. LogfsLowLevel *ll = server->ll;
  119. long oldb = seg->blockmap[index];
  120. opath = (*ll->getblockpath)(ll, oldb);
  121. for(;;) {
  122. long newb;
  123. int pages;
  124. char *errmsg;
  125. LogfsLowLevelReadResult llrr;
  126. int markedbad;
  127. newb = logfsfindfreeblock(ll, AllocReasonReplace);
  128. if(newb < 0)
  129. return "full replacing log block";
  130. /* TODO - scavenge data space for a spare block */
  131. (*ll->setblocktag)(ll, newb, LogfsTlog);
  132. (*ll->setblockpath)(ll, newb, mklogpath(seg->gen, index, copygensucc(copygenof(opath))));
  133. if(index == seg->curblockindex)
  134. pages = seg->curpage;
  135. else
  136. pages = 1 << server->ll->l2pagesperblock;
  137. errmsg = copypages(server, newb, oldb, logfsdatapagemask(pages, 0), &llrr, &markedbad);
  138. if(errmsg == nil) {
  139. (*ll->markblockbad)(ll, seg->blockmap[index]);
  140. seg->blockmap[index] = newb;
  141. return nil;
  142. }
  143. if(!markedbad)
  144. return errmsg;
  145. }
  146. }
  147. char *
  148. logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long index)
  149. {
  150. if(seg)
  151. return logfsserverreplacelogblock(server, seg, index);
  152. else
  153. return logfsserverreplacedatablock(server, index);
  154. }