4 * Contains functionality for checking file system consistency
5 * and mending problems.
6 * Three levels of consistency checks are implemented:
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.
15 * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
18 * Created on: Jul 7, 2013
24 #include "spiffs_nucleus.h"
28 #if SPIFFS_HAL_CALLBACK_EXTRA
29 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
31 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
34 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
36 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
40 //---------------------------------------
41 // Look up consistency
43 // searches in the object indices and returns the referenced page index given
44 // the object id and the data span index
45 // destroys fs->lu_work
46 static s32_t
spiffs_object_get_data_page_index_reference(
49 spiffs_span_ix data_spix
,
51 spiffs_page_ix
*objix_pix
) {
54 // calculate object index span index for given data page span index
55 spiffs_span_ix objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
57 // find obj index for obj id and span index
58 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, objix_spix
, 0, objix_pix
);
59 SPIFFS_CHECK_RES(res
);
61 // load obj index entry
62 u32_t addr
= SPIFFS_PAGE_TO_PADDR(fs
, *objix_pix
);
63 if (objix_spix
== 0) {
64 // get referenced page from object index header
65 addr
+= sizeof(spiffs_page_object_ix_header
) + data_spix
* sizeof(spiffs_page_ix
);
67 // get referenced page from object index
68 addr
+= sizeof(spiffs_page_object_ix
) + SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
) * sizeof(spiffs_page_ix
);
71 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
, 0, addr
, sizeof(spiffs_page_ix
), (u8_t
*)pix
);
76 // copies page contents to a new page
77 static s32_t
spiffs_rewrite_page(spiffs
*fs
, spiffs_page_ix cur_pix
, spiffs_page_header
*p_hdr
, spiffs_page_ix
*new_pix
) {
79 res
= spiffs_page_allocate_data(fs
, p_hdr
->obj_id
, p_hdr
, 0, 0, 0, 0, new_pix
);
80 SPIFFS_CHECK_RES(res
);
81 res
= spiffs_phys_cpy(fs
, 0,
82 SPIFFS_PAGE_TO_PADDR(fs
, *new_pix
) + sizeof(spiffs_page_header
),
83 SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + sizeof(spiffs_page_header
),
84 SPIFFS_DATA_PAGE_SIZE(fs
));
85 SPIFFS_CHECK_RES(res
);
89 // rewrites the object index for given object id and replaces the
90 // data page index to a new page index
91 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
) {
95 spiffs_page_ix free_pix
;
96 obj_id
|= SPIFFS_OBJ_ID_IX_FLAG
;
99 res
= spiffs_obj_lu_find_free(fs
, fs
->free_cursor_block_ix
, fs
->free_cursor_obj_lu_entry
, &bix
, &entry
);
100 SPIFFS_CHECK_RES(res
);
101 free_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
103 // calculate object index span index for given data page span index
104 spiffs_span_ix objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
105 if (objix_spix
== 0) {
106 // calc index in index header
109 // calc entry in index
110 entry
= SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
);
114 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
115 0, SPIFFS_PAGE_TO_PADDR(fs
, objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
116 SPIFFS_CHECK_RES(res
);
117 spiffs_page_header
*objix_p_hdr
= (spiffs_page_header
*)fs
->lu_work
;
119 // be ultra safe, double check header against provided data
120 if (objix_p_hdr
->obj_id
!= obj_id
) {
121 spiffs_page_delete(fs
, free_pix
);
122 return SPIFFS_ERR_CHECK_OBJ_ID_MISM
;
124 if (objix_p_hdr
->span_ix
!= objix_spix
) {
125 spiffs_page_delete(fs
, free_pix
);
126 return SPIFFS_ERR_CHECK_SPIX_MISM
;
128 if ((objix_p_hdr
->flags
& (SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_IXDELE
| SPIFFS_PH_FLAG_INDEX
|
129 SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
)) !=
130 (SPIFFS_PH_FLAG_IXDELE
| SPIFFS_PH_FLAG_DELET
)) {
131 spiffs_page_delete(fs
, free_pix
);
132 return SPIFFS_ERR_CHECK_FLAGS_BAD
;
136 if (objix_spix
== 0) {
137 ((spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
] = new_data_pix
;
139 ((spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)] = new_data_pix
;
142 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
143 0, SPIFFS_PAGE_TO_PADDR(fs
, free_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
144 SPIFFS_CHECK_RES(res
);
145 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
146 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
),
147 sizeof(spiffs_obj_id
),
149 SPIFFS_CHECK_RES(res
);
150 res
= spiffs_page_delete(fs
, objix_pix
);
155 // deletes an object just by marking object index header as deleted
156 static s32_t
spiffs_delete_obj_lazy(spiffs
*fs
, spiffs_obj_id obj_id
) {
157 spiffs_page_ix objix_hdr_pix
;
159 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
, 0, 0, &objix_hdr_pix
);
160 if (res
== SPIFFS_ERR_NOT_FOUND
) {
163 SPIFFS_CHECK_RES(res
);
165 #if SPIFFS_NO_BLIND_WRITES
166 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_READ
,
167 0, SPIFFS_PAGE_TO_PADDR(fs
, objix_hdr_pix
) + offsetof(spiffs_page_header
, flags
),
168 sizeof(flags
), &flags
);
169 SPIFFS_CHECK_RES(res
);
171 flags
&= ~SPIFFS_PH_FLAG_IXDELE
;
172 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
173 0, SPIFFS_PAGE_TO_PADDR(fs
, objix_hdr_pix
) + offsetof(spiffs_page_header
, flags
),
174 sizeof(flags
), &flags
);
178 // validates the given look up entry
179 static s32_t
spiffs_lookup_check_validate(spiffs
*fs
, spiffs_obj_id lu_obj_id
, spiffs_page_header
*p_hdr
,
180 spiffs_page_ix cur_pix
, spiffs_block_ix cur_block
, int cur_entry
, int *reload_lu
) {
183 u8_t delete_page
= 0;
184 s32_t res
= SPIFFS_OK
;
185 spiffs_page_ix objix_pix
;
186 spiffs_page_ix ref_pix
;
187 // check validity, take actions
188 if (((lu_obj_id
== SPIFFS_OBJ_ID_DELETED
) && (p_hdr
->flags
& SPIFFS_PH_FLAG_DELET
)) ||
189 ((lu_obj_id
== SPIFFS_OBJ_ID_FREE
) && (p_hdr
->flags
& SPIFFS_PH_FLAG_USED
) == 0)) {
190 // look up entry deleted / free but used in page header
191 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" deleted/free in lu but not on page\n", cur_pix
);
194 if (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
) {
195 // header says data page
196 // data page can be removed if not referenced by some object index
197 res
= spiffs_object_get_data_page_index_reference(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, &ref_pix
, &objix_pix
);
198 if (res
== SPIFFS_ERR_NOT_FOUND
) {
199 // no object with this id, so remove page safely
202 SPIFFS_CHECK_RES(res
);
203 if (ref_pix
== cur_pix
) {
204 // data page referenced by object index but deleted in lu
205 // copy page to new place and re-write the object index to new place
206 spiffs_page_ix new_pix
;
207 res
= spiffs_rewrite_page(fs
, cur_pix
, p_hdr
, &new_pix
);
208 SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg
" to new page "_SPIPRIpg
"\n", cur_pix
, new_pix
);
209 SPIFFS_CHECK_RES(res
);
211 SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg
" rewritten to "_SPIPRIpg
", affected objix_pix "_SPIPRIpg
"\n", cur_pix
, new_pix
, objix_pix
);
212 res
= spiffs_rewrite_index(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, new_pix
, objix_pix
);
213 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
214 // index bad also, cannot mend this file
215 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
216 res
= spiffs_page_delete(fs
, new_pix
);
217 SPIFFS_CHECK_RES(res
);
218 res
= spiffs_delete_obj_lazy(fs
, p_hdr
->obj_id
);
219 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
->obj_id
, 0);
221 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_INDEX
, p_hdr
->obj_id
, p_hdr
->span_ix
);
223 SPIFFS_CHECK_RES(res
);
227 // header says index page
228 // index page can be removed if other index with same obj_id and spanix is found
229 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);
230 if (res
== SPIFFS_ERR_NOT_FOUND
) {
231 // no such index page found, check for a data page amongst page headers
232 // lu cannot be trusted
233 res
= spiffs_obj_lu_find_id_and_span_by_phdr(fs
, p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, 0);
234 if (res
== SPIFFS_OK
) { // ignore other errors
235 // got a data page also, assume lu corruption only, rewrite to new page
236 spiffs_page_ix new_pix
;
237 res
= spiffs_rewrite_page(fs
, cur_pix
, p_hdr
, &new_pix
);
238 SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg
" to new page "_SPIPRIpg
"\n", cur_pix
, new_pix
);
239 SPIFFS_CHECK_RES(res
);
241 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
244 SPIFFS_CHECK_RES(res
);
248 if (lu_obj_id
!= SPIFFS_OBJ_ID_FREE
&& lu_obj_id
!= SPIFFS_OBJ_ID_DELETED
) {
249 // look up entry used
250 if ((p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
) != (lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
)) {
251 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" differ in obj_id lu:"_SPIPRIid
" ph:"_SPIPRIid
"\n", cur_pix
, lu_obj_id
, p_hdr
->obj_id
);
253 if ((p_hdr
->flags
& SPIFFS_PH_FLAG_DELET
) == 0 ||
254 (p_hdr
->flags
& SPIFFS_PH_FLAG_FINAL
) ||
255 (p_hdr
->flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_IXDELE
)) == 0) {
256 // page deleted or not finalized, just remove it
258 if (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
) {
259 // if data page, check for reference to this page
260 res
= spiffs_object_get_data_page_index_reference(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, &ref_pix
, &objix_pix
);
261 if (res
== SPIFFS_ERR_NOT_FOUND
) {
262 // no object with this id, so remove page safely
265 SPIFFS_CHECK_RES(res
);
266 // if found, rewrite page with object id, update index, and delete current
267 if (ref_pix
== cur_pix
) {
268 spiffs_page_ix new_pix
;
269 res
= spiffs_rewrite_page(fs
, cur_pix
, p_hdr
, &new_pix
);
270 SPIFFS_CHECK_RES(res
);
271 res
= spiffs_rewrite_index(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, new_pix
, objix_pix
);
272 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
273 // index bad also, cannot mend this file
274 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
275 res
= spiffs_page_delete(fs
, new_pix
);
276 SPIFFS_CHECK_RES(res
);
277 res
= spiffs_delete_obj_lazy(fs
, p_hdr
->obj_id
);
279 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
->obj_id
, 0);
281 SPIFFS_CHECK_RES(res
);
285 // else if index, check for other pages with both obj_id's and spanix
286 spiffs_page_ix objix_pix_lu
, objix_pix_ph
;
287 // see if other object index page exists for lookup obj id and span index
288 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
);
289 if (res
== SPIFFS_ERR_NOT_FOUND
) {
293 SPIFFS_CHECK_RES(res
);
294 // see if other object index exists for page header obj id and span index
295 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
);
296 if (res
== SPIFFS_ERR_NOT_FOUND
) {
300 SPIFFS_CHECK_RES(res
);
301 // if both obj_id's found, just delete current
302 if (objix_pix_ph
== 0 || objix_pix_lu
== 0) {
303 // otherwise try finding first corresponding data pages
304 spiffs_page_ix data_pix_lu
, data_pix_ph
;
305 // see if other data page exists for look up obj id and span index
306 res
= spiffs_obj_lu_find_id_and_span(fs
, lu_obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &data_pix_lu
);
307 if (res
== SPIFFS_ERR_NOT_FOUND
) {
311 SPIFFS_CHECK_RES(res
);
312 // see if other data page exists for page header obj id and span index
313 res
= spiffs_obj_lu_find_id_and_span(fs
, p_hdr
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &data_pix_ph
);
314 if (res
== SPIFFS_ERR_NOT_FOUND
) {
318 SPIFFS_CHECK_RES(res
);
320 spiffs_page_header new_ph
;
321 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
);
322 new_ph
.span_ix
= p_hdr
->span_ix
;
323 spiffs_page_ix new_pix
;
324 if ((objix_pix_lu
&& data_pix_lu
&& data_pix_ph
&& objix_pix_ph
== 0) ||
325 (objix_pix_lu
== 0 && data_pix_ph
&& objix_pix_ph
== 0)) {
326 // got a data page for page header obj id
327 // rewrite as obj_id_ph
328 new_ph
.obj_id
= p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
329 res
= spiffs_rewrite_page(fs
, cur_pix
, &new_ph
, &new_pix
);
330 SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg
" as "_SPIPRIid
" to pix "_SPIPRIpg
"\n", cur_pix
, new_ph
.obj_id
, new_pix
);
331 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
332 SPIFFS_CHECK_RES(res
);
334 } else if ((objix_pix_ph
&& data_pix_ph
&& data_pix_lu
&& objix_pix_lu
== 0) ||
335 (objix_pix_ph
== 0 && data_pix_lu
&& objix_pix_lu
== 0)) {
336 // got a data page for look up obj id
337 // rewrite as obj_id_lu
338 new_ph
.obj_id
= lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
339 SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg
" as "_SPIPRIid
"\n", cur_pix
, new_ph
.obj_id
);
340 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
341 res
= spiffs_rewrite_page(fs
, cur_pix
, &new_ph
, &new_pix
);
342 SPIFFS_CHECK_RES(res
);
345 // cannot safely do anything
346 SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n", NULL
);
351 } else if (((lu_obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) && (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
)) ||
352 ((lu_obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) == 0 && (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
) == 0)) {
353 SPIFFS_CHECK_DBG("LU: "_SPIPRIpg
" lu/page index marking differ\n", cur_pix
);
354 spiffs_page_ix data_pix
, objix_pix_d
;
355 // see if other data page exists for given obj id and span index
356 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
);
357 if (res
== SPIFFS_ERR_NOT_FOUND
) {
361 SPIFFS_CHECK_RES(res
);
362 // see if other object index exists for given obj id and span index
363 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
);
364 if (res
== SPIFFS_ERR_NOT_FOUND
) {
368 SPIFFS_CHECK_RES(res
);
371 // if other data page exists and object index exists, just delete page
372 if (data_pix
&& objix_pix_d
) {
373 SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n", NULL
);
375 // if only data page exists, make this page index
376 if (data_pix
&& objix_pix_d
== 0) {
377 SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n", NULL
);
378 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_INDEX
, lu_obj_id
, p_hdr
->span_ix
);
379 spiffs_page_header new_ph
;
380 spiffs_page_ix new_pix
;
381 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_INDEX
);
382 new_ph
.obj_id
= lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
383 new_ph
.span_ix
= p_hdr
->span_ix
;
384 res
= spiffs_page_allocate_data(fs
, new_ph
.obj_id
, &new_ph
, 0, 0, 0, 1, &new_pix
);
385 SPIFFS_CHECK_RES(res
);
386 res
= spiffs_phys_cpy(fs
, 0, SPIFFS_PAGE_TO_PADDR(fs
, new_pix
) + sizeof(spiffs_page_header
),
387 SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + sizeof(spiffs_page_header
),
388 SPIFFS_CFG_LOG_PAGE_SZ(fs
) - sizeof(spiffs_page_header
));
389 SPIFFS_CHECK_RES(res
);
391 // if only index exists, make data page
392 if (data_pix
== 0 && objix_pix_d
) {
393 SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n", NULL
);
394 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, lu_obj_id
, p_hdr
->span_ix
);
395 spiffs_page_header new_ph
;
396 spiffs_page_ix new_pix
;
397 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
);
398 new_ph
.obj_id
= lu_obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
399 new_ph
.span_ix
= p_hdr
->span_ix
;
400 res
= spiffs_page_allocate_data(fs
, new_ph
.obj_id
, &new_ph
, 0, 0, 0, 1, &new_pix
);
401 SPIFFS_CHECK_RES(res
);
402 res
= spiffs_phys_cpy(fs
, 0, SPIFFS_PAGE_TO_PADDR(fs
, new_pix
) + sizeof(spiffs_page_header
),
403 SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + sizeof(spiffs_page_header
),
404 SPIFFS_CFG_LOG_PAGE_SZ(fs
) - sizeof(spiffs_page_header
));
405 SPIFFS_CHECK_RES(res
);
407 // if nothing exists, we cannot safely make a decision - delete
409 } else if ((p_hdr
->flags
& SPIFFS_PH_FLAG_DELET
) == 0) {
410 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" busy in lu but deleted on page\n", cur_pix
);
412 } else if ((p_hdr
->flags
& SPIFFS_PH_FLAG_FINAL
)) {
413 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" busy but not final\n", cur_pix
);
414 // page can be removed if not referenced by object index
416 res
= spiffs_object_get_data_page_index_reference(fs
, lu_obj_id
, p_hdr
->span_ix
, &ref_pix
, &objix_pix
);
417 if (res
== SPIFFS_ERR_NOT_FOUND
) {
418 // no object with this id, so remove page safely
422 SPIFFS_CHECK_RES(res
);
423 if (ref_pix
!= cur_pix
) {
424 SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n", NULL
);
427 // page referenced by object index but not final
429 SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n", NULL
);
430 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
432 #if SPIFFS_NO_BLIND_WRITES
433 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_READ
,
434 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + offsetof(spiffs_page_header
, flags
),
435 sizeof(flags
), &flags
);
436 SPIFFS_CHECK_RES(res
);
438 flags
&= ~SPIFFS_PH_FLAG_FINAL
;
439 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
440 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + offsetof(spiffs_page_header
, flags
),
441 sizeof(flags
), &flags
);
448 SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg
"\n", cur_pix
);
449 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_DELETE_PAGE
, cur_pix
, 0);
450 res
= spiffs_page_delete(fs
, cur_pix
);
451 SPIFFS_CHECK_RES(res
);
457 static s32_t
spiffs_lookup_check_v(spiffs
*fs
, spiffs_obj_id obj_id
, spiffs_block_ix cur_block
, int cur_entry
,
458 const void *user_const_p
, void *user_var_p
) {
461 s32_t res
= SPIFFS_OK
;
462 spiffs_page_header p_hdr
;
463 spiffs_page_ix cur_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, cur_block
, cur_entry
);
465 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_PROGRESS
,
466 (cur_block
* 256) / fs
->block_count
, 0);
469 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
470 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
471 SPIFFS_CHECK_RES(res
);
475 res
= spiffs_lookup_check_validate(fs
, obj_id
, &p_hdr
, cur_pix
, cur_block
, cur_entry
, &reload_lu
);
476 SPIFFS_CHECK_RES(res
);
478 if (res
== SPIFFS_OK
) {
479 return reload_lu
? SPIFFS_VIS_COUNTINUE_RELOAD
: SPIFFS_VIS_COUNTINUE
;
485 // Scans all object look up. For each entry, corresponding page header is checked for validity.
486 // If an object index header page is found, this is also checked
487 s32_t
spiffs_lookup_consistency_check(spiffs
*fs
, u8_t check_all_objects
) {
488 (void)check_all_objects
;
489 s32_t res
= SPIFFS_OK
;
491 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_PROGRESS
, 0, 0);
493 res
= spiffs_obj_lu_find_entry_visitor(fs
, 0, 0, 0, 0, spiffs_lookup_check_v
, 0, 0, 0, 0);
495 if (res
== SPIFFS_VIS_END
) {
499 if (res
!= SPIFFS_OK
) {
500 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_ERROR
, res
, 0);
503 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_PROGRESS
, 256, 0);
508 //---------------------------------------
511 // Scans all pages (except lu pages), reserves 4 bits in working memory for each page
512 // bit 0: 0 == FREE|DELETED, 1 == USED
513 // bit 1: 0 == UNREFERENCED, 1 == REFERENCED
514 // bit 2: 0 == NOT_INDEX, 1 == INDEX
516 // A consistent file system will have only pages being
517 // * x000 free, unreferenced, not index
518 // * x011 used, referenced only once, not index
519 // * x101 used, unreferenced, index
520 // The working memory might not fit all pages so several scans might be needed
521 static s32_t
spiffs_page_consistency_check_i(spiffs
*fs
) {
522 const u32_t bits
= 4;
523 const spiffs_page_ix pages_per_scan
= SPIFFS_CFG_LOG_PAGE_SZ(fs
) * 8 / bits
;
525 s32_t res
= SPIFFS_OK
;
526 spiffs_page_ix pix_offset
= 0;
528 // for each range of pages fitting into work memory
529 while (pix_offset
< SPIFFS_PAGES_PER_BLOCK(fs
) * fs
->block_count
) {
530 // set this flag to abort all checks and rescan the page range
532 memset(fs
->work
, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
534 spiffs_block_ix cur_block
= 0;
535 // build consistency bitmap for id range traversing all blocks
536 while (!restart
&& cur_block
< fs
->block_count
) {
537 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_PROGRESS
,
538 (pix_offset
* 256) / (SPIFFS_PAGES_PER_BLOCK(fs
) * fs
->block_count
) +
539 ((((cur_block
* pages_per_scan
* 256) / (SPIFFS_PAGES_PER_BLOCK(fs
) * fs
->block_count
))) / fs
->block_count
),
541 // traverse each page except for lookup pages
542 spiffs_page_ix cur_pix
= SPIFFS_OBJ_LOOKUP_PAGES(fs
) + SPIFFS_PAGES_PER_BLOCK(fs
) * cur_block
;
543 while (!restart
&& cur_pix
< SPIFFS_PAGES_PER_BLOCK(fs
) * (cur_block
+ 1)) {
544 //if ((cur_pix & 0xff) == 0)
545 // SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
546 // cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
549 spiffs_page_header p_hdr
;
550 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
551 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
552 SPIFFS_CHECK_RES(res
);
554 u8_t within_range
= (cur_pix
>= pix_offset
&& cur_pix
< pix_offset
+ pages_per_scan
);
555 const u32_t pix_byte_ix
= (cur_pix
- pix_offset
) / (8 / bits
);
556 const u8_t pix_bit_ix
= (cur_pix
& ((8 / bits
) - 1)) * bits
;
559 (p_hdr
.flags
& SPIFFS_PH_FLAG_DELET
) && (p_hdr
.flags
& SPIFFS_PH_FLAG_USED
) == 0) {
561 fs
->work
[pix_byte_ix
] |= (1 << (pix_bit_ix
+ 0));
563 if ((p_hdr
.flags
& SPIFFS_PH_FLAG_DELET
) &&
564 (p_hdr
.flags
& SPIFFS_PH_FLAG_IXDELE
) &&
565 (p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_USED
)) == 0) {
566 // found non-deleted index
568 fs
->work
[pix_byte_ix
] |= (1 << (pix_bit_ix
+ 2));
571 // load non-deleted index
572 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
573 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
574 SPIFFS_CHECK_RES(res
);
576 // traverse index for referenced pages
577 spiffs_page_ix
*object_page_index
;
578 spiffs_page_header
*objix_p_hdr
= (spiffs_page_header
*)fs
->lu_work
;
582 spiffs_span_ix data_spix_offset
;
583 if (p_hdr
.span_ix
== 0) {
584 // object header page index
585 entries
= SPIFFS_OBJ_HDR_IX_LEN(fs
);
586 data_spix_offset
= 0;
587 object_page_index
= (spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix_header
));
590 entries
= SPIFFS_OBJ_IX_LEN(fs
);
591 data_spix_offset
= SPIFFS_OBJ_HDR_IX_LEN(fs
) + SPIFFS_OBJ_IX_LEN(fs
) * (p_hdr
.span_ix
- 1);
592 object_page_index
= (spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix
));
595 // for all entries in index
596 for (i
= 0; !restart
&& i
< entries
; i
++) {
597 spiffs_page_ix rpix
= object_page_index
[i
];
598 u8_t rpix_within_range
= rpix
>= pix_offset
&& rpix
< pix_offset
+ pages_per_scan
;
600 if ((rpix
!= (spiffs_page_ix
) - 1 && rpix
> SPIFFS_MAX_PAGES(fs
))
601 || (rpix_within_range
&& SPIFFS_IS_LOOKUP_PAGE(fs
, rpix
))) {
604 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
"x bad pix / LU referenced from page "_SPIPRIpg
"\n",
606 // check for data page elsewhere
607 spiffs_page_ix data_pix
;
608 res
= spiffs_obj_lu_find_id_and_span(fs
, objix_p_hdr
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
609 data_spix_offset
+ i
, 0, &data_pix
);
610 if (res
== SPIFFS_ERR_NOT_FOUND
) {
614 SPIFFS_CHECK_RES(res
);
616 // if not, allocate free page
617 spiffs_page_header new_ph
;
618 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
);
619 new_ph
.obj_id
= objix_p_hdr
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
620 new_ph
.span_ix
= data_spix_offset
+ i
;
621 res
= spiffs_page_allocate_data(fs
, new_ph
.obj_id
, &new_ph
, 0, 0, 0, 1, &data_pix
);
622 SPIFFS_CHECK_RES(res
);
623 SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg
"\n", data_pix
);
626 SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg
"\n", cur_pix
);
627 res
= spiffs_rewrite_index(fs
, objix_p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
,
628 data_spix_offset
+ i
, data_pix
, cur_pix
);
629 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
630 // index bad also, cannot mend this file
631 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi
", cannot mend - delete object\n", res
);
632 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, objix_p_hdr
->obj_id
, 0);
634 res
= spiffs_page_delete(fs
, cur_pix
);
636 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_FIX_INDEX
, objix_p_hdr
->obj_id
, objix_p_hdr
->span_ix
);
638 SPIFFS_CHECK_RES(res
);
641 } else if (rpix_within_range
) {
644 // read referenced page header
645 spiffs_page_header rp_hdr
;
646 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
647 0, SPIFFS_PAGE_TO_PADDR(fs
, rpix
), sizeof(spiffs_page_header
), (u8_t
*)&rp_hdr
);
648 SPIFFS_CHECK_RES(res
);
650 // cross reference page header check
651 if (rp_hdr
.obj_id
!= (p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
) ||
652 rp_hdr
.span_ix
!= data_spix_offset
+ i
||
653 (rp_hdr
.flags
& (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_USED
)) !=
654 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_INDEX
)) {
655 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" has inconsistent page header ix id/span:"_SPIPRIid
"/"_SPIPRIsp
", ref id/span:"_SPIPRIid
"/"_SPIPRIsp
" flags:"_SPIPRIfl
"\n",
656 rpix
, p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, data_spix_offset
+ i
,
657 rp_hdr
.obj_id
, rp_hdr
.span_ix
, rp_hdr
.flags
);
658 // try finding correct page
659 spiffs_page_ix data_pix
;
660 res
= spiffs_obj_lu_find_id_and_span(fs
, p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
661 data_spix_offset
+ i
, rpix
, &data_pix
);
662 if (res
== SPIFFS_ERR_NOT_FOUND
) {
666 SPIFFS_CHECK_RES(res
);
668 // not found, this index is badly borked
669 SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid
"\n", p_hdr
.obj_id
);
670 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
671 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
672 SPIFFS_CHECK_RES(res
);
675 // found it, so rewrite index
676 SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg
", rewrite ix pix "_SPIPRIpg
" id "_SPIPRIid
"\n",
677 data_pix
, cur_pix
, p_hdr
.obj_id
);
678 res
= spiffs_rewrite_index(fs
, p_hdr
.obj_id
, data_spix_offset
+ i
, data_pix
, cur_pix
);
679 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
680 // index bad also, cannot mend this file
681 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
682 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
683 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
685 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_FIX_INDEX
, p_hdr
.obj_id
, p_hdr
.span_ix
);
687 SPIFFS_CHECK_RES(res
);
691 // mark rpix as referenced
692 const u32_t rpix_byte_ix
= (rpix
- pix_offset
) / (8 / bits
);
693 const u8_t rpix_bit_ix
= (rpix
& ((8 / bits
) - 1)) * bits
;
694 if (fs
->work
[rpix_byte_ix
] & (1 << (rpix_bit_ix
+ 1))) {
695 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" multiple referenced from page "_SPIPRIpg
"\n",
697 // Here, we should have fixed all broken references - getting this means there
698 // must be multiple files with same object id. Only solution is to delete
699 // the object which is referring to this page
700 SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid
" and page "_SPIPRIpg
"\n",
701 p_hdr
.obj_id
, cur_pix
);
702 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
703 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
704 SPIFFS_CHECK_RES(res
);
705 // extra precaution, delete this page also
706 res
= spiffs_page_delete(fs
, cur_pix
);
707 SPIFFS_CHECK_RES(res
);
710 fs
->work
[rpix_byte_ix
] |= (1 << (rpix_bit_ix
+ 1));
713 } // for all index entries
722 // check consistency bitmap
724 spiffs_page_ix objix_pix
;
729 for (byte_ix
= 0; !restart
&& byte_ix
< SPIFFS_CFG_LOG_PAGE_SZ(fs
); byte_ix
++) {
730 for (bit_ix
= 0; !restart
&& bit_ix
< 8 / bits
; bit_ix
++) {
731 u8_t bitmask
= (fs
->work
[byte_ix
] >> (bit_ix
* bits
)) & 0x7;
732 spiffs_page_ix cur_pix
= pix_offset
+ byte_ix
* (8 / bits
) + bit_ix
;
734 // 000 ok - free, unreferenced, not index
736 if (bitmask
== 0x1) {
739 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" USED, UNREFERENCED, not index\n", cur_pix
);
741 u8_t rewrite_ix_to_this
= 0;
742 u8_t delete_page
= 0;
743 // check corresponding object index entry
744 spiffs_page_header p_hdr
;
745 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
746 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
747 SPIFFS_CHECK_RES(res
);
749 res
= spiffs_object_get_data_page_index_reference(fs
, p_hdr
.obj_id
, p_hdr
.span_ix
,
751 if (res
== SPIFFS_OK
) {
752 if (((rpix
== (spiffs_page_ix
) - 1 || rpix
> SPIFFS_MAX_PAGES(fs
)) || (SPIFFS_IS_LOOKUP_PAGE(fs
, rpix
)))) {
753 // pointing to a bad page altogether, rewrite index to this
754 rewrite_ix_to_this
= 1;
755 SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg
", rewrite to this "_SPIPRIpg
"\n", rpix
, cur_pix
);
757 // pointing to something else, check what
758 spiffs_page_header rp_hdr
;
759 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
760 0, SPIFFS_PAGE_TO_PADDR(fs
, rpix
), sizeof(spiffs_page_header
), (u8_t
*)&rp_hdr
);
761 SPIFFS_CHECK_RES(res
);
762 if (((p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
) == rp_hdr
.obj_id
) &&
763 ((rp_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
)) ==
764 (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_DELET
))) {
765 // pointing to something else valid, just delete this page then
766 SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg
", delete this "_SPIPRIpg
"\n", rpix
, cur_pix
);
769 // pointing to something weird, update index to point to this page instead
770 if (rpix
!= cur_pix
) {
771 SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg
" %s%s%s%s, rewrite this "_SPIPRIpg
"\n", rpix
,
772 (rp_hdr
.flags
& SPIFFS_PH_FLAG_INDEX
) ? "" : "INDEX ",
773 (rp_hdr
.flags
& SPIFFS_PH_FLAG_DELET
) ? "" : "DELETED ",
774 (rp_hdr
.flags
& SPIFFS_PH_FLAG_USED
) ? "NOTUSED " : "",
775 (rp_hdr
.flags
& SPIFFS_PH_FLAG_FINAL
) ? "NOTFINAL " : "",
777 rewrite_ix_to_this
= 1;
779 // should not happen, destined for fubar
783 } else if (res
== SPIFFS_ERR_NOT_FOUND
) {
784 SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg
"\n", cur_pix
);
789 if (rewrite_ix_to_this
) {
790 // if pointing to invalid page, redirect index to this page
791 SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid
" data spix "_SPIPRIsp
" to point to this pix: "_SPIPRIpg
"\n",
792 p_hdr
.obj_id
, p_hdr
.span_ix
, cur_pix
);
793 res
= spiffs_rewrite_index(fs
, p_hdr
.obj_id
, p_hdr
.span_ix
, cur_pix
, objix_pix
);
794 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
795 // index bad also, cannot mend this file
796 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
797 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
798 res
= spiffs_page_delete(fs
, cur_pix
);
799 SPIFFS_CHECK_RES(res
);
800 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
802 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_FIX_INDEX
, p_hdr
.obj_id
, p_hdr
.span_ix
);
804 SPIFFS_CHECK_RES(res
);
807 } else if (delete_page
) {
808 SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg
"\n", cur_pix
);
809 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_PAGE
, cur_pix
, 0);
810 res
= spiffs_page_delete(fs
, cur_pix
);
812 SPIFFS_CHECK_RES(res
);
814 if (bitmask
== 0x2) {
817 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" FREE, REFERENCED, not index\n", cur_pix
);
819 // no op, this should be taken care of when checking valid references
822 // 011 ok - busy, referenced, not index
824 if (bitmask
== 0x4) {
827 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" FREE, unreferenced, INDEX\n", cur_pix
);
829 // this should never happen, major fubar
832 // 101 ok - busy, unreferenced, index
834 if (bitmask
== 0x6) {
837 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" FREE, REFERENCED, INDEX\n", cur_pix
);
839 // no op, this should be taken care of when checking valid references
841 if (bitmask
== 0x7) {
844 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" USED, REFERENCED, INDEX\n", cur_pix
);
846 // no op, this should be taken care of when checking valid references
852 SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg
", restart "_SPIPRIi
"\n", pix_offset
, restart
);
855 pix_offset
+= pages_per_scan
;
857 } // while page range not reached end
861 // Checks consistency amongst all pages and fixes irregularities
862 s32_t
spiffs_page_consistency_check(spiffs
*fs
) {
863 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_PROGRESS
, 0, 0);
864 s32_t res
= spiffs_page_consistency_check_i(fs
);
865 if (res
!= SPIFFS_OK
) {
866 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_ERROR
, res
, 0);
868 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_PROGRESS
, 256, 0);
872 //---------------------------------------
873 // Object index consistency
875 // searches for given object id in temporary object id index,
876 // returns the index or -1
877 static int spiffs_object_index_search(spiffs
*fs
, spiffs_obj_id obj_id
) {
879 spiffs_obj_id
*obj_table
= (spiffs_obj_id
*)fs
->work
;
880 obj_id
&= ~SPIFFS_OBJ_ID_IX_FLAG
;
881 for (i
= 0; i
< SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
); i
++) {
882 if ((obj_table
[i
] & ~SPIFFS_OBJ_ID_IX_FLAG
) == obj_id
) {
889 static s32_t
spiffs_object_index_consistency_check_v(spiffs
*fs
, spiffs_obj_id obj_id
, spiffs_block_ix cur_block
,
890 int cur_entry
, const void *user_const_p
, void *user_var_p
) {
892 s32_t res_c
= SPIFFS_VIS_COUNTINUE
;
893 s32_t res
= SPIFFS_OK
;
894 u32_t
*log_ix
= (u32_t
*)user_var_p
;
895 spiffs_obj_id
*obj_table
= (spiffs_obj_id
*)fs
->work
;
897 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_PROGRESS
,
898 (cur_block
* 256) / fs
->block_count
, 0);
900 if (obj_id
!= SPIFFS_OBJ_ID_FREE
&& obj_id
!= SPIFFS_OBJ_ID_DELETED
&& (obj_id
& SPIFFS_OBJ_ID_IX_FLAG
)) {
901 spiffs_page_header p_hdr
;
902 spiffs_page_ix cur_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, cur_block
, cur_entry
);
905 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
906 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
907 SPIFFS_CHECK_RES(res
);
909 if (p_hdr
.span_ix
== 0 &&
910 (p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) ==
911 (SPIFFS_PH_FLAG_DELET
)) {
912 SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg
", obj id:"_SPIPRIid
" spix:"_SPIPRIsp
" header not fully deleted - deleting\n",
913 cur_pix
, obj_id
, p_hdr
.span_ix
);
914 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_DELETE_PAGE
, cur_pix
, obj_id
);
915 res
= spiffs_page_delete(fs
, cur_pix
);
916 SPIFFS_CHECK_RES(res
);
920 if ((p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) ==
921 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) {
925 if (p_hdr
.span_ix
== 0) {
926 // objix header page, register objid as reachable
927 int r
= spiffs_object_index_search(fs
, obj_id
);
929 // not registered, do it
930 obj_table
[*log_ix
] = obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
932 if (*log_ix
>= SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
)) {
936 } else { // span index
937 // objix page, see if header can be found
938 int r
= spiffs_object_index_search(fs
, obj_id
);
941 // not in temporary index, try finding it
942 spiffs_page_ix objix_hdr_pix
;
943 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &objix_hdr_pix
);
944 res_c
= SPIFFS_VIS_COUNTINUE_RELOAD
;
945 if (res
== SPIFFS_OK
) {
946 // found, register as reachable
947 obj_table
[*log_ix
] = obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
948 } else if (res
== SPIFFS_ERR_NOT_FOUND
) {
949 // not found, register as unreachable
951 obj_table
[*log_ix
] = obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
953 SPIFFS_CHECK_RES(res
);
956 if (*log_ix
>= SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
)) {
960 // in temporary index, check reachable flag
961 if ((obj_table
[r
] & SPIFFS_OBJ_ID_IX_FLAG
)) {
962 // registered as unreachable
968 SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg
", obj id:"_SPIPRIid
" spix:"_SPIPRIsp
" is orphan index - deleting\n",
969 cur_pix
, obj_id
, p_hdr
.span_ix
);
970 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_DELETE_ORPHANED_INDEX
, cur_pix
, obj_id
);
971 res
= spiffs_page_delete(fs
, cur_pix
);
972 SPIFFS_CHECK_RES(res
);
975 } // valid object index id
980 // Removes orphaned and partially deleted index pages.
981 // Scans for index pages. When an index page is found, corresponding index header is searched for.
982 // If no such page exists, the index page cannot be reached as no index header exists and must be
984 s32_t
spiffs_object_index_consistency_check(spiffs
*fs
) {
985 s32_t res
= SPIFFS_OK
;
987 // fs->work is used for a temporary object index memory, listing found object ids and
988 // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
989 // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
990 // a reachable/unreachable object id.
991 memset(fs
->work
, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
992 u32_t obj_id_log_ix
= 0;
993 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_PROGRESS
, 0, 0);
994 res
= spiffs_obj_lu_find_entry_visitor(fs
, 0, 0, 0, 0, spiffs_object_index_consistency_check_v
, 0, &obj_id_log_ix
,
996 if (res
== SPIFFS_VIS_END
) {
999 if (res
!= SPIFFS_OK
) {
1000 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_ERROR
, res
, 0);
1002 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_PROGRESS
, 256, 0);
1006 #endif // !SPIFFS_READ_ONLY