open.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #include "logfsos.h"
  2. #include "logfs.h"
  3. #include "nandfs.h"
  4. #include "local.h"
  5. char *
  6. nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata)
  7. {
  8. NandfsBlockData *blockdata = nil;
  9. long u;
  10. ulong badones, goodones;
  11. char *errmsg;
  12. long possiblebaseblock, possiblesize;
  13. long baseblock, limitblock;
  14. int ppb;
  15. if (trace > 1)
  16. print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock);
  17. if (nandfs->blockdata)
  18. return Eperm;
  19. if (base % nandfs->rawblocksize)
  20. return Ebadarg;
  21. baseblock = base / nandfs->rawblocksize;
  22. if (limit == 0)
  23. limitblock = nandfs->limitblock;
  24. else if (limit % nandfs->rawblocksize)
  25. return Ebadarg;
  26. else
  27. limitblock = limit / nandfs->rawblocksize;
  28. if (trace > 1)
  29. print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock);
  30. possiblebaseblock = 0;
  31. possiblesize = 0;
  32. /*
  33. * search for Tboot block which will reveal the parameters
  34. */
  35. nandfs->baseblock = 0;
  36. for (u = baseblock; u < limitblock; u++) {
  37. NandfsTags tags;
  38. LogfsLowLevelReadResult e;
  39. int p;
  40. int lim;
  41. lim = xcount + 3;
  42. for (p = 0; p < lim; p++) {
  43. errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e);
  44. if (errmsg)
  45. goto error;
  46. if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot)
  47. break;
  48. if (trace > 1)
  49. print("block %lud/%d: 0x%.lux\n", u, p, tags.path);
  50. switch (p) {
  51. case 1:
  52. possiblebaseblock = tags.path;
  53. break;
  54. case 2:
  55. possiblesize = tags.path;
  56. break;
  57. default:
  58. xdata[p - 3] = tags.path;
  59. break;
  60. }
  61. }
  62. if (p == lim)
  63. break;
  64. }
  65. if (u >= limitblock) {
  66. errmsg = "no valid boot blocks found";
  67. goto error;
  68. }
  69. if (possiblebaseblock < baseblock
  70. || possiblebaseblock >= limitblock
  71. || possiblebaseblock + possiblesize > limitblock
  72. || possiblesize == 0) {
  73. errmsg = "embedded parameters out of range";
  74. goto error;
  75. }
  76. baseblock = possiblebaseblock;
  77. limitblock = possiblebaseblock + possiblesize;
  78. if (trace > 0) {
  79. int x;
  80. print("nandfs filesystem detected: base %lud limit %lud",
  81. baseblock, limitblock);
  82. for (x = 0; x < xcount; x++)
  83. print(" data%d %ld", x, xdata[x]);
  84. print("\n");
  85. }
  86. blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData));
  87. if (blockdata == nil) {
  88. errmsg = Enomem;
  89. goto error;
  90. }
  91. /*
  92. * sanity check
  93. * check the partition until 10 good blocks have been found
  94. * check that bad blocks represent 10% or less
  95. */
  96. badones = goodones = 0;
  97. ppb = 1 << nandfs->ll.l2pagesperblock;
  98. for (u = baseblock; u < limitblock; u++) {
  99. LogfsLowLevelReadResult firste, laste;
  100. NandfsTags firsttags, lasttags;
  101. errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
  102. if (errmsg)
  103. goto error;
  104. errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
  105. if (errmsg)
  106. goto error;
  107. if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad)
  108. continue;
  109. if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic &&
  110. lasttags.magic == LogfsMagic)
  111. goodones++;
  112. else
  113. badones++;
  114. if (badones == 0 && goodones >= 10)
  115. break;
  116. }
  117. if (badones * 10 > goodones) {
  118. errmsg = "most likely not a Log Filesystem";
  119. goto error;
  120. }
  121. for (u = baseblock; u < limitblock; u++) {
  122. int erased, partial;
  123. LogfsLowLevelReadResult firste, laste;
  124. NandfsTags firsttags, lasttags, newtags;
  125. int markedbad;
  126. errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
  127. if (errmsg)
  128. goto error;
  129. errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
  130. if (errmsg)
  131. goto error;
  132. if (trace > 1)
  133. print("%lud: ", u);
  134. if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) {
  135. if (trace > 1)
  136. print("bad\n");
  137. blockdata[u - baseblock].tag = LogfsTbad;
  138. continue;
  139. }
  140. newtags = firsttags;
  141. erased = 0;
  142. partial = 0;
  143. if (firsttags.tag != lasttags.tag) {
  144. partial = 1;
  145. if (trace > 1)
  146. print("partially written\n");
  147. /*
  148. * partially written block
  149. * if Tboot, then it is either
  150. * a failure during logfsformat() - well, we never got started, so give up
  151. * a failure during blocktransfer() - erase it as the transfer was not completed
  152. * tell the difference by the presence of another block with the same path
  153. * if Tnone, then it's a no brainer
  154. * if anything else, leave alone
  155. */
  156. if (newtags.tag == LogfsTnone) {
  157. newtags.tag = LogfsTnone;
  158. newtags.path = NandfsPathMask;
  159. errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
  160. if (errmsg)
  161. goto error;
  162. if (markedbad) {
  163. blockdata[u - baseblock].tag = LogfsTbad;
  164. continue;
  165. }
  166. /* now erased */
  167. erased = 1;
  168. partial = 0;
  169. }
  170. }
  171. if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) {
  172. if (trace > 1)
  173. print("probably erased");
  174. /*
  175. * finding erased blocks at this stage is a rare event, so
  176. * erase again just in case
  177. */
  178. newtags.tag = LogfsTnone;
  179. newtags.path = NandfsPathMask;
  180. newtags.nerase = 1; // what do I do here?
  181. errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
  182. if (errmsg)
  183. goto error;
  184. if (markedbad) {
  185. blockdata[u - baseblock].tag = LogfsTbad;
  186. continue;
  187. }
  188. erased = 1;
  189. }
  190. if (erased) {
  191. newtags.magic = 'V';
  192. errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
  193. if (errmsg)
  194. goto error;
  195. if (markedbad) {
  196. blockdata[u - baseblock].tag = LogfsTbad;
  197. continue;
  198. }
  199. }
  200. switch (newtags.tag) {
  201. case LogfsTboot:
  202. case LogfsTnone:
  203. case LogfsTdata:
  204. case LogfsTlog:
  205. blockdata[u - baseblock].path = newtags.path;
  206. blockdata[u - baseblock].tag = newtags.tag;
  207. blockdata[u - baseblock].nerase = newtags.nerase;
  208. blockdata[u - baseblock].partial = partial;
  209. if (trace > 1)
  210. print("%s 0x%.8lux %lud\n",
  211. logfstagname(blockdata[u - baseblock].tag),
  212. blockdata[u - baseblock].path,
  213. blockdata[u - baseblock].nerase);
  214. continue;
  215. }
  216. break;
  217. }
  218. nandfs->ll.blocks = u - baseblock;
  219. nandfs->baseblock = baseblock;
  220. nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData));
  221. if (nandfs->blockdata == nil) {
  222. errmsg = Enomem;
  223. goto error;
  224. }
  225. nandfs->trace = trace;
  226. memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks);
  227. nandfsfreemem(blockdata);
  228. if (trace > 0)
  229. print("nandfsopen: success\n");
  230. return nil;
  231. error:
  232. nandfsfreemem(blockdata);
  233. return errmsg;
  234. }