-
spiffs_gc.c@0:1f44439df816, 2021-04-22 (annotated)
- Committer:
- aguscahya
- Date:
- Thu Apr 22 03:49:45 2021 +0000
- Revision:
- 0:1f44439df816
-
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
aguscahya | 0:1f44439df816 | 1 | #include "spiffs.h" |
aguscahya | 0:1f44439df816 | 2 | #include "spiffs_nucleus.h" |
aguscahya | 0:1f44439df816 | 3 | |
aguscahya | 0:1f44439df816 | 4 | // Erases a logical block and updates the erase counter. |
aguscahya | 0:1f44439df816 | 5 | // If cache is enabled, all pages that might be cached in this block |
aguscahya | 0:1f44439df816 | 6 | // is dropped. |
aguscahya | 0:1f44439df816 | 7 | static s32_t spiffs_gc_erase_block( |
aguscahya | 0:1f44439df816 | 8 | spiffs *fs, |
aguscahya | 0:1f44439df816 | 9 | spiffs_block_ix bix) { |
aguscahya | 0:1f44439df816 | 10 | s32_t res; |
aguscahya | 0:1f44439df816 | 11 | u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); |
aguscahya | 0:1f44439df816 | 12 | s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); |
aguscahya | 0:1f44439df816 | 13 | |
aguscahya | 0:1f44439df816 | 14 | SPIFFS_GC_DBG("gc: erase block %i\n", bix); |
aguscahya | 0:1f44439df816 | 15 | |
aguscahya | 0:1f44439df816 | 16 | // here we ignore res, just try erasing the block |
aguscahya | 0:1f44439df816 | 17 | while (size > 0) { |
aguscahya | 0:1f44439df816 | 18 | SPIFFS_GC_DBG("gc: erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); |
aguscahya | 0:1f44439df816 | 19 | (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); |
aguscahya | 0:1f44439df816 | 20 | addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); |
aguscahya | 0:1f44439df816 | 21 | size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); |
aguscahya | 0:1f44439df816 | 22 | } |
aguscahya | 0:1f44439df816 | 23 | fs->free_blocks++; |
aguscahya | 0:1f44439df816 | 24 | |
aguscahya | 0:1f44439df816 | 25 | // register erase count for this block |
aguscahya | 0:1f44439df816 | 26 | res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, |
aguscahya | 0:1f44439df816 | 27 | SPIFFS_ERASE_COUNT_PADDR(fs, bix), |
aguscahya | 0:1f44439df816 | 28 | sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); |
aguscahya | 0:1f44439df816 | 29 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 30 | |
aguscahya | 0:1f44439df816 | 31 | fs->max_erase_count++; |
aguscahya | 0:1f44439df816 | 32 | if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { |
aguscahya | 0:1f44439df816 | 33 | fs->max_erase_count = 0; |
aguscahya | 0:1f44439df816 | 34 | } |
aguscahya | 0:1f44439df816 | 35 | |
aguscahya | 0:1f44439df816 | 36 | #if SPIFFS_CACHE |
aguscahya | 0:1f44439df816 | 37 | { |
aguscahya | 0:1f44439df816 | 38 | int i; |
aguscahya | 0:1f44439df816 | 39 | for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) { |
aguscahya | 0:1f44439df816 | 40 | spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i); |
aguscahya | 0:1f44439df816 | 41 | } |
aguscahya | 0:1f44439df816 | 42 | } |
aguscahya | 0:1f44439df816 | 43 | #endif |
aguscahya | 0:1f44439df816 | 44 | return res; |
aguscahya | 0:1f44439df816 | 45 | } |
aguscahya | 0:1f44439df816 | 46 | |
aguscahya | 0:1f44439df816 | 47 | // Searches for blocks where all entries are deleted - if one is found, |
aguscahya | 0:1f44439df816 | 48 | // the block is erased. Compared to the non-quick gc, the quick one ensures |
aguscahya | 0:1f44439df816 | 49 | // that no updates are needed on existing objects on pages that are erased. |
aguscahya | 0:1f44439df816 | 50 | s32_t spiffs_gc_quick( |
aguscahya | 0:1f44439df816 | 51 | spiffs *fs) { |
aguscahya | 0:1f44439df816 | 52 | s32_t res = SPIFFS_OK; |
aguscahya | 0:1f44439df816 | 53 | u32_t blocks = fs->block_count; |
aguscahya | 0:1f44439df816 | 54 | spiffs_block_ix cur_block = 0; |
aguscahya | 0:1f44439df816 | 55 | u32_t cur_block_addr = 0; |
aguscahya | 0:1f44439df816 | 56 | int cur_entry = 0; |
aguscahya | 0:1f44439df816 | 57 | spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; |
aguscahya | 0:1f44439df816 | 58 | |
aguscahya | 0:1f44439df816 | 59 | SPIFFS_GC_DBG("gc_quick: running\n", cur_block); |
aguscahya | 0:1f44439df816 | 60 | #if SPIFFS_GC_STATS |
aguscahya | 0:1f44439df816 | 61 | fs->stats_gc_runs++; |
aguscahya | 0:1f44439df816 | 62 | #endif |
aguscahya | 0:1f44439df816 | 63 | |
aguscahya | 0:1f44439df816 | 64 | u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); |
aguscahya | 0:1f44439df816 | 65 | |
aguscahya | 0:1f44439df816 | 66 | // find fully deleted blocks |
aguscahya | 0:1f44439df816 | 67 | // check each block |
aguscahya | 0:1f44439df816 | 68 | while (res == SPIFFS_OK && blocks--) { |
aguscahya | 0:1f44439df816 | 69 | u16_t deleted_pages_in_block = 0; |
aguscahya | 0:1f44439df816 | 70 | |
aguscahya | 0:1f44439df816 | 71 | int obj_lookup_page = 0; |
aguscahya | 0:1f44439df816 | 72 | // check each object lookup page |
aguscahya | 0:1f44439df816 | 73 | while (res == SPIFFS_OK && obj_lookup_page < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 74 | int entry_offset = obj_lookup_page * entries_per_page; |
aguscahya | 0:1f44439df816 | 75 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 76 | 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); |
aguscahya | 0:1f44439df816 | 77 | // check each entry |
aguscahya | 0:1f44439df816 | 78 | while (res == SPIFFS_OK && |
aguscahya | 0:1f44439df816 | 79 | cur_entry - entry_offset < entries_per_page && cur_entry < SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 80 | spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; |
aguscahya | 0:1f44439df816 | 81 | if (obj_id == SPIFFS_OBJ_ID_DELETED) { |
aguscahya | 0:1f44439df816 | 82 | deleted_pages_in_block++; |
aguscahya | 0:1f44439df816 | 83 | } else if (obj_id == SPIFFS_OBJ_ID_FREE) { |
aguscahya | 0:1f44439df816 | 84 | // kill scan, go for next block |
aguscahya | 0:1f44439df816 | 85 | obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); |
aguscahya | 0:1f44439df816 | 86 | break; |
aguscahya | 0:1f44439df816 | 87 | } else { |
aguscahya | 0:1f44439df816 | 88 | // kill scan, go for next block |
aguscahya | 0:1f44439df816 | 89 | obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); |
aguscahya | 0:1f44439df816 | 90 | break; |
aguscahya | 0:1f44439df816 | 91 | } |
aguscahya | 0:1f44439df816 | 92 | cur_entry++; |
aguscahya | 0:1f44439df816 | 93 | } // per entry |
aguscahya | 0:1f44439df816 | 94 | obj_lookup_page++; |
aguscahya | 0:1f44439df816 | 95 | } // per object lookup page |
aguscahya | 0:1f44439df816 | 96 | |
aguscahya | 0:1f44439df816 | 97 | if (res == SPIFFS_OK && deleted_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 98 | // found a fully deleted block |
aguscahya | 0:1f44439df816 | 99 | fs->stats_p_deleted -= deleted_pages_in_block; |
aguscahya | 0:1f44439df816 | 100 | res = spiffs_gc_erase_block(fs, cur_block); |
aguscahya | 0:1f44439df816 | 101 | return res; |
aguscahya | 0:1f44439df816 | 102 | } |
aguscahya | 0:1f44439df816 | 103 | |
aguscahya | 0:1f44439df816 | 104 | cur_entry = 0; |
aguscahya | 0:1f44439df816 | 105 | cur_block++; |
aguscahya | 0:1f44439df816 | 106 | cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); |
aguscahya | 0:1f44439df816 | 107 | } // per block |
aguscahya | 0:1f44439df816 | 108 | |
aguscahya | 0:1f44439df816 | 109 | return res; |
aguscahya | 0:1f44439df816 | 110 | } |
aguscahya | 0:1f44439df816 | 111 | |
aguscahya | 0:1f44439df816 | 112 | // Checks if garbaga collecting is necessary. If so a candidate block is found, |
aguscahya | 0:1f44439df816 | 113 | // cleansed and erased |
aguscahya | 0:1f44439df816 | 114 | s32_t spiffs_gc_check( |
aguscahya | 0:1f44439df816 | 115 | spiffs *fs, |
aguscahya | 0:1f44439df816 | 116 | u32_t len) { |
aguscahya | 0:1f44439df816 | 117 | s32_t res; |
aguscahya | 0:1f44439df816 | 118 | u32_t free_pages = |
aguscahya | 0:1f44439df816 | 119 | (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count |
aguscahya | 0:1f44439df816 | 120 | - fs->stats_p_allocated - fs->stats_p_deleted; |
aguscahya | 0:1f44439df816 | 121 | int tries = 0; |
aguscahya | 0:1f44439df816 | 122 | |
aguscahya | 0:1f44439df816 | 123 | if (fs->free_blocks > 3 && |
aguscahya | 0:1f44439df816 | 124 | len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) { |
aguscahya | 0:1f44439df816 | 125 | return SPIFFS_OK; |
aguscahya | 0:1f44439df816 | 126 | } |
aguscahya | 0:1f44439df816 | 127 | |
aguscahya | 0:1f44439df816 | 128 | //printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len); |
aguscahya | 0:1f44439df816 | 129 | |
aguscahya | 0:1f44439df816 | 130 | do { |
aguscahya | 0:1f44439df816 | 131 | SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n", |
aguscahya | 0:1f44439df816 | 132 | tries, |
aguscahya | 0:1f44439df816 | 133 | fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted), |
aguscahya | 0:1f44439df816 | 134 | len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs)); |
aguscahya | 0:1f44439df816 | 135 | |
aguscahya | 0:1f44439df816 | 136 | spiffs_block_ix *cands; |
aguscahya | 0:1f44439df816 | 137 | int count; |
aguscahya | 0:1f44439df816 | 138 | spiffs_block_ix cand; |
aguscahya | 0:1f44439df816 | 139 | res = spiffs_gc_find_candidate(fs, &cands, &count); |
aguscahya | 0:1f44439df816 | 140 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 141 | if (count == 0) { |
aguscahya | 0:1f44439df816 | 142 | SPIFFS_GC_DBG("gc_check: no candidates, return\n"); |
aguscahya | 0:1f44439df816 | 143 | return res; |
aguscahya | 0:1f44439df816 | 144 | } |
aguscahya | 0:1f44439df816 | 145 | #if SPIFFS_GC_STATS |
aguscahya | 0:1f44439df816 | 146 | fs->stats_gc_runs++; |
aguscahya | 0:1f44439df816 | 147 | #endif |
aguscahya | 0:1f44439df816 | 148 | cand = cands[0]; |
aguscahya | 0:1f44439df816 | 149 | fs->cleaning = 1; |
aguscahya | 0:1f44439df816 | 150 | //printf("gcing: cleaning block %i\n", cand); |
aguscahya | 0:1f44439df816 | 151 | res = spiffs_gc_clean(fs, cand); |
aguscahya | 0:1f44439df816 | 152 | fs->cleaning = 0; |
aguscahya | 0:1f44439df816 | 153 | if (res < 0) { |
aguscahya | 0:1f44439df816 | 154 | SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res); |
aguscahya | 0:1f44439df816 | 155 | } else { |
aguscahya | 0:1f44439df816 | 156 | SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res); |
aguscahya | 0:1f44439df816 | 157 | } |
aguscahya | 0:1f44439df816 | 158 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 159 | |
aguscahya | 0:1f44439df816 | 160 | res = spiffs_gc_erase_page_stats(fs, cand); |
aguscahya | 0:1f44439df816 | 161 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 162 | |
aguscahya | 0:1f44439df816 | 163 | res = spiffs_gc_erase_block(fs, cand); |
aguscahya | 0:1f44439df816 | 164 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 165 | |
aguscahya | 0:1f44439df816 | 166 | free_pages = |
aguscahya | 0:1f44439df816 | 167 | (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count |
aguscahya | 0:1f44439df816 | 168 | - fs->stats_p_allocated - fs->stats_p_deleted; |
aguscahya | 0:1f44439df816 | 169 | |
aguscahya | 0:1f44439df816 | 170 | } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || |
aguscahya | 0:1f44439df816 | 171 | len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); |
aguscahya | 0:1f44439df816 | 172 | SPIFFS_GC_DBG("gc_check: finished\n"); |
aguscahya | 0:1f44439df816 | 173 | |
aguscahya | 0:1f44439df816 | 174 | //printf("gcing finished %i dirty, blocks %i free, %i pages free, %i tries, res %i\n", |
aguscahya | 0:1f44439df816 | 175 | // fs->stats_p_allocated + fs->stats_p_deleted, |
aguscahya | 0:1f44439df816 | 176 | // fs->free_blocks, free_pages, tries, res); |
aguscahya | 0:1f44439df816 | 177 | |
aguscahya | 0:1f44439df816 | 178 | return res; |
aguscahya | 0:1f44439df816 | 179 | } |
aguscahya | 0:1f44439df816 | 180 | |
aguscahya | 0:1f44439df816 | 181 | // Updates page statistics for a block that is about to be erased |
aguscahya | 0:1f44439df816 | 182 | s32_t spiffs_gc_erase_page_stats( |
aguscahya | 0:1f44439df816 | 183 | spiffs *fs, |
aguscahya | 0:1f44439df816 | 184 | spiffs_block_ix bix) { |
aguscahya | 0:1f44439df816 | 185 | s32_t res = SPIFFS_OK; |
aguscahya | 0:1f44439df816 | 186 | int obj_lookup_page = 0; |
aguscahya | 0:1f44439df816 | 187 | u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); |
aguscahya | 0:1f44439df816 | 188 | spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; |
aguscahya | 0:1f44439df816 | 189 | int cur_entry = 0; |
aguscahya | 0:1f44439df816 | 190 | u32_t dele = 0; |
aguscahya | 0:1f44439df816 | 191 | u32_t allo = 0; |
aguscahya | 0:1f44439df816 | 192 | |
aguscahya | 0:1f44439df816 | 193 | // check each object lookup page |
aguscahya | 0:1f44439df816 | 194 | while (res == SPIFFS_OK && obj_lookup_page < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 195 | int entry_offset = obj_lookup_page * entries_per_page; |
aguscahya | 0:1f44439df816 | 196 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 197 | 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); |
aguscahya | 0:1f44439df816 | 198 | // check each entry |
aguscahya | 0:1f44439df816 | 199 | while (res == SPIFFS_OK && |
aguscahya | 0:1f44439df816 | 200 | cur_entry - entry_offset < entries_per_page && cur_entry < SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 201 | spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; |
aguscahya | 0:1f44439df816 | 202 | if (obj_id == SPIFFS_OBJ_ID_FREE) { |
aguscahya | 0:1f44439df816 | 203 | } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { |
aguscahya | 0:1f44439df816 | 204 | dele++; |
aguscahya | 0:1f44439df816 | 205 | } else { |
aguscahya | 0:1f44439df816 | 206 | allo++; |
aguscahya | 0:1f44439df816 | 207 | } |
aguscahya | 0:1f44439df816 | 208 | cur_entry++; |
aguscahya | 0:1f44439df816 | 209 | } // per entry |
aguscahya | 0:1f44439df816 | 210 | obj_lookup_page++; |
aguscahya | 0:1f44439df816 | 211 | } // per object lookup page |
aguscahya | 0:1f44439df816 | 212 | SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele); |
aguscahya | 0:1f44439df816 | 213 | fs->stats_p_allocated -= allo; |
aguscahya | 0:1f44439df816 | 214 | fs->stats_p_deleted -= dele; |
aguscahya | 0:1f44439df816 | 215 | return res; |
aguscahya | 0:1f44439df816 | 216 | } |
aguscahya | 0:1f44439df816 | 217 | |
aguscahya | 0:1f44439df816 | 218 | // Finds block candidates to erase |
aguscahya | 0:1f44439df816 | 219 | s32_t spiffs_gc_find_candidate( |
aguscahya | 0:1f44439df816 | 220 | spiffs *fs, |
aguscahya | 0:1f44439df816 | 221 | spiffs_block_ix **block_candidates, |
aguscahya | 0:1f44439df816 | 222 | int *candidate_count) { |
aguscahya | 0:1f44439df816 | 223 | s32_t res = SPIFFS_OK; |
aguscahya | 0:1f44439df816 | 224 | u32_t blocks = fs->block_count; |
aguscahya | 0:1f44439df816 | 225 | spiffs_block_ix cur_block = 0; |
aguscahya | 0:1f44439df816 | 226 | u32_t cur_block_addr = 0; |
aguscahya | 0:1f44439df816 | 227 | spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; |
aguscahya | 0:1f44439df816 | 228 | int cur_entry = 0; |
aguscahya | 0:1f44439df816 | 229 | |
aguscahya | 0:1f44439df816 | 230 | // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score |
aguscahya | 0:1f44439df816 | 231 | int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t))); |
aguscahya | 0:1f44439df816 | 232 | *candidate_count = 0; |
aguscahya | 0:1f44439df816 | 233 | memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); |
aguscahya | 0:1f44439df816 | 234 | |
aguscahya | 0:1f44439df816 | 235 | // divide up work area into block indices and scores |
aguscahya | 0:1f44439df816 | 236 | // todo alignment? |
aguscahya | 0:1f44439df816 | 237 | spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work; |
aguscahya | 0:1f44439df816 | 238 | s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix)); |
aguscahya | 0:1f44439df816 | 239 | |
aguscahya | 0:1f44439df816 | 240 | *block_candidates = cand_blocks; |
aguscahya | 0:1f44439df816 | 241 | |
aguscahya | 0:1f44439df816 | 242 | u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); |
aguscahya | 0:1f44439df816 | 243 | |
aguscahya | 0:1f44439df816 | 244 | // check each block |
aguscahya | 0:1f44439df816 | 245 | while (res == SPIFFS_OK && blocks--) { |
aguscahya | 0:1f44439df816 | 246 | u16_t deleted_pages_in_block = 0; |
aguscahya | 0:1f44439df816 | 247 | u16_t used_pages_in_block = 0; |
aguscahya | 0:1f44439df816 | 248 | |
aguscahya | 0:1f44439df816 | 249 | int obj_lookup_page = 0; |
aguscahya | 0:1f44439df816 | 250 | // check each object lookup page |
aguscahya | 0:1f44439df816 | 251 | while (res == SPIFFS_OK && obj_lookup_page < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 252 | int entry_offset = obj_lookup_page * entries_per_page; |
aguscahya | 0:1f44439df816 | 253 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 254 | 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); |
aguscahya | 0:1f44439df816 | 255 | // check each entry |
aguscahya | 0:1f44439df816 | 256 | while (res == SPIFFS_OK && |
aguscahya | 0:1f44439df816 | 257 | cur_entry - entry_offset < entries_per_page && cur_entry < SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 258 | spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; |
aguscahya | 0:1f44439df816 | 259 | if (obj_id == SPIFFS_OBJ_ID_FREE) { |
aguscahya | 0:1f44439df816 | 260 | // when a free entry is encountered, scan logic ensures that all following entries are free also |
aguscahya | 0:1f44439df816 | 261 | break; |
aguscahya | 0:1f44439df816 | 262 | } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { |
aguscahya | 0:1f44439df816 | 263 | deleted_pages_in_block++; |
aguscahya | 0:1f44439df816 | 264 | } else { |
aguscahya | 0:1f44439df816 | 265 | used_pages_in_block++; |
aguscahya | 0:1f44439df816 | 266 | } |
aguscahya | 0:1f44439df816 | 267 | cur_entry++; |
aguscahya | 0:1f44439df816 | 268 | } // per entry |
aguscahya | 0:1f44439df816 | 269 | obj_lookup_page++; |
aguscahya | 0:1f44439df816 | 270 | } // per object lookup page |
aguscahya | 0:1f44439df816 | 271 | |
aguscahya | 0:1f44439df816 | 272 | // calculate score and insert into candidate table |
aguscahya | 0:1f44439df816 | 273 | // stoneage sort, but probably not so many blocks |
aguscahya | 0:1f44439df816 | 274 | if (res == SPIFFS_OK && deleted_pages_in_block > 0) { |
aguscahya | 0:1f44439df816 | 275 | // read erase count |
aguscahya | 0:1f44439df816 | 276 | spiffs_obj_id erase_count; |
aguscahya | 0:1f44439df816 | 277 | res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, |
aguscahya | 0:1f44439df816 | 278 | SPIFFS_ERASE_COUNT_PADDR(fs, cur_block), |
aguscahya | 0:1f44439df816 | 279 | sizeof(spiffs_obj_id), (u8_t *)&erase_count); |
aguscahya | 0:1f44439df816 | 280 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 281 | |
aguscahya | 0:1f44439df816 | 282 | spiffs_obj_id erase_age; |
aguscahya | 0:1f44439df816 | 283 | if (fs->max_erase_count > erase_count) { |
aguscahya | 0:1f44439df816 | 284 | erase_age = fs->max_erase_count - erase_count; |
aguscahya | 0:1f44439df816 | 285 | } else { |
aguscahya | 0:1f44439df816 | 286 | erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count); |
aguscahya | 0:1f44439df816 | 287 | } |
aguscahya | 0:1f44439df816 | 288 | |
aguscahya | 0:1f44439df816 | 289 | s32_t score = |
aguscahya | 0:1f44439df816 | 290 | deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + |
aguscahya | 0:1f44439df816 | 291 | used_pages_in_block * SPIFFS_GC_HEUR_W_USED + |
aguscahya | 0:1f44439df816 | 292 | erase_age * SPIFFS_GC_HEUR_W_ERASE_AGE; |
aguscahya | 0:1f44439df816 | 293 | int cand_ix = 0; |
aguscahya | 0:1f44439df816 | 294 | 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); |
aguscahya | 0:1f44439df816 | 295 | while (cand_ix < max_candidates) { |
aguscahya | 0:1f44439df816 | 296 | if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) { |
aguscahya | 0:1f44439df816 | 297 | cand_blocks[cand_ix] = cur_block; |
aguscahya | 0:1f44439df816 | 298 | cand_scores[cand_ix] = score; |
aguscahya | 0:1f44439df816 | 299 | break; |
aguscahya | 0:1f44439df816 | 300 | } else if (cand_scores[cand_ix] < score) { |
aguscahya | 0:1f44439df816 | 301 | int reorder_cand_ix = max_candidates - 2; |
aguscahya | 0:1f44439df816 | 302 | while (reorder_cand_ix >= cand_ix) { |
aguscahya | 0:1f44439df816 | 303 | cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix]; |
aguscahya | 0:1f44439df816 | 304 | cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix]; |
aguscahya | 0:1f44439df816 | 305 | reorder_cand_ix--; |
aguscahya | 0:1f44439df816 | 306 | } |
aguscahya | 0:1f44439df816 | 307 | cand_blocks[cand_ix] = cur_block; |
aguscahya | 0:1f44439df816 | 308 | cand_scores[cand_ix] = score; |
aguscahya | 0:1f44439df816 | 309 | break; |
aguscahya | 0:1f44439df816 | 310 | } |
aguscahya | 0:1f44439df816 | 311 | cand_ix++; |
aguscahya | 0:1f44439df816 | 312 | } |
aguscahya | 0:1f44439df816 | 313 | (*candidate_count)++; |
aguscahya | 0:1f44439df816 | 314 | } |
aguscahya | 0:1f44439df816 | 315 | |
aguscahya | 0:1f44439df816 | 316 | cur_entry = 0; |
aguscahya | 0:1f44439df816 | 317 | cur_block++; |
aguscahya | 0:1f44439df816 | 318 | cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); |
aguscahya | 0:1f44439df816 | 319 | } // per block |
aguscahya | 0:1f44439df816 | 320 | |
aguscahya | 0:1f44439df816 | 321 | return res; |
aguscahya | 0:1f44439df816 | 322 | } |
aguscahya | 0:1f44439df816 | 323 | |
aguscahya | 0:1f44439df816 | 324 | typedef enum { |
aguscahya | 0:1f44439df816 | 325 | FIND_OBJ_DATA, |
aguscahya | 0:1f44439df816 | 326 | MOVE_OBJ_DATA, |
aguscahya | 0:1f44439df816 | 327 | MOVE_OBJ_IX, |
aguscahya | 0:1f44439df816 | 328 | FINISHED |
aguscahya | 0:1f44439df816 | 329 | } spiffs_gc_clean_state; |
aguscahya | 0:1f44439df816 | 330 | |
aguscahya | 0:1f44439df816 | 331 | typedef struct { |
aguscahya | 0:1f44439df816 | 332 | spiffs_gc_clean_state state; |
aguscahya | 0:1f44439df816 | 333 | spiffs_obj_id cur_obj_id; |
aguscahya | 0:1f44439df816 | 334 | spiffs_span_ix cur_objix_spix; |
aguscahya | 0:1f44439df816 | 335 | spiffs_page_ix cur_objix_pix; |
aguscahya | 0:1f44439df816 | 336 | int stored_scan_entry_index; |
aguscahya | 0:1f44439df816 | 337 | u8_t obj_id_found; |
aguscahya | 0:1f44439df816 | 338 | } spiffs_gc; |
aguscahya | 0:1f44439df816 | 339 | |
aguscahya | 0:1f44439df816 | 340 | // Empties given block by moving all data into free pages of another block |
aguscahya | 0:1f44439df816 | 341 | // Strategy: |
aguscahya | 0:1f44439df816 | 342 | // loop: |
aguscahya | 0:1f44439df816 | 343 | // scan object lookup for object data pages |
aguscahya | 0:1f44439df816 | 344 | // for first found id, check spix and load corresponding object index page to memory |
aguscahya | 0:1f44439df816 | 345 | // push object scan lookup entry index |
aguscahya | 0:1f44439df816 | 346 | // rescan object lookup, find data pages with same id and referenced by same object index |
aguscahya | 0:1f44439df816 | 347 | // move data page, update object index in memory |
aguscahya | 0:1f44439df816 | 348 | // when reached end of lookup, store updated object index |
aguscahya | 0:1f44439df816 | 349 | // pop object scan lookup entry index |
aguscahya | 0:1f44439df816 | 350 | // repeat loop until end of object lookup |
aguscahya | 0:1f44439df816 | 351 | // scan object lookup again for remaining object index pages, move to new page in other block |
aguscahya | 0:1f44439df816 | 352 | // |
aguscahya | 0:1f44439df816 | 353 | s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { |
aguscahya | 0:1f44439df816 | 354 | s32_t res = SPIFFS_OK; |
aguscahya | 0:1f44439df816 | 355 | u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); |
aguscahya | 0:1f44439df816 | 356 | int cur_entry = 0; |
aguscahya | 0:1f44439df816 | 357 | spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; |
aguscahya | 0:1f44439df816 | 358 | spiffs_gc gc; |
aguscahya | 0:1f44439df816 | 359 | spiffs_page_ix cur_pix = 0; |
aguscahya | 0:1f44439df816 | 360 | spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; |
aguscahya | 0:1f44439df816 | 361 | spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; |
aguscahya | 0:1f44439df816 | 362 | |
aguscahya | 0:1f44439df816 | 363 | SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix); |
aguscahya | 0:1f44439df816 | 364 | |
aguscahya | 0:1f44439df816 | 365 | memset(&gc, 0, sizeof(spiffs_gc)); |
aguscahya | 0:1f44439df816 | 366 | gc.state = FIND_OBJ_DATA; |
aguscahya | 0:1f44439df816 | 367 | |
aguscahya | 0:1f44439df816 | 368 | if (fs->free_cursor_block_ix == bix) { |
aguscahya | 0:1f44439df816 | 369 | // move free cursor to next block, cannot use free pages from the block we want to clean |
aguscahya | 0:1f44439df816 | 370 | fs->free_cursor_block_ix = (bix+1)%fs->block_count; |
aguscahya | 0:1f44439df816 | 371 | fs->free_cursor_obj_lu_entry = 0; |
aguscahya | 0:1f44439df816 | 372 | SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix); |
aguscahya | 0:1f44439df816 | 373 | } |
aguscahya | 0:1f44439df816 | 374 | |
aguscahya | 0:1f44439df816 | 375 | while (res == SPIFFS_OK && gc.state != FINISHED) { |
aguscahya | 0:1f44439df816 | 376 | SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry); |
aguscahya | 0:1f44439df816 | 377 | gc.obj_id_found = 0; |
aguscahya | 0:1f44439df816 | 378 | |
aguscahya | 0:1f44439df816 | 379 | // scan through lookup pages |
aguscahya | 0:1f44439df816 | 380 | int obj_lookup_page = cur_entry / entries_per_page; |
aguscahya | 0:1f44439df816 | 381 | u8_t scan = 1; |
aguscahya | 0:1f44439df816 | 382 | // check each object lookup page |
aguscahya | 0:1f44439df816 | 383 | while (scan && res == SPIFFS_OK && obj_lookup_page < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 384 | int entry_offset = obj_lookup_page * entries_per_page; |
aguscahya | 0:1f44439df816 | 385 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 386 | 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), |
aguscahya | 0:1f44439df816 | 387 | SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); |
aguscahya | 0:1f44439df816 | 388 | // check each entry |
aguscahya | 0:1f44439df816 | 389 | while (scan && res == SPIFFS_OK && |
aguscahya | 0:1f44439df816 | 390 | cur_entry - entry_offset < entries_per_page && cur_entry < SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) { |
aguscahya | 0:1f44439df816 | 391 | spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; |
aguscahya | 0:1f44439df816 | 392 | cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry); |
aguscahya | 0:1f44439df816 | 393 | |
aguscahya | 0:1f44439df816 | 394 | // act upon object id depending on gc state |
aguscahya | 0:1f44439df816 | 395 | switch (gc.state) { |
aguscahya | 0:1f44439df816 | 396 | case FIND_OBJ_DATA: |
aguscahya | 0:1f44439df816 | 397 | if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && |
aguscahya | 0:1f44439df816 | 398 | ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) { |
aguscahya | 0:1f44439df816 | 399 | SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id); |
aguscahya | 0:1f44439df816 | 400 | gc.obj_id_found = 1; |
aguscahya | 0:1f44439df816 | 401 | gc.cur_obj_id = obj_id; |
aguscahya | 0:1f44439df816 | 402 | scan = 0; |
aguscahya | 0:1f44439df816 | 403 | } |
aguscahya | 0:1f44439df816 | 404 | break; |
aguscahya | 0:1f44439df816 | 405 | case MOVE_OBJ_DATA: |
aguscahya | 0:1f44439df816 | 406 | if (obj_id == gc.cur_obj_id) { |
aguscahya | 0:1f44439df816 | 407 | spiffs_page_header p_hdr; |
aguscahya | 0:1f44439df816 | 408 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 409 | 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); |
aguscahya | 0:1f44439df816 | 410 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 411 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix); |
aguscahya | 0:1f44439df816 | 412 | if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) { |
aguscahya | 0:1f44439df816 | 413 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n"); |
aguscahya | 0:1f44439df816 | 414 | } else { |
aguscahya | 0:1f44439df816 | 415 | spiffs_page_ix new_data_pix; |
aguscahya | 0:1f44439df816 | 416 | if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { |
aguscahya | 0:1f44439df816 | 417 | // move page |
aguscahya | 0:1f44439df816 | 418 | res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix); |
aguscahya | 0:1f44439df816 | 419 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix %04x:%04x page %04x to %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix); |
aguscahya | 0:1f44439df816 | 420 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 421 | // move wipes obj_lu, reload it |
aguscahya | 0:1f44439df816 | 422 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 423 | 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), |
aguscahya | 0:1f44439df816 | 424 | SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); |
aguscahya | 0:1f44439df816 | 425 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 426 | } else { |
aguscahya | 0:1f44439df816 | 427 | // page is deleted but not deleted in lookup, scrap it |
aguscahya | 0:1f44439df816 | 428 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix); |
aguscahya | 0:1f44439df816 | 429 | res = spiffs_page_delete(fs, cur_pix); |
aguscahya | 0:1f44439df816 | 430 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 431 | new_data_pix = SPIFFS_OBJ_ID_FREE; |
aguscahya | 0:1f44439df816 | 432 | } |
aguscahya | 0:1f44439df816 | 433 | // update memory representation of object index page with new data page |
aguscahya | 0:1f44439df816 | 434 | if (gc.cur_objix_spix == 0) { |
aguscahya | 0:1f44439df816 | 435 | // update object index header page |
aguscahya | 0:1f44439df816 | 436 | ((spiffs_page_ix*)((u8_t*)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix; |
aguscahya | 0:1f44439df816 | 437 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); |
aguscahya | 0:1f44439df816 | 438 | } else { |
aguscahya | 0:1f44439df816 | 439 | // update object index page |
aguscahya | 0:1f44439df816 | 440 | ((spiffs_page_ix*)((u8_t*)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix; |
aguscahya | 0:1f44439df816 | 441 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); |
aguscahya | 0:1f44439df816 | 442 | } |
aguscahya | 0:1f44439df816 | 443 | } |
aguscahya | 0:1f44439df816 | 444 | } |
aguscahya | 0:1f44439df816 | 445 | break; |
aguscahya | 0:1f44439df816 | 446 | case MOVE_OBJ_IX: |
aguscahya | 0:1f44439df816 | 447 | if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && |
aguscahya | 0:1f44439df816 | 448 | (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) { |
aguscahya | 0:1f44439df816 | 449 | // found an index object id |
aguscahya | 0:1f44439df816 | 450 | spiffs_page_header p_hdr; |
aguscahya | 0:1f44439df816 | 451 | spiffs_page_ix new_pix; |
aguscahya | 0:1f44439df816 | 452 | // load header |
aguscahya | 0:1f44439df816 | 453 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 454 | 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); |
aguscahya | 0:1f44439df816 | 455 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 456 | if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { |
aguscahya | 0:1f44439df816 | 457 | // move page |
aguscahya | 0:1f44439df816 | 458 | res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix); |
aguscahya | 0:1f44439df816 | 459 | SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix); |
aguscahya | 0:1f44439df816 | 460 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 461 | spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, obj_id, p_hdr.span_ix, new_pix, 0); |
aguscahya | 0:1f44439df816 | 462 | // move wipes obj_lu, reload it |
aguscahya | 0:1f44439df816 | 463 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 464 | 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), |
aguscahya | 0:1f44439df816 | 465 | SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); |
aguscahya | 0:1f44439df816 | 466 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 467 | } else { |
aguscahya | 0:1f44439df816 | 468 | // page is deleted but not deleted in lookup, scrap it |
aguscahya | 0:1f44439df816 | 469 | SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix); |
aguscahya | 0:1f44439df816 | 470 | res = spiffs_page_delete(fs, cur_pix); |
aguscahya | 0:1f44439df816 | 471 | if (res == SPIFFS_OK) { |
aguscahya | 0:1f44439df816 | 472 | spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0); |
aguscahya | 0:1f44439df816 | 473 | } |
aguscahya | 0:1f44439df816 | 474 | } |
aguscahya | 0:1f44439df816 | 475 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 476 | } |
aguscahya | 0:1f44439df816 | 477 | break; |
aguscahya | 0:1f44439df816 | 478 | default: |
aguscahya | 0:1f44439df816 | 479 | scan = 0; |
aguscahya | 0:1f44439df816 | 480 | break; |
aguscahya | 0:1f44439df816 | 481 | } |
aguscahya | 0:1f44439df816 | 482 | cur_entry++; |
aguscahya | 0:1f44439df816 | 483 | } // per entry |
aguscahya | 0:1f44439df816 | 484 | obj_lookup_page++; |
aguscahya | 0:1f44439df816 | 485 | } // per object lookup page |
aguscahya | 0:1f44439df816 | 486 | |
aguscahya | 0:1f44439df816 | 487 | if (res != SPIFFS_OK) break; |
aguscahya | 0:1f44439df816 | 488 | |
aguscahya | 0:1f44439df816 | 489 | // state finalization and switch |
aguscahya | 0:1f44439df816 | 490 | switch (gc.state) { |
aguscahya | 0:1f44439df816 | 491 | case FIND_OBJ_DATA: |
aguscahya | 0:1f44439df816 | 492 | if (gc.obj_id_found) { |
aguscahya | 0:1f44439df816 | 493 | // find out corresponding obj ix page and load it to memory |
aguscahya | 0:1f44439df816 | 494 | spiffs_page_header p_hdr; |
aguscahya | 0:1f44439df816 | 495 | spiffs_page_ix objix_pix; |
aguscahya | 0:1f44439df816 | 496 | gc.stored_scan_entry_index = cur_entry; |
aguscahya | 0:1f44439df816 | 497 | cur_entry = 0; |
aguscahya | 0:1f44439df816 | 498 | gc.state = MOVE_OBJ_DATA; |
aguscahya | 0:1f44439df816 | 499 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 500 | 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); |
aguscahya | 0:1f44439df816 | 501 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 502 | gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix); |
aguscahya | 0:1f44439df816 | 503 | SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix); |
aguscahya | 0:1f44439df816 | 504 | res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix); |
aguscahya | 0:1f44439df816 | 505 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 506 | SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix); |
aguscahya | 0:1f44439df816 | 507 | res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, |
aguscahya | 0:1f44439df816 | 508 | 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); |
aguscahya | 0:1f44439df816 | 509 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 510 | SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix); |
aguscahya | 0:1f44439df816 | 511 | gc.cur_objix_pix = objix_pix; |
aguscahya | 0:1f44439df816 | 512 | } else { |
aguscahya | 0:1f44439df816 | 513 | gc.state = MOVE_OBJ_IX; |
aguscahya | 0:1f44439df816 | 514 | cur_entry = 0; // restart entry scan index |
aguscahya | 0:1f44439df816 | 515 | } |
aguscahya | 0:1f44439df816 | 516 | break; |
aguscahya | 0:1f44439df816 | 517 | case MOVE_OBJ_DATA: { |
aguscahya | 0:1f44439df816 | 518 | // store modified objix (hdr) page |
aguscahya | 0:1f44439df816 | 519 | spiffs_page_ix new_objix_pix; |
aguscahya | 0:1f44439df816 | 520 | gc.state = FIND_OBJ_DATA; |
aguscahya | 0:1f44439df816 | 521 | cur_entry = gc.stored_scan_entry_index; |
aguscahya | 0:1f44439df816 | 522 | if (gc.cur_objix_spix == 0) { |
aguscahya | 0:1f44439df816 | 523 | // store object index header page |
aguscahya | 0:1f44439df816 | 524 | res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix); |
aguscahya | 0:1f44439df816 | 525 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0); |
aguscahya | 0:1f44439df816 | 526 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 527 | } else { |
aguscahya | 0:1f44439df816 | 528 | // store object index page |
aguscahya | 0:1f44439df816 | 529 | spiffs_page_ix new_objix_pix; |
aguscahya | 0:1f44439df816 | 530 | res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix); |
aguscahya | 0:1f44439df816 | 531 | SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix); |
aguscahya | 0:1f44439df816 | 532 | SPIFFS_CHECK_RES(res); |
aguscahya | 0:1f44439df816 | 533 | spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); |
aguscahya | 0:1f44439df816 | 534 | } |
aguscahya | 0:1f44439df816 | 535 | } |
aguscahya | 0:1f44439df816 | 536 | break; |
aguscahya | 0:1f44439df816 | 537 | case MOVE_OBJ_IX: |
aguscahya | 0:1f44439df816 | 538 | gc.state = FINISHED; |
aguscahya | 0:1f44439df816 | 539 | break; |
aguscahya | 0:1f44439df816 | 540 | default: |
aguscahya | 0:1f44439df816 | 541 | cur_entry = 0; |
aguscahya | 0:1f44439df816 | 542 | break; |
aguscahya | 0:1f44439df816 | 543 | } |
aguscahya | 0:1f44439df816 | 544 | SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state); |
aguscahya | 0:1f44439df816 | 545 | } // while state != FINISHED |
aguscahya | 0:1f44439df816 | 546 | |
aguscahya | 0:1f44439df816 | 547 | |
aguscahya | 0:1f44439df816 | 548 | return res; |
aguscahya | 0:1f44439df816 | 549 | } |