void dump_erase_counts(spiffs *fs) { spiffs_block_ix bix; printf(" BLOCK |\n"); printf(" AGE COUNT|\n"); for (bix = 0; bix < fs->block_count; bix++) { printf("----%3i ----|", bix); } printf("\n"); for (bix = 0; bix < fs->block_count; bix++) { spiffs_obj_id erase_mark; _spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (uint8_t *)&erase_mark); if (erases[bix] == 0) { printf(" |"); } else { printf("%7i %4i|", (fs->max_erase_count - erase_mark), erases[bix]); } } printf("\n"); }
// Finds block candidates to erase s32_t spiffs_gc_find_candidate( spiffs *fs, spiffs_block_ix **block_candidates, int *candidate_count, char fs_crammed) { s32_t res = SPIFFS_OK; u32_t blocks = fs->block_count; spiffs_block_ix cur_block = 0; u32_t cur_block_addr = 0; spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; int cur_entry = 0; // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t))); *candidate_count = 0; c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); // divide up work area into block indices and scores // todo alignment? spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work; s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix)); *block_candidates = cand_blocks; int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); // check each block while (res == SPIFFS_OK && blocks--) { u16_t deleted_pages_in_block = 0; u16_t used_pages_in_block = 0; int obj_lookup_page = 0; // check each object lookup page while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { int entry_offset = obj_lookup_page * entries_per_page; res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); // check each entry while (res == SPIFFS_OK && cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; if (obj_id == SPIFFS_OBJ_ID_FREE) { // when a free entry is encountered, scan logic ensures that all following entries are free also res = 1; // kill object lu loop break; } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { deleted_pages_in_block++; } else { used_pages_in_block++; } cur_entry++; } // per entry obj_lookup_page++; } // per object lookup page if (res == 1) res = SPIFFS_OK; // calculate score and insert into candidate table // stoneage sort, but probably not so many blocks if (res == SPIFFS_OK && deleted_pages_in_block > 0) { // read erase count spiffs_obj_id erase_count; res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, SPIFFS_ERASE_COUNT_PADDR(fs, cur_block), sizeof(spiffs_obj_id), (u8_t *)&erase_count); SPIFFS_CHECK_RES(res); spiffs_obj_id erase_age; if (fs->max_erase_count > erase_count) { erase_age = fs->max_erase_count - erase_count; } else { erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count); } s32_t score = deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + used_pages_in_block * SPIFFS_GC_HEUR_W_USED + erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE); int cand_ix = 0; SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); while (cand_ix < max_candidates) { if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) { cand_blocks[cand_ix] = cur_block; cand_scores[cand_ix] = score; break; } else if (cand_scores[cand_ix] < score) { int reorder_cand_ix = max_candidates - 2; while (reorder_cand_ix >= cand_ix) { cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix]; cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix]; reorder_cand_ix--; } cand_blocks[cand_ix] = cur_block; cand_scores[cand_ix] = score; break; } cand_ix++; } (*candidate_count)++; } cur_entry = 0; cur_block++; cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); } // per block return res; }
s32_t SPIFFS_vis(spiffs *fs) { s32_t res = SPIFFS_OK; SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; spiffs_block_ix bix = 0; while (bix < fs->block_count) { // check each object lookup page int obj_lookup_page = 0; int cur_entry = 0; while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { int entry_offset = obj_lookup_page * entries_per_page; res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); // check each entry while (res == SPIFFS_OK && cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; if (cur_entry == 0) { spiffs_printf("%4i ", bix); } else if ((cur_entry & 0x3f) == 0) { spiffs_printf(" "); } if (obj_id == SPIFFS_OBJ_ID_FREE) { spiffs_printf(SPIFFS_TEST_VIS_FREE_STR); } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { spiffs_printf(SPIFFS_TEST_VIS_DELE_STR); } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){ spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id)); } else { spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id)); } cur_entry++; if ((cur_entry & 0x3f) == 0) { spiffs_printf("\n"); } } // per entry obj_lookup_page++; } // per object lookup page spiffs_obj_id erase_count; res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&erase_count); SPIFFS_CHECK_RES(res); if (erase_count != (spiffs_obj_id)-1) { spiffs_printf("\tera_cnt: %d\n", erase_count); } else { spiffs_printf("\tera_cnt: N/A\n"); } bix++; } // per block spiffs_printf("era_cnt_max: %d\n", fs->max_erase_count); spiffs_printf("last_errno: %d\n", fs->errno); spiffs_printf("blocks: %d\n", fs->block_count); spiffs_printf("free_blocks: %d\n", fs->free_blocks); spiffs_printf("page_alloc: %d\n", fs->stats_p_allocated); spiffs_printf("page_delet: %d\n", fs->stats_p_deleted); SPIFFS_UNLOCK(fs); return res; }