spiffs_check.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. /*
  2. * spiffs_check.c
  3. *
  4. * Contains functionality for checking file system consistency
  5. * and mending problems.
  6. * Three levels of consistency checks are implemented:
  7. *
  8. * Look up consistency
  9. * Checks if indices in lookup pages are coherent with page headers
  10. * Object index consistency
  11. * Checks if there are any orphaned object indices (missing object index headers).
  12. * If an object index is found but not its header, the object index is deleted.
  13. * This is critical for the following page consistency check.
  14. * Page consistency
  15. * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
  16. *
  17. *
  18. * Created on: Jul 7, 2013
  19. * Author: petera
  20. */
  21. #include "spiffs.h"
  22. #include "spiffs_nucleus.h"
  23. #if !SPIFFS_READ_ONLY
  24. #if SPIFFS_HAL_CALLBACK_EXTRA
  25. #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
  26. do { \
  27. if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
  28. } while (0)
  29. #else
  30. #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
  31. do { \
  32. if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
  33. } while (0)
  34. #endif
  35. //---------------------------------------
  36. // Look up consistency
  37. // searches in the object indices and returns the referenced page index given
  38. // the object id and the data span index
  39. // destroys fs->lu_work
  40. static s32_t spiffs_object_get_data_page_index_reference(
  41. spiffs *fs,
  42. spiffs_obj_id obj_id,
  43. spiffs_span_ix data_spix,
  44. spiffs_page_ix *pix,
  45. spiffs_page_ix *objix_pix) {
  46. s32_t res;
  47. // calculate object index span index for given data page span index
  48. spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  49. // find obj index for obj id and span index
  50. res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);
  51. SPIFFS_CHECK_RES(res);
  52. // load obj index entry
  53. u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);
  54. if (objix_spix == 0) {
  55. // get referenced page from object index header
  56. addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);
  57. } else {
  58. // get referenced page from object index
  59. addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);
  60. }
  61. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
  62. return res;
  63. }
  64. // copies page contents to a new page
  65. static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {
  66. s32_t res;
  67. res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);
  68. SPIFFS_CHECK_RES(res);
  69. res = spiffs_phys_cpy(fs, 0,
  70. SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),
  71. SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
  72. SPIFFS_DATA_PAGE_SIZE(fs));
  73. SPIFFS_CHECK_RES(res);
  74. return res;
  75. }
  76. // rewrites the object index for given object id and replaces the
  77. // data page index to a new page index
  78. static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {
  79. s32_t res;
  80. spiffs_block_ix bix;
  81. int entry;
  82. spiffs_page_ix free_pix;
  83. obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
  84. // find free entry
  85. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  86. SPIFFS_CHECK_RES(res);
  87. free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  88. // calculate object index span index for given data page span index
  89. spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  90. if (objix_spix == 0) {
  91. // calc index in index header
  92. entry = data_spix;
  93. } else {
  94. // calc entry in index
  95. entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
  96. }
  97. // load index
  98. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  99. 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
  100. SPIFFS_CHECK_RES(res);
  101. spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
  102. // be ultra safe, double check header against provided data
  103. if (objix_p_hdr->obj_id != obj_id) {
  104. spiffs_page_delete(fs, free_pix);
  105. return SPIFFS_ERR_CHECK_OBJ_ID_MISM;
  106. }
  107. if (objix_p_hdr->span_ix != objix_spix) {
  108. spiffs_page_delete(fs, free_pix);
  109. return SPIFFS_ERR_CHECK_SPIX_MISM;
  110. }
  111. if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |
  112. SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=
  113. (SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {
  114. spiffs_page_delete(fs, free_pix);
  115. return SPIFFS_ERR_CHECK_FLAGS_BAD;
  116. }
  117. // rewrite in mem
  118. if (objix_spix == 0) {
  119. ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
  120. } else {
  121. ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
  122. }
  123. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  124. 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
  125. SPIFFS_CHECK_RES(res);
  126. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  127. 0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),
  128. sizeof(spiffs_obj_id),
  129. (u8_t *)&obj_id);
  130. SPIFFS_CHECK_RES(res);
  131. res = spiffs_page_delete(fs, objix_pix);
  132. return res;
  133. }
  134. // deletes an object just by marking object index header as deleted
  135. static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
  136. spiffs_page_ix objix_hdr_pix;
  137. s32_t res;
  138. res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
  139. if (res == SPIFFS_ERR_NOT_FOUND) {
  140. return SPIFFS_OK;
  141. }
  142. SPIFFS_CHECK_RES(res);
  143. u8_t flags = 0xff;
  144. #if SPIFFS_NO_BLIND_WRITES
  145. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
  146. 0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
  147. sizeof(flags), &flags);
  148. SPIFFS_CHECK_RES(res);
  149. #endif
  150. flags &= ~SPIFFS_PH_FLAG_IXDELE;
  151. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  152. 0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
  153. sizeof(flags), &flags);
  154. return res;
  155. }
  156. // validates the given look up entry
  157. static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
  158. spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
  159. (void)cur_block;
  160. (void)cur_entry;
  161. u8_t delete_page = 0;
  162. s32_t res = SPIFFS_OK;
  163. spiffs_page_ix objix_pix;
  164. spiffs_page_ix ref_pix;
  165. // check validity, take actions
  166. if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
  167. ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
  168. // look up entry deleted / free but used in page header
  169. SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix);
  170. *reload_lu = 1;
  171. delete_page = 1;
  172. if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
  173. // header says data page
  174. // data page can be removed if not referenced by some object index
  175. res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
  176. if (res == SPIFFS_ERR_NOT_FOUND) {
  177. // no object with this id, so remove page safely
  178. res = SPIFFS_OK;
  179. } else {
  180. SPIFFS_CHECK_RES(res);
  181. if (ref_pix == cur_pix) {
  182. // data page referenced by object index but deleted in lu
  183. // copy page to new place and re-write the object index to new place
  184. spiffs_page_ix new_pix;
  185. res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
  186. SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
  187. SPIFFS_CHECK_RES(res);
  188. *reload_lu = 1;
  189. SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix);
  190. res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
  191. if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
  192. // index bad also, cannot mend this file
  193. SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
  194. res = spiffs_page_delete(fs, new_pix);
  195. SPIFFS_CHECK_RES(res);
  196. res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
  197. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
  198. } else {
  199. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
  200. }
  201. SPIFFS_CHECK_RES(res);
  202. }
  203. }
  204. } else {
  205. // header says index page
  206. // index page can be removed if other index with same obj_id and spanix is found
  207. res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);
  208. if (res == SPIFFS_ERR_NOT_FOUND) {
  209. // no such index page found, check for a data page amongst page headers
  210. // lu cannot be trusted
  211. res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
  212. if (res == SPIFFS_OK) { // ignore other errors
  213. // got a data page also, assume lu corruption only, rewrite to new page
  214. spiffs_page_ix new_pix;
  215. res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
  216. SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
  217. SPIFFS_CHECK_RES(res);
  218. *reload_lu = 1;
  219. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
  220. }
  221. } else {
  222. SPIFFS_CHECK_RES(res);
  223. }
  224. }
  225. }
  226. if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
  227. // look up entry used
  228. if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
  229. SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id);
  230. delete_page = 1;
  231. if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
  232. (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
  233. (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
  234. // page deleted or not finalized, just remove it
  235. } else {
  236. if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
  237. // if data page, check for reference to this page
  238. res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
  239. if (res == SPIFFS_ERR_NOT_FOUND) {
  240. // no object with this id, so remove page safely
  241. res = SPIFFS_OK;
  242. } else {
  243. SPIFFS_CHECK_RES(res);
  244. // if found, rewrite page with object id, update index, and delete current
  245. if (ref_pix == cur_pix) {
  246. spiffs_page_ix new_pix;
  247. res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
  248. SPIFFS_CHECK_RES(res);
  249. res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
  250. if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
  251. // index bad also, cannot mend this file
  252. SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
  253. res = spiffs_page_delete(fs, new_pix);
  254. SPIFFS_CHECK_RES(res);
  255. res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
  256. *reload_lu = 1;
  257. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
  258. }
  259. SPIFFS_CHECK_RES(res);
  260. }
  261. }
  262. } else {
  263. // else if index, check for other pages with both obj_id's and spanix
  264. spiffs_page_ix objix_pix_lu, objix_pix_ph;
  265. // see if other object index page exists for lookup obj id and span index
  266. res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);
  267. if (res == SPIFFS_ERR_NOT_FOUND) {
  268. res = SPIFFS_OK;
  269. objix_pix_lu = 0;
  270. }
  271. SPIFFS_CHECK_RES(res);
  272. // see if other object index exists for page header obj id and span index
  273. res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);
  274. if (res == SPIFFS_ERR_NOT_FOUND) {
  275. res = SPIFFS_OK;
  276. objix_pix_ph = 0;
  277. }
  278. SPIFFS_CHECK_RES(res);
  279. // if both obj_id's found, just delete current
  280. if (objix_pix_ph == 0 || objix_pix_lu == 0) {
  281. // otherwise try finding first corresponding data pages
  282. spiffs_page_ix data_pix_lu, data_pix_ph;
  283. // see if other data page exists for look up obj id and span index
  284. res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
  285. if (res == SPIFFS_ERR_NOT_FOUND) {
  286. res = SPIFFS_OK;
  287. objix_pix_lu = 0;
  288. }
  289. SPIFFS_CHECK_RES(res);
  290. // see if other data page exists for page header obj id and span index
  291. res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
  292. if (res == SPIFFS_ERR_NOT_FOUND) {
  293. res = SPIFFS_OK;
  294. objix_pix_ph = 0;
  295. }
  296. SPIFFS_CHECK_RES(res);
  297. spiffs_page_header new_ph;
  298. new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
  299. new_ph.span_ix = p_hdr->span_ix;
  300. spiffs_page_ix new_pix;
  301. if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
  302. (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
  303. // got a data page for page header obj id
  304. // rewrite as obj_id_ph
  305. new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
  306. res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
  307. SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix);
  308. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
  309. SPIFFS_CHECK_RES(res);
  310. *reload_lu = 1;
  311. } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
  312. (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
  313. // got a data page for look up obj id
  314. // rewrite as obj_id_lu
  315. new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
  316. SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id);
  317. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
  318. res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
  319. SPIFFS_CHECK_RES(res);
  320. *reload_lu = 1;
  321. } else {
  322. // cannot safely do anything
  323. SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n");
  324. }
  325. }
  326. }
  327. }
  328. } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
  329. ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
  330. SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix);
  331. spiffs_page_ix data_pix, objix_pix_d;
  332. // see if other data page exists for given obj id and span index
  333. res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);
  334. if (res == SPIFFS_ERR_NOT_FOUND) {
  335. res = SPIFFS_OK;
  336. data_pix = 0;
  337. }
  338. SPIFFS_CHECK_RES(res);
  339. // see if other object index exists for given obj id and span index
  340. res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);
  341. if (res == SPIFFS_ERR_NOT_FOUND) {
  342. res = SPIFFS_OK;
  343. objix_pix_d = 0;
  344. }
  345. SPIFFS_CHECK_RES(res);
  346. delete_page = 1;
  347. // if other data page exists and object index exists, just delete page
  348. if (data_pix && objix_pix_d) {
  349. SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n");
  350. } else
  351. // if only data page exists, make this page index
  352. if (data_pix && objix_pix_d == 0) {
  353. SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
  354. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
  355. spiffs_page_header new_ph;
  356. spiffs_page_ix new_pix;
  357. new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
  358. new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
  359. new_ph.span_ix = p_hdr->span_ix;
  360. res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
  361. SPIFFS_CHECK_RES(res);
  362. res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
  363. SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
  364. SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
  365. SPIFFS_CHECK_RES(res);
  366. } else
  367. // if only index exists, make data page
  368. if (data_pix == 0 && objix_pix_d) {
  369. SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
  370. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
  371. spiffs_page_header new_ph;
  372. spiffs_page_ix new_pix;
  373. new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
  374. new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  375. new_ph.span_ix = p_hdr->span_ix;
  376. res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
  377. SPIFFS_CHECK_RES(res);
  378. res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
  379. SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
  380. SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
  381. SPIFFS_CHECK_RES(res);
  382. } else {
  383. // if nothing exists, we cannot safely make a decision - delete
  384. }
  385. }
  386. else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
  387. SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix);
  388. delete_page = 1;
  389. } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
  390. SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix);
  391. // page can be removed if not referenced by object index
  392. *reload_lu = 1;
  393. res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
  394. if (res == SPIFFS_ERR_NOT_FOUND) {
  395. // no object with this id, so remove page safely
  396. res = SPIFFS_OK;
  397. delete_page = 1;
  398. } else {
  399. SPIFFS_CHECK_RES(res);
  400. if (ref_pix != cur_pix) {
  401. SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n");
  402. delete_page = 1;
  403. } else {
  404. // page referenced by object index but not final
  405. // just finalize
  406. SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
  407. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
  408. u8_t flags = 0xff;
  409. #if SPIFFS_NO_BLIND_WRITES
  410. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
  411. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
  412. sizeof(flags), &flags);
  413. SPIFFS_CHECK_RES(res);
  414. #endif
  415. flags &= ~SPIFFS_PH_FLAG_FINAL;
  416. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  417. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
  418. sizeof(flags), &flags);
  419. }
  420. }
  421. }
  422. }
  423. if (delete_page) {
  424. SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
  425. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
  426. res = spiffs_page_delete(fs, cur_pix);
  427. SPIFFS_CHECK_RES(res);
  428. }
  429. return res;
  430. }
  431. static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
  432. const void *user_const_p, void *user_var_p) {
  433. (void)user_const_p;
  434. (void)user_var_p;
  435. s32_t res = SPIFFS_OK;
  436. spiffs_page_header p_hdr;
  437. spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
  438. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
  439. (cur_block * 256)/fs->block_count, 0);
  440. // load header
  441. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  442. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
  443. SPIFFS_CHECK_RES(res);
  444. int reload_lu = 0;
  445. res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
  446. SPIFFS_CHECK_RES(res);
  447. if (res == SPIFFS_OK) {
  448. return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
  449. }
  450. return res;
  451. }
  452. // Scans all object look up. For each entry, corresponding page header is checked for validity.
  453. // If an object index header page is found, this is also checked
  454. s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
  455. (void)check_all_objects;
  456. s32_t res = SPIFFS_OK;
  457. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
  458. res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
  459. if (res == SPIFFS_VIS_END) {
  460. res = SPIFFS_OK;
  461. }
  462. if (res != SPIFFS_OK) {
  463. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
  464. }
  465. CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
  466. return res;
  467. }
  468. //---------------------------------------
  469. // Page consistency
  470. // Scans all pages (except lu pages), reserves 4 bits in working memory for each page
  471. // bit 0: 0 == FREE|DELETED, 1 == USED
  472. // bit 1: 0 == UNREFERENCED, 1 == REFERENCED
  473. // bit 2: 0 == NOT_INDEX, 1 == INDEX
  474. // bit 3: unused
  475. // A consistent file system will have only pages being
  476. // * x000 free, unreferenced, not index
  477. // * x011 used, referenced only once, not index
  478. // * x101 used, unreferenced, index
  479. // The working memory might not fit all pages so several scans might be needed
  480. static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
  481. const u32_t bits = 4;
  482. const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
  483. s32_t res = SPIFFS_OK;
  484. spiffs_page_ix pix_offset = 0;
  485. // for each range of pages fitting into work memory
  486. while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
  487. // set this flag to abort all checks and rescan the page range
  488. u8_t restart = 0;
  489. memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  490. spiffs_block_ix cur_block = 0;
  491. // build consistency bitmap for id range traversing all blocks
  492. while (!restart && cur_block < fs->block_count) {
  493. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
  494. (pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
  495. ((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
  496. 0);
  497. // traverse each page except for lookup pages
  498. spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
  499. while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
  500. //if ((cur_pix & 0xff) == 0)
  501. // SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
  502. // cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
  503. // read header
  504. spiffs_page_header p_hdr;
  505. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  506. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
  507. SPIFFS_CHECK_RES(res);
  508. u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
  509. const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);
  510. const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;
  511. if (within_range &&
  512. (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
  513. // used
  514. fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));
  515. }
  516. if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
  517. (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
  518. (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
  519. // found non-deleted index
  520. if (within_range) {
  521. fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));
  522. }
  523. // load non-deleted index
  524. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  525. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
  526. SPIFFS_CHECK_RES(res);
  527. // traverse index for referenced pages
  528. spiffs_page_ix *object_page_index;
  529. spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
  530. int entries;
  531. int i;
  532. spiffs_span_ix data_spix_offset;
  533. if (p_hdr.span_ix == 0) {
  534. // object header page index
  535. entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
  536. data_spix_offset = 0;
  537. object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
  538. } else {
  539. // object page index
  540. entries = SPIFFS_OBJ_IX_LEN(fs);
  541. data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
  542. object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
  543. }
  544. // for all entries in index
  545. for (i = 0; !restart && i < entries; i++) {
  546. spiffs_page_ix rpix = object_page_index[i];
  547. u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
  548. if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))
  549. || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
  550. // bad reference
  551. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n",
  552. rpix, cur_pix);
  553. // check for data page elsewhere
  554. spiffs_page_ix data_pix;
  555. res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  556. data_spix_offset + i, 0, &data_pix);
  557. if (res == SPIFFS_ERR_NOT_FOUND) {
  558. res = SPIFFS_OK;
  559. data_pix = 0;
  560. }
  561. SPIFFS_CHECK_RES(res);
  562. if (data_pix == 0) {
  563. // if not, allocate free page
  564. spiffs_page_header new_ph;
  565. new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
  566. new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  567. new_ph.span_ix = data_spix_offset + i;
  568. res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
  569. SPIFFS_CHECK_RES(res);
  570. SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix);
  571. }
  572. // remap index
  573. SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix);
  574. res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
  575. data_spix_offset + i, data_pix, cur_pix);
  576. if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
  577. // index bad also, cannot mend this file
  578. SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res);
  579. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
  580. // delete file
  581. res = spiffs_page_delete(fs, cur_pix);
  582. } else {
  583. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
  584. }
  585. SPIFFS_CHECK_RES(res);
  586. restart = 1;
  587. } else if (rpix_within_range) {
  588. // valid reference
  589. // read referenced page header
  590. spiffs_page_header rp_hdr;
  591. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  592. 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
  593. SPIFFS_CHECK_RES(res);
  594. // cross reference page header check
  595. if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
  596. rp_hdr.span_ix != data_spix_offset + i ||
  597. (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
  598. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
  599. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n",
  600. rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
  601. rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
  602. // try finding correct page
  603. spiffs_page_ix data_pix;
  604. res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  605. data_spix_offset + i, rpix, &data_pix);
  606. if (res == SPIFFS_ERR_NOT_FOUND) {
  607. res = SPIFFS_OK;
  608. data_pix = 0;
  609. }
  610. SPIFFS_CHECK_RES(res);
  611. if (data_pix == 0) {
  612. // not found, this index is badly borked
  613. SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id);
  614. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
  615. res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
  616. SPIFFS_CHECK_RES(res);
  617. break;
  618. } else {
  619. // found it, so rewrite index
  620. SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n",
  621. data_pix, cur_pix, p_hdr.obj_id);
  622. res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
  623. if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
  624. // index bad also, cannot mend this file
  625. SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
  626. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
  627. res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
  628. } else {
  629. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
  630. }
  631. SPIFFS_CHECK_RES(res);
  632. restart = 1;
  633. }
  634. }
  635. else {
  636. // mark rpix as referenced
  637. const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);
  638. const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;
  639. if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {
  640. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n",
  641. rpix, cur_pix);
  642. // Here, we should have fixed all broken references - getting this means there
  643. // must be multiple files with same object id. Only solution is to delete
  644. // the object which is referring to this page
  645. SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n",
  646. p_hdr.obj_id, cur_pix);
  647. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
  648. res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
  649. SPIFFS_CHECK_RES(res);
  650. // extra precaution, delete this page also
  651. res = spiffs_page_delete(fs, cur_pix);
  652. SPIFFS_CHECK_RES(res);
  653. restart = 1;
  654. }
  655. fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));
  656. }
  657. }
  658. } // for all index entries
  659. } // found index
  660. // next page
  661. cur_pix++;
  662. }
  663. // next block
  664. cur_block++;
  665. }
  666. // check consistency bitmap
  667. if (!restart) {
  668. spiffs_page_ix objix_pix;
  669. spiffs_page_ix rpix;
  670. u32_t byte_ix;
  671. u8_t bit_ix;
  672. for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
  673. for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {
  674. u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
  675. spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;
  676. // 000 ok - free, unreferenced, not index
  677. if (bitmask == 0x1) {
  678. // 001
  679. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix);
  680. u8_t rewrite_ix_to_this = 0;
  681. u8_t delete_page = 0;
  682. // check corresponding object index entry
  683. spiffs_page_header p_hdr;
  684. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  685. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
  686. SPIFFS_CHECK_RES(res);
  687. res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
  688. &rpix, &objix_pix);
  689. if (res == SPIFFS_OK) {
  690. if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
  691. // pointing to a bad page altogether, rewrite index to this
  692. rewrite_ix_to_this = 1;
  693. SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix);
  694. } else {
  695. // pointing to something else, check what
  696. spiffs_page_header rp_hdr;
  697. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  698. 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
  699. SPIFFS_CHECK_RES(res);
  700. if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
  701. ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
  702. (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
  703. // pointing to something else valid, just delete this page then
  704. SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix);
  705. delete_page = 1;
  706. } else {
  707. // pointing to something weird, update index to point to this page instead
  708. if (rpix != cur_pix) {
  709. SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix,
  710. (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
  711. (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
  712. (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
  713. (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
  714. cur_pix);
  715. rewrite_ix_to_this = 1;
  716. } else {
  717. // should not happen, destined for fubar
  718. }
  719. }
  720. }
  721. } else if (res == SPIFFS_ERR_NOT_FOUND) {
  722. SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix);
  723. delete_page = 1;
  724. res = SPIFFS_OK;
  725. }
  726. if (rewrite_ix_to_this) {
  727. // if pointing to invalid page, redirect index to this page
  728. SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n",
  729. p_hdr.obj_id, p_hdr.span_ix, cur_pix);
  730. res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
  731. if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
  732. // index bad also, cannot mend this file
  733. SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
  734. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
  735. res = spiffs_page_delete(fs, cur_pix);
  736. SPIFFS_CHECK_RES(res);
  737. res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
  738. } else {
  739. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
  740. }
  741. SPIFFS_CHECK_RES(res);
  742. restart = 1;
  743. continue;
  744. } else if (delete_page) {
  745. SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
  746. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
  747. res = spiffs_page_delete(fs, cur_pix);
  748. }
  749. SPIFFS_CHECK_RES(res);
  750. }
  751. if (bitmask == 0x2) {
  752. // 010
  753. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix);
  754. // no op, this should be taken care of when checking valid references
  755. }
  756. // 011 ok - busy, referenced, not index
  757. if (bitmask == 0x4) {
  758. // 100
  759. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix);
  760. // this should never happen, major fubar
  761. }
  762. // 101 ok - busy, unreferenced, index
  763. if (bitmask == 0x6) {
  764. // 110
  765. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix);
  766. // no op, this should be taken care of when checking valid references
  767. }
  768. if (bitmask == 0x7) {
  769. // 111
  770. SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix);
  771. // no op, this should be taken care of when checking valid references
  772. }
  773. }
  774. }
  775. }
  776. SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart);
  777. // next page range
  778. if (!restart) {
  779. pix_offset += pages_per_scan;
  780. }
  781. } // while page range not reached end
  782. return res;
  783. }
  784. // Checks consistency amongst all pages and fixes irregularities
  785. s32_t spiffs_page_consistency_check(spiffs *fs) {
  786. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
  787. s32_t res = spiffs_page_consistency_check_i(fs);
  788. if (res != SPIFFS_OK) {
  789. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
  790. }
  791. CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
  792. return res;
  793. }
  794. //---------------------------------------
  795. // Object index consistency
  796. // searches for given object id in temporary object id index,
  797. // returns the index or -1
  798. static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
  799. u32_t i;
  800. spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
  801. obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  802. for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
  803. if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
  804. return i;
  805. }
  806. }
  807. return -1;
  808. }
  809. static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
  810. int cur_entry, const void *user_const_p, void *user_var_p) {
  811. (void)user_const_p;
  812. s32_t res_c = SPIFFS_VIS_COUNTINUE;
  813. s32_t res = SPIFFS_OK;
  814. u32_t *log_ix = (u32_t*)user_var_p;
  815. spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
  816. CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
  817. (cur_block * 256)/fs->block_count, 0);
  818. if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
  819. spiffs_page_header p_hdr;
  820. spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
  821. // load header
  822. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  823. 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
  824. SPIFFS_CHECK_RES(res);
  825. if (p_hdr.span_ix == 0 &&
  826. (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
  827. (SPIFFS_PH_FLAG_DELET)) {
  828. SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n",
  829. cur_pix, obj_id, p_hdr.span_ix);
  830. CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
  831. res = spiffs_page_delete(fs, cur_pix);
  832. SPIFFS_CHECK_RES(res);
  833. return res_c;
  834. }
  835. if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
  836. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
  837. return res_c;
  838. }
  839. if (p_hdr.span_ix == 0) {
  840. // objix header page, register objid as reachable
  841. int r = spiffs_object_index_search(fs, obj_id);
  842. if (r == -1) {
  843. // not registered, do it
  844. obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  845. (*log_ix)++;
  846. if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
  847. *log_ix = 0;
  848. }
  849. }
  850. } else { // span index
  851. // objix page, see if header can be found
  852. int r = spiffs_object_index_search(fs, obj_id);
  853. u8_t delete = 0;
  854. if (r == -1) {
  855. // not in temporary index, try finding it
  856. spiffs_page_ix objix_hdr_pix;
  857. res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
  858. res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
  859. if (res == SPIFFS_OK) {
  860. // found, register as reachable
  861. obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  862. } else if (res == SPIFFS_ERR_NOT_FOUND) {
  863. // not found, register as unreachable
  864. delete = 1;
  865. obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
  866. } else {
  867. SPIFFS_CHECK_RES(res);
  868. }
  869. (*log_ix)++;
  870. if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
  871. *log_ix = 0;
  872. }
  873. } else {
  874. // in temporary index, check reachable flag
  875. if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
  876. // registered as unreachable
  877. delete = 1;
  878. }
  879. }
  880. if (delete) {
  881. SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n",
  882. cur_pix, obj_id, p_hdr.span_ix);
  883. CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
  884. res = spiffs_page_delete(fs, cur_pix);
  885. SPIFFS_CHECK_RES(res);
  886. }
  887. } // span index
  888. } // valid object index id
  889. return res_c;
  890. }
  891. // Removes orphaned and partially deleted index pages.
  892. // Scans for index pages. When an index page is found, corresponding index header is searched for.
  893. // If no such page exists, the index page cannot be reached as no index header exists and must be
  894. // deleted.
  895. s32_t spiffs_object_index_consistency_check(spiffs *fs) {
  896. s32_t res = SPIFFS_OK;
  897. // impl note:
  898. // fs->work is used for a temporary object index memory, listing found object ids and
  899. // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
  900. // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
  901. // a reachable/unreachable object id.
  902. memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  903. u32_t obj_id_log_ix = 0;
  904. CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
  905. res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
  906. 0, 0);
  907. if (res == SPIFFS_VIS_END) {
  908. res = SPIFFS_OK;
  909. }
  910. if (res != SPIFFS_OK) {
  911. CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
  912. }
  913. CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
  914. return res;
  915. }
  916. #endif // !SPIFFS_READ_ONLY