some refactoring

This commit is contained in:
Peter Andersson
2013-07-07 23:10:46 +02:00
parent c421181286
commit 4702090739
19 changed files with 890 additions and 785 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -1
View File
@@ -1,4 +1,6 @@
FILES += spiffs_nucleus.c \
spiffs_gc.c \
spiffs_hydrogen.c \
spiffs_cache.c
spiffs_cache.c \
spiffs_check.c
+15 -13
View File
@@ -13,23 +13,23 @@
#include "spiffs_config.h"
#define SPIFFS_OK 0
#define SPIFFS_ERR_FULL -10000
#define SPIFFS_ERR_NOT_FOUND -10001
#define SPIFFS_ERR_END_OF_OBJECT -10002
#define SPIFFS_ERR_DELETED -10003
#define SPIFFS_ERR_NOT_FINALIZED -10004
#define SPIFFS_ERR_NOT_INDEX -10005
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10006
#define SPIFFS_ERR_NOT_MOUNTED -10000
#define SPIFFS_ERR_FULL -10001
#define SPIFFS_ERR_NOT_FOUND -10002
#define SPIFFS_ERR_END_OF_OBJECT -10003
#define SPIFFS_ERR_DELETED -10004
#define SPIFFS_ERR_NOT_FINALIZED -10005
#define SPIFFS_ERR_NOT_INDEX -10006
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
#define SPIFFS_ERR_FILE_CLOSED -10008
#define SPIFFS_ERR_FILE_DELETED -10009
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
#define SPIFFS_ERR_IS_INDEX -10011
#define SPIFFS_ERR_INDEX_WRONG_ID -10012
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10013
#define SPIFFS_ERR_DATA_WRONG_ID -10014
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10012
#define SPIFFS_ERR_INDEX_WRONG_ID -10013
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014
#define SPIFFS_ERR_DATA_WRONG_ID -10015
#define SPIFFS_COUNTINUE -11000
// spi read call type
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
@@ -173,7 +173,7 @@ typedef struct {
// functions
/**
* Initializes the file system dynamic parameters
* Initializes the file system dynamic parameters and mounts the filesystem
* @param fs the file system struct
* @param config the physical and logical configuration of the file system
* @param work a memory work buffer comprising 2*config->log_page_size
@@ -183,10 +183,12 @@ typedef struct {
* @param cache memory for cache, may be null
* @param cache_size memory size of cache
*/
s32_t SPIFFS_init(spiffs *fs, spiffs_config *config, u8_t *work,
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
u8_t *fd_space, u32_t fd_space_size,
void *cache, u32_t cache_size);
void SPIFFS_unmount(spiffs *fs);
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_attr attr);
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_attr attr, spiffs_mode mode);
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
+1 -1
View File
@@ -236,7 +236,7 @@ spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
return cp;
}
void spiffs_cache_fh_release(spiffs *fs, spiffs_cache_page *cp) {
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
if (cp == 0) return;
int i;
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
+220
View File
@@ -0,0 +1,220 @@
/*
* spiffs_check.c
*
* Created on: Jul 7, 2013
* Author: petera
*/
#include "spiffs.h"
#include "spiffs_nucleus.h"
static s32_t spiffs_object_check_data_page(
spiffs *fs,
spiffs_obj_id obj_id,
spiffs_span_ix data_spix,
spiffs_page_ix *pix) {
s32_t res;
spiffs_page_ix objix_pix;
spiffs_page_ix ref_pix;
// calculate object index span index for given data page span index
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
// find obj index for obj id and span index
res = spiffs_obj_lu_find_id_and_index(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, &objix_pix);
SPIFFS_CHECK_RES(res);
// load obj index
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs),
(u8_t*)fs->work);
SPIFFS_CHECK_RES(res);
if (objix_spix == 0) {
// get referenced page from object index header
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
ref_pix = ((spiffs_page_ix*)((void*)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
} else {
// get referenced page from object index
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
ref_pix = ((spiffs_page_ix*)((void*)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
}
*pix = ref_pix;
return res;
}
static s32_t spiffs_area_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
u8_t delete_page = 0;
s32_t res = SPIFFS_OK;
// check validity, take actions
if (lu_obj_id == SPIFFS_OBJ_ID_ERASED) {
// TODO
if (p_hdr->flags & SPIFFS_PH_FLAG_DELET) {
print("WARNING: pix %04x deleted in lu but not on page\n", cur_pix);
// page can be removed if not referenced by object index
spiffs_page_ix ref_pix;
res = spiffs_object_check_data_page(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix);
if (res == SPIFFS_ERR_NOT_FOUND) {
// no object with this id, so remove page safely
res = SPIFFS_OK;
delete_page = 1;
ref_pix = cur_pix+1;
}
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
if (ref_pix != cur_pix) {
delete_page = 1;
} else {
// TODO - page referenced by object index but deleted in lu
}
}
} else if (lu_obj_id == SPIFFS_OBJ_ID_FREE) {
// TODO
if (p_hdr->flags != 0xff) {
print("WARNING: pix %04x free in lu but not on page\n", cur_pix);
// page can be removed if not referenced by object index
spiffs_page_ix ref_pix;
res = spiffs_object_check_data_page(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix);
if (res == SPIFFS_ERR_NOT_FOUND) {
// no object with this id, so remove page safely
res = SPIFFS_OK;
delete_page = 1;
ref_pix = cur_pix+1;
}
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
if (ref_pix != cur_pix) {
delete_page = 1;
} else {
// TODO - page referenced by object index but free in lu
}
}
} else {
// TODO
if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
print("WARNING: pix %04x busy in lu but free on page\n", cur_pix);
delete_page = 1;
}
if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
print("WARNING: pix %04x busy but not final\n", cur_pix);
// page can be removed if not referenced by object index
spiffs_page_ix ref_pix;
res = spiffs_object_check_data_page(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix);
if (res == SPIFFS_ERR_NOT_FOUND) {
// no object with this id, so remove page safely
res = SPIFFS_OK;
delete_page = 1;
ref_pix = cur_pix+1;
}
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
if (ref_pix != cur_pix) {
delete_page = 1;
} else {
// TODO - page referenced by object index but not final
}
}
if (p_hdr->obj_id != lu_obj_id) {
print("WARNING: pix %04x has id %04x in lu but %04x on page\n", cur_pix, lu_obj_id, p_hdr->obj_id);
if (p_hdr->obj_id == SPIFFS_OBJ_ID_FREE || p_hdr->obj_id == SPIFFS_OBJ_ID_ERASED) {
delete_page = 1;
}
}
if (lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
// index page
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
print("WARNING: pix %04x marked as index in lu but as data on page\n", cur_pix);
}
} else {
// data page
if ((p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0) {
print("WARNING: pix %04x as data in lu but as index on page\n", cur_pix);
}
}
}
if (delete_page) {
print("FIX: deleting page %04x\n", cur_pix);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
return res;
}
static s32_t spiffs_area_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
u32_t user_data, void *user_p) {
s32_t res = SPIFFS_OK;
spiffs_page_header p_hdr;
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
// load header
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
int reload_lu = 0;
res = spiffs_area_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
if (reload_lu) {
// reload lu
u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
int obj_lookup_page = cur_entry / entries_per_page;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_BLOCK_TO_PADDR(fs, cur_block) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res);
}
if (res == SPIFFS_OK) {
return SPIFFS_VIS_COUNTINUE;
}
return res;
}
// Scans all object look up. For each entry, corresponding page header is checked for validity.
// If an object index header page is found, this is checked
s32_t spiffs_area_check(spiffs *fs, u8_t check_all_objects) {
s32_t res = SPIFFS_OK;
s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs);
spiffs_block_ix cur_block = 0;
u32_t cur_block_addr = SPIFFS_BLOCK_TO_PADDR(fs, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_area_check_v, 0, 0, 0, 0);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
return res;
}
// Scans all object look up for consistency within given object id. When an index is found, it is loaded
// and checked for validity against each referenced page. When an object index header is found, size is
// checked.
// When an index points to a bad page (deleted, other id, bad span index, etc), the whole area is searched
// for correct page, followed by an index update. If no such page is found, a free page is allocated and
// referenced instead meaning there will be a page hole filled with 0xff in the file.
s32_t spiffs_object_check(spiffs *fs, spiffs_obj_id obj_id, u8_t mend) {
s32_t res = SPIFFS_OK;
spiffs_page_ix pix;
spiffs_page_object_ix_header objix_hdr;
// find obj index header for obj id
res = spiffs_obj_lu_find_id_and_index(fs, obj_id, 0, &pix);
SPIFFS_CHECK_RES(res);
// load header, get size
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t*)&objix_hdr);
SPIFFS_CHECK_RES(res);
return res;
}
+420
View File
@@ -0,0 +1,420 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
s32_t spiffs_gc_check(
spiffs *fs,
u32_t len) {
s32_t res;
u32_t free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count
- fs->stats_p_allocated - fs->stats_p_deleted;
int tries = 0;
if (fs->free_blocks > 2 &&
len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) {
return SPIFFS_OK;
}
do {
SPIFFS_GC_DBG("\ngc_check #i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
tries,
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
spiffs_block_ix *cands;
int count;
spiffs_block_ix cand;
res = spiffs_gc_find_candidate(fs, &cands, &count);
SPIFFS_CHECK_RES(res);
if (count == 0) {
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
return res;
}
#if SPIFFS_GC_STATS
fs->stats_gc_runs++;
#endif
cand = cands[0];
res = spiffs_gc_clean(fs, cand);
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
SPIFFS_CHECK_RES(res);
res = spiffs_gc_erase_page_stats(fs, cand);
SPIFFS_CHECK_RES(res);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, cand);
s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);
// here we ignore res, just try erasing the block
SPIFFS_GC_DBG("gc_check: erase block %i\n", cand);
while (size > 0) {
SPIFFS_DBG("gc_check: erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
res = fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
}
fs->free_blocks++;
free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count
- fs->stats_p_allocated - fs->stats_p_deleted;
#if SPIFFS_CACHE
{
int i;
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, cand) + i);
}
}
#endif
} while (tries++ < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
SPIFFS_GC_DBG("gc_check: finished\n");
return res;
}
s32_t spiffs_gc_erase_page_stats(
spiffs *fs,
spiffs_block_ix bix) {
s32_t res = SPIFFS_OK;
int obj_lookup_page = 0;
u32_t 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;
int cur_entry = 0;
u32_t dele = 0;
u32_t allo = 0;
// check each object lookup page
while (res == SPIFFS_OK && obj_lookup_page < 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, SPIFFS_BLOCK_TO_PADDR(fs, bix) + 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 < 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) {
} else if (obj_id == SPIFFS_OBJ_ID_ERASED) {
dele++;
} else {
allo++;
}
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele);
fs->stats_p_allocated -= allo;
fs->stats_p_deleted -= dele;
return res;
}
s32_t spiffs_gc_find_candidate(
spiffs *fs,
spiffs_block_ix **block_candidates,
int *candidate_count) {
s32_t res = SPIFFS_OK;
u32_t blocks = fs->block_count;
spiffs_block_ix cur_block = 0;
u32_t cur_block_addr = SPIFFS_CFG_PHYS_ADDR(fs);
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/(int)score
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(int)));
*candidate_count = 0;
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;
int *cand_scores = (int *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
*block_candidates = cand_blocks;
u32_t 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 < 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 < 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
break;
} else if (obj_id == SPIFFS_OBJ_ID_ERASED) {
deleted_pages_in_block++;
} else {
used_pages_in_block++;
}
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
// calculate score and insert into candidate table
// stoneage sort, but probably not so many blocks
if (res == SPIFFS_OK && deleted_pages_in_block > 0) {
int score = deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + used_pages_in_block * SPIFFS_GC_HEUR_W_USED;
int cand_ix = 0;
SPIFFS_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;
}
typedef enum {
MOVE_OBJ_IX,
FIND_OBJ_DATA,
MOVE_OBJ_DATA,
FINISHED
} spiffs_gc_clean_state;
typedef struct {
spiffs_gc_clean_state state;
spiffs_obj_id cur_obj_id;
spiffs_span_ix cur_objix_spix;
spiffs_page_ix cur_objix_pix;
int stored_scan_entry_index;
u8_t obj_id_found;
} spiffs_gc;
// Empties given block by moving all data into free pages of another block
// Strategy:
// scan object lookup for object index pages, move to new page in other block
// loop:
// scan object lookup for object data pages
// for first found id, check spix and load corresponding object index page to memory
// push object scan lookup entry index
// rescan object lookup, find data pages with same id and referenced by same object index
// move data page, update object index in memory
// when reached end of lookup, store updated object index
// pop object scan lookup entry index
// repeat loop until end of object lookup
//
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
s32_t res = SPIFFS_OK;
u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
int cur_entry = 0;
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
spiffs_gc gc;
spiffs_page_ix cur_pix = 0;
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
memset(&gc, 0, sizeof(spiffs_gc));
gc.state = MOVE_OBJ_IX;
if (fs->free_cursor_block_ix == bix) {
// move free cursor to next block
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
fs->free_cursor_obj_lu_entry = 0;
SPIFFS_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix);
}
while (res == SPIFFS_OK && gc.state != FINISHED) {
SPIFFS_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry);
gc.obj_id_found = 0;
// scan through lookup pages
int obj_lookup_page = cur_entry / entries_per_page;
u8_t scan = 1;
// check each object lookup page
while (scan && res == SPIFFS_OK && obj_lookup_page < 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, SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
// check each entry
while (scan && res == SPIFFS_OK &&
cur_entry - entry_offset < entries_per_page && cur_entry < SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
// act upon object id depending on gc state
switch (gc.state) {
case MOVE_OBJ_IX:
if (obj_id != SPIFFS_OBJ_ID_ERASED && obj_id != SPIFFS_OBJ_ID_FREE && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
// found an index object id
spiffs_page_header p_hdr;
spiffs_page_ix new_pix;
// load header
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
// move page
res = spiffs_page_move(fs, 0, 0, &p_hdr, cur_pix, &new_pix);
SPIFFS_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, obj_id, p_hdr.span_ix, new_pix, 0);
// move wipes obj_lu, reload it
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res);
} else {
// page is deleted but not deleted in lookup, scrap it
SPIFFS_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
res = spiffs_page_delete(fs, cur_pix);
if (res == SPIFFS_OK) {
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
}
}
SPIFFS_CHECK_RES(res);
}
break;
case FIND_OBJ_DATA:
if (obj_id != SPIFFS_OBJ_ID_ERASED && obj_id != SPIFFS_OBJ_ID_FREE) {
SPIFFS_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id);
gc.obj_id_found = 1;
gc.cur_obj_id = obj_id;
scan = 0;
}
break;
case MOVE_OBJ_DATA:
if (obj_id == gc.cur_obj_id) {
spiffs_page_header p_hdr;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
SPIFFS_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
} else {
spiffs_page_ix new_data_pix;
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
// move page
res = spiffs_page_move(fs, 0, 0, &p_hdr, cur_pix, &new_data_pix);
SPIFFS_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);
SPIFFS_CHECK_RES(res);
// move wipes obj_lu, reload it
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res);
} else {
// page is deleted but not deleted in lookup, scrap it
SPIFFS_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
new_data_pix = SPIFFS_OBJ_ID_FREE;
}
// update memory representation of object index page with new data page
if (gc.cur_objix_spix == 0) {
// update object index header page
((spiffs_page_ix*)((void*)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
SPIFFS_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));
} else {
// update object index page
((spiffs_page_ix*)((void*)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
SPIFFS_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));
}
}
}
break;
default:
scan = 0;
break;
}
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
if (res != SPIFFS_OK) break;
// state finalization and switch
switch (gc.state) {
case MOVE_OBJ_IX:
gc.state = FIND_OBJ_DATA;
cur_entry = 0; // restart entry scan index
break;
case FIND_OBJ_DATA:
if (gc.obj_id_found) {
// find out corresponding obj ix page and load it to memory
spiffs_page_header p_hdr;
spiffs_page_ix objix_pix;
gc.stored_scan_entry_index = cur_entry;
cur_entry = 0;
gc.state = MOVE_OBJ_DATA;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
SPIFFS_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix);
res = spiffs_obj_lu_find_id_and_index(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, &objix_pix);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix);
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
SPIFFS_CHECK_RES(res);
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id, gc.cur_objix_spix);
gc.cur_objix_pix = objix_pix;
} else {
gc.state = FINISHED;
}
break;
case MOVE_OBJ_DATA: {
// store modified objix (hdr) page
spiffs_page_ix new_objix_pix;
gc.state = FIND_OBJ_DATA;
cur_entry = gc.stored_scan_entry_index;
if (gc.cur_objix_spix == 0) {
// store object index header page
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix);
SPIFFS_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0);
SPIFFS_CHECK_RES(res);
} else {
// store object index page
spiffs_page_ix new_objix_pix;
res = spiffs_page_move(fs, 0, fs->work, 0, gc.cur_objix_pix, &new_objix_pix);
SPIFFS_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix);
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
}
}
break;
default:
cur_entry = 0;
break;
}
SPIFFS_DBG("gc_clean: state-> %i\n", gc.state);
} // while state != FINISHED
return res;
}
+111 -7
View File
@@ -10,7 +10,89 @@
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
u8_t *fd_space, u32_t fd_space_size,
void *cache, u32_t cache_size) {
SPIFFS_LOCK(fs);
memset(fs, 0, sizeof(spiffs));
memcpy(&fs->cfg, config, sizeof(spiffs_config));
fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
fs->work = &work[0];
fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
memset(fd_space, 0, fd_space_size);
// align fd_space pointer to pointer size byte boundary, below is safe
u8_t ptr_size = sizeof(void*);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
u8_t addr_lsb = ((u8_t)fd_space) & (ptr_size-1);
#pragma GCC diagnostic pop
if (addr_lsb) {
fd_space += (ptr_size-addr_lsb);
fd_space_size -= (ptr_size-addr_lsb);
}
fs->fd_space = fd_space;
fs->fd_count = (fd_space_size/sizeof(spiffs_fd));
// align cache pointer to 4 byte boundary, below is safe
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
addr_lsb = ((u8_t)cache) & (ptr_size-1);
#pragma GCC diagnostic pop
if (addr_lsb) {
cache += (ptr_size-addr_lsb);
cache_size -= (ptr_size-addr_lsb);
}
if (cache_size & (ptr_size-1)) {
cache_size -= (cache_size & (ptr_size-1));
}
#if SPIFFS_CACHE
fs->cache = cache;
fs->cache_size = cache_size;
spiffs_cache_init(fs);
#endif
s32_t res = spiffs_obj_lu_scan(fs);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs));
SPIFFS_DBG("object lookup pages: %i\n", SPIFFS_OBJ_LOOKUP_PAGES(fs));
SPIFFS_DBG("page pages per block: %i\n", SPIFFS_PAGES_PER_BLOCK(fs));
SPIFFS_DBG("page header length: %i\n", sizeof(spiffs_page_header));
SPIFFS_DBG("object header index entries: %i\n", SPIFFS_OBJ_HDR_IX_LEN(fs));
SPIFFS_DBG("object index entries: %i\n", SPIFFS_OBJ_IX_LEN(fs));
SPIFFS_DBG("available file descriptors: %i\n", fs->fd_count);
SPIFFS_DBG("free blocks: %i\n", fs->free_blocks);
SPIFFS_UNLOCK(fs);
return 0;
}
void SPIFFS_unmount(spiffs *fs) {
if (!SPIFFS_CHECK_MOUNT(fs)) return;
SPIFFS_LOCK(fs);
int i;
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
for (i = 0; i < fs->fd_count; i++) {
spiffs_fd *cur_fd = &fds[i];
if (cur_fd->file_nbr != 0) {
#if SPIFFS_CACHE
(void)spiffs_fflush_cache(fs, cur_fd->file_nbr);
#endif
spiffs_fd_return(fs, cur_fd->file_nbr);
}
}
fs->block_count = 0;
SPIFFS_UNLOCK(fs);
}
s32_t SPIFFS_errno(spiffs *fs) {
return fs->errno;
}
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_attr attr) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_obj_id obj_id;
s32_t res;
@@ -24,6 +106,7 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_attr attr) {
}
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_attr attr, spiffs_mode mode) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
@@ -80,6 +163,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_attr attr, spiffs_m
}
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
@@ -138,6 +222,7 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs
}
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
@@ -186,7 +271,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
res = spiffs_hydro_write(fs, fd,
get_cache_page(fs, get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size);
spiffs_cache_fh_release(fs, fd->cache_page);
spiffs_cache_fd_release(fs, fd->cache_page);
} else {
// writing within cache
alloc_cpage = 0;
@@ -230,7 +315,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
res = spiffs_hydro_write(fs, fd,
get_cache_page(fs, get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size);
spiffs_cache_fh_release(fs, fd->cache_page);
spiffs_cache_fd_release(fs, fd->cache_page);
res = spiffs_hydro_write(fs, fd, buf, offset, len);
SPIFFS_API_CHECK_RES(fs, res);
}
@@ -248,6 +333,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
}
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
@@ -291,6 +377,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
}
s32_t SPIFFS_remove(spiffs *fs, const char *path) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd fd;
@@ -310,6 +397,7 @@ s32_t SPIFFS_remove(spiffs *fs, const char *path) {
}
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
@@ -318,7 +406,7 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
#if SPIFFS_CACHE_WR
spiffs_cache_fh_release(fs, fd->cache_page);
spiffs_cache_fd_release(fs, fd->cache_page);
#endif
res = spiffs_object_truncate(fd, 0, 1);
@@ -331,6 +419,7 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
@@ -379,7 +468,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
res = spiffs_hydro_write(fs, fd,
get_cache_page(fs, get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size);
spiffs_cache_fh_release(fs, fd->cache_page);
spiffs_cache_fd_release(fs, fd->cache_page);
}
}
#endif
@@ -388,6 +477,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_MOUNT(fs);
s32_t res = SPIFFS_OK;
#if SPIFFS_CACHE_WR
SPIFFS_LOCK(fs);
@@ -400,6 +490,10 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
}
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->errno = SPIFFS_ERR_NOT_MOUNTED;
return;
}
SPIFFS_LOCK(fs);
#if SPIFFS_CACHE
@@ -411,6 +505,10 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh) {
}
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->errno = SPIFFS_ERR_NOT_MOUNTED;
return 0;
}
d->fs = fs;
d->block = 0;
d->entry = 0;
@@ -428,7 +526,7 @@ static s32_t spiffs_read_dir_v(
spiffs_page_object_ix_header objix_hdr;
if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_ERASED ||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
@@ -446,10 +544,14 @@ static s32_t spiffs_read_dir_v(
return SPIFFS_OK;
}
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
if (!SPIFFS_CHECK_MOUNT(d->fs)) {
d->fs->errno = SPIFFS_ERR_NOT_MOUNTED;
return 0;
}
SPIFFS_LOCK(fs);
spiffs_block_ix bix;
@@ -479,11 +581,13 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
}
s32_t SPIFFS_closedir(spiffs_DIR *d) {
return SPIFFS_OK;
SPIFFS_API_CHECK_MOUNT(d->fs);
return 0;
}
s32_t SPIFFS_check(spiffs *fs) {
s32_t res;
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
res = spiffs_area_check(fs, 0);
+30 -588
View File
@@ -47,68 +47,6 @@ static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix p
return res;
}
s32_t SPIFFS_init(spiffs *fs, spiffs_config *config, u8_t *work,
u8_t *fd_space, u32_t fd_space_size,
void *cache, u32_t cache_size) {
SPIFFS_LOCK(fs);
memset(fs, 0, sizeof(spiffs));
memcpy(&fs->cfg, config, sizeof(spiffs_config));
fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
fs->work = &work[0];
fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
memset(fd_space, 0, fd_space_size);
// align fd_space pointer to pointer size byte boundary, below is safe
u8_t ptr_size = sizeof(void*);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
u8_t addr_lsb = ((u8_t)fd_space) & (ptr_size-1);
#pragma GCC diagnostic pop
if (addr_lsb) {
fd_space += (ptr_size-addr_lsb);
fd_space_size -= (ptr_size-addr_lsb);
}
fs->fd_space = fd_space;
fs->fd_count = (fd_space_size/sizeof(spiffs_fd));
// align cache pointer to 4 byte boundary, below is safe
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
addr_lsb = ((u8_t)cache) & (ptr_size-1);
#pragma GCC diagnostic pop
if (addr_lsb) {
cache += (ptr_size-addr_lsb);
cache_size -= (ptr_size-addr_lsb);
}
if (cache_size & (ptr_size-1)) {
cache_size -= (cache_size & (ptr_size-1));
}
#if SPIFFS_CACHE
fs->cache = cache;
fs->cache_size = cache_size;
spiffs_cache_init(fs);
#endif
s32_t res = spiffs_obj_lu_scan(fs);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs));
SPIFFS_DBG("object lookup pages: %i\n", SPIFFS_OBJ_LOOKUP_PAGES(fs));
SPIFFS_DBG("page pages per block: %i\n", SPIFFS_PAGES_PER_BLOCK(fs));
SPIFFS_DBG("page header length: %i\n", sizeof(spiffs_page_header));
SPIFFS_DBG("object header index entries: %i\n", SPIFFS_OBJ_HDR_IX_LEN(fs));
SPIFFS_DBG("object index entries: %i\n", SPIFFS_OBJ_IX_LEN(fs));
SPIFFS_DBG("available file descriptors: %i\n", fs->fd_count);
SPIFFS_DBG("free blocks: %i\n", fs->free_blocks);
SPIFFS_UNLOCK(fs);
return 0;
}
s32_t SPIFFS_errno(spiffs *fs) {
return fs->errno;
}
#if !SPIFFS_CACHE
s32_t spiffs_phys_rd(
@@ -129,7 +67,7 @@ s32_t spiffs_phys_wr(
#endif
s32_t spiffs_phys_cpy(
static s32_t spiffs_phys_cpy(
spiffs *fs,
spiffs_file fh,
u32_t dst,
@@ -207,7 +145,7 @@ s32_t spiffs_obj_lu_find_entry_visitor(
if (index_entry) *index_entry = cur_entry;
if (v) {
res = v(fs, obj_lu_buf[cur_entry-entry_offset], cur_block, cur_entry, user_data, user_p);
if (res == SPIFFS_COUNTINUE) {
if (res == SPIFFS_VIS_COUNTINUE) {
res = SPIFFS_OK;
cur_entry++;
entry_count--;
@@ -215,8 +153,9 @@ s32_t spiffs_obj_lu_find_entry_visitor(
} else {
return res;
}
} else {
return SPIFFS_OK;
}
return SPIFFS_OK;
}
entry_count--;
cur_entry++;
@@ -228,7 +167,7 @@ s32_t spiffs_obj_lu_find_entry_visitor(
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
if (cur_block >= fs->block_count) {
if (flags & SPIFFS_VIS_NO_WRAP) {
return SPIFFS_ERR_NOT_FOUND;
return SPIFFS_VIS_END;
} else {
// block wrap
cur_block = 0;
@@ -239,7 +178,7 @@ s32_t spiffs_obj_lu_find_entry_visitor(
SPIFFS_CHECK_RES(res);
return SPIFFS_ERR_NOT_FOUND;
return SPIFFS_VIS_END;
}
@@ -261,7 +200,7 @@ static s32_t spiffs_obj_lu_scan_v(
fs->stats_p_allocated++;
}
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
// Scans thru all obj lu and counts free, deleted and used pages
@@ -286,6 +225,10 @@ s32_t spiffs_obj_lu_scan(
&bix,
&entry);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
SPIFFS_CHECK_RES(res);
return res;
@@ -309,10 +252,10 @@ s32_t spiffs_obj_lu_find_free(
fs->free_blocks--;
}
}
if (res == SPIFFS_ERR_NOT_FOUND) {
if (res == SPIFFS_VIS_END) {
SPIFFS_DBG("fs full\n");
}
return res == SPIFFS_ERR_NOT_FOUND ? SPIFFS_ERR_FULL : res;
return res == SPIFFS_VIS_END ? SPIFFS_ERR_FULL : res;
}
// Find object lookup entry containing given id
@@ -326,6 +269,9 @@ s32_t spiffs_obj_lu_find_id(
int *index_entry) {
s32_t res = spiffs_obj_lu_find_entry_visitor(
fs, starting_block, starting_index_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, index_entry);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_ERR_NOT_FOUND;
}
return res;
}
@@ -346,7 +292,7 @@ static s32_t spiffs_obj_lu_find_id_and_index_v(
if (ph.span_ix == (spiffs_span_ix)user_data && ((ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) == SPIFFS_PH_FLAG_DELET)) {
return SPIFFS_OK;
} else {
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
}
@@ -372,6 +318,10 @@ s32_t spiffs_obj_lu_find_id_and_index(
&bix,
&entry);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_ERR_NOT_FOUND;
}
SPIFFS_CHECK_RES(res);
if (pix) {
@@ -1154,7 +1104,7 @@ static s32_t spiffs_object_find_object_index_header_by_name_v(
spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_ERASED ||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
@@ -1167,7 +1117,7 @@ static s32_t spiffs_object_find_object_index_header_by_name_v(
}
}
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
// Finds object index header page by name
@@ -1190,6 +1140,9 @@ s32_t spiffs_object_find_object_index_header_by_name(
&bix,
&entry);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_ERR_NOT_FOUND;
}
SPIFFS_CHECK_RES(res);
if (pix) {
@@ -1471,423 +1424,6 @@ s32_t spiffs_object_read(
return res;
}
s32_t spiffs_gc_check(
spiffs *fs,
u32_t len) {
s32_t res;
u32_t free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count
- fs->stats_p_allocated - fs->stats_p_deleted;
int tries = 0;
if (fs->free_blocks > 2 &&
len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) {
return SPIFFS_OK;
}
do {
SPIFFS_GC_DBG("\ngc_check #i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
tries,
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
spiffs_block_ix *cands;
int count;
spiffs_block_ix cand;
res = spiffs_gc_find_candidate(fs, &cands, &count);
SPIFFS_CHECK_RES(res);
if (count == 0) {
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
return res;
}
#if SPIFFS_GC_STATS
fs->stats_gc_runs++;
#endif
cand = cands[0];
res = spiffs_gc_clean(fs, cand);
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
SPIFFS_CHECK_RES(res);
res = spiffs_gc_erase_page_stats(fs, cand);
SPIFFS_CHECK_RES(res);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, cand);
s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);
// here we ignore res, just try erasing the block
SPIFFS_GC_DBG("gc_check: erase block %i\n", cand);
while (size > 0) {
SPIFFS_DBG("gc_check: erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
res = fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
}
fs->free_blocks++;
free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count
- fs->stats_p_allocated - fs->stats_p_deleted;
#if SPIFFS_CACHE
{
int i;
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, cand) + i);
}
}
#endif
} while (tries++ < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
SPIFFS_GC_DBG("gc_check: finished\n");
return res;
}
s32_t spiffs_gc_erase_page_stats(
spiffs *fs,
spiffs_block_ix bix) {
s32_t res = SPIFFS_OK;
int obj_lookup_page = 0;
u32_t 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;
int cur_entry = 0;
u32_t dele = 0;
u32_t allo = 0;
// check each object lookup page
while (res == SPIFFS_OK && obj_lookup_page < 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, SPIFFS_BLOCK_TO_PADDR(fs, bix) + 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 < 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) {
} else if (obj_id == SPIFFS_OBJ_ID_ERASED) {
dele++;
} else {
allo++;
}
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele);
fs->stats_p_allocated -= allo;
fs->stats_p_deleted -= dele;
return res;
}
s32_t spiffs_gc_find_candidate(
spiffs *fs,
spiffs_block_ix **block_candidates,
int *candidate_count) {
s32_t res = SPIFFS_OK;
u32_t blocks = fs->block_count;
spiffs_block_ix cur_block = 0;
u32_t cur_block_addr = SPIFFS_CFG_PHYS_ADDR(fs);
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/(int)score
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(int)));
*candidate_count = 0;
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;
int *cand_scores = (int *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
*block_candidates = cand_blocks;
u32_t 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 < 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 < 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
break;
} else if (obj_id == SPIFFS_OBJ_ID_ERASED) {
deleted_pages_in_block++;
} else {
used_pages_in_block++;
}
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
// calculate score and insert into candidate table
// stoneage sort, but probably not so many blocks
if (res == SPIFFS_OK && deleted_pages_in_block > 0) {
int score = deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + used_pages_in_block * SPIFFS_GC_HEUR_W_USED;
int cand_ix = 0;
SPIFFS_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;
}
typedef enum {
MOVE_OBJ_IX,
FIND_OBJ_DATA,
MOVE_OBJ_DATA,
FINISHED
} spiffs_gc_clean_state;
typedef struct {
spiffs_gc_clean_state state;
spiffs_obj_id cur_obj_id;
spiffs_span_ix cur_objix_spix;
spiffs_page_ix cur_objix_pix;
int stored_scan_entry_index;
u8_t obj_id_found;
} spiffs_gc;
// Empties given block by moving all data into free pages of another block
// Strategy:
// scan object lookup for object index pages, move to new page in other block
// loop:
// scan object lookup for object data pages
// for first found id, check spix and load corresponding object index page to memory
// push object scan lookup entry index
// rescan object lookup, find data pages with same id and referenced by same object index
// move data page, update object index in memory
// when reached end of lookup, store updated object index
// pop object scan lookup entry index
// repeat loop until end of object lookup
//
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
s32_t res = SPIFFS_OK;
u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
int cur_entry = 0;
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
spiffs_gc gc;
spiffs_page_ix cur_pix = 0;
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
memset(&gc, 0, sizeof(spiffs_gc));
gc.state = MOVE_OBJ_IX;
if (fs->free_cursor_block_ix == bix) {
// move free cursor to next block
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
fs->free_cursor_obj_lu_entry = 0;
SPIFFS_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix);
}
while (res == SPIFFS_OK && gc.state != FINISHED) {
SPIFFS_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry);
gc.obj_id_found = 0;
// scan through lookup pages
int obj_lookup_page = cur_entry / entries_per_page;
u8_t scan = 1;
// check each object lookup page
while (scan && res == SPIFFS_OK && obj_lookup_page < 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, SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
// check each entry
while (scan && res == SPIFFS_OK &&
cur_entry - entry_offset < entries_per_page && cur_entry < SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
// act upon object id depending on gc state
switch (gc.state) {
case MOVE_OBJ_IX:
if (obj_id != SPIFFS_OBJ_ID_ERASED && obj_id != SPIFFS_OBJ_ID_FREE && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
// found an index object id
spiffs_page_header p_hdr;
spiffs_page_ix new_pix;
// load header
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
// move page
res = spiffs_page_move(fs, 0, 0, &p_hdr, cur_pix, &new_pix);
SPIFFS_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, obj_id, p_hdr.span_ix, new_pix, 0);
// move wipes obj_lu, reload it
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res);
} else {
// page is deleted but not deleted in lookup, scrap it
SPIFFS_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
res = spiffs_page_delete(fs, cur_pix);
if (res == SPIFFS_OK) {
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
}
}
SPIFFS_CHECK_RES(res);
}
break;
case FIND_OBJ_DATA:
if (obj_id != SPIFFS_OBJ_ID_ERASED && obj_id != SPIFFS_OBJ_ID_FREE) {
SPIFFS_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id);
gc.obj_id_found = 1;
gc.cur_obj_id = obj_id;
scan = 0;
}
break;
case MOVE_OBJ_DATA:
if (obj_id == gc.cur_obj_id) {
spiffs_page_header p_hdr;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
SPIFFS_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
} else {
spiffs_page_ix new_data_pix;
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
// move page
res = spiffs_page_move(fs, 0, 0, &p_hdr, cur_pix, &new_data_pix);
SPIFFS_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);
SPIFFS_CHECK_RES(res);
// move wipes obj_lu, reload it
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
SPIFFS_CHECK_RES(res);
} else {
// page is deleted but not deleted in lookup, scrap it
SPIFFS_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
new_data_pix = SPIFFS_OBJ_ID_FREE;
}
// update memory representation of object index page with new data page
if (gc.cur_objix_spix == 0) {
// update object index header page
((spiffs_page_ix*)((void*)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
SPIFFS_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));
} else {
// update object index page
((spiffs_page_ix*)((void*)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
SPIFFS_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));
}
}
}
break;
default:
scan = 0;
break;
}
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
if (res != SPIFFS_OK) break;
// state finalization and switch
switch (gc.state) {
case MOVE_OBJ_IX:
gc.state = FIND_OBJ_DATA;
cur_entry = 0; // restart entry scan index
break;
case FIND_OBJ_DATA:
if (gc.obj_id_found) {
// find out corresponding obj ix page and load it to memory
spiffs_page_header p_hdr;
spiffs_page_ix objix_pix;
gc.stored_scan_entry_index = cur_entry;
cur_entry = 0;
gc.state = MOVE_OBJ_DATA;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
SPIFFS_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix);
res = spiffs_obj_lu_find_id_and_index(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, &objix_pix);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix);
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
SPIFFS_CHECK_RES(res);
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id, gc.cur_objix_spix);
gc.cur_objix_pix = objix_pix;
} else {
gc.state = FINISHED;
}
break;
case MOVE_OBJ_DATA: {
// store modified objix (hdr) page
spiffs_page_ix new_objix_pix;
gc.state = FIND_OBJ_DATA;
cur_entry = gc.stored_scan_entry_index;
if (gc.cur_objix_spix == 0) {
// store object index header page
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix);
SPIFFS_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0);
SPIFFS_CHECK_RES(res);
} else {
// store object index page
spiffs_page_ix new_objix_pix;
res = spiffs_page_move(fs, 0, fs->work, 0, gc.cur_objix_pix, &new_objix_pix);
SPIFFS_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix);
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
}
}
break;
default:
cur_entry = 0;
break;
}
SPIFFS_DBG("gc_clean: state-> %i\n", gc.state);
} // while state != FINISHED
return res;
}
typedef struct {
spiffs_obj_id min_obj_id;
spiffs_obj_id max_obj_id;
@@ -1905,7 +1441,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id i
fs->work[byte_ix] |= (1<<bit_ix);
}
}
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
@@ -1929,7 +1465,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id
}
}
}
return SPIFFS_COUNTINUE;
return SPIFFS_VIS_COUNTINUE;
}
// Scans thru all object lookup for object index header pages. If total possible number of
@@ -1955,7 +1491,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id) {
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id, 0, 0, 0);
if (res == SPIFFS_ERR_NOT_FOUND) res = SPIFFS_OK;
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
SPIFFS_CHECK_RES(res);
// traverse bitmask until found free obj_id
for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) {
@@ -2019,7 +1555,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id) {
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0);
if (res == SPIFFS_ERR_NOT_FOUND) res = SPIFFS_OK;
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
SPIFFS_CHECK_RES(res);
}
}
@@ -2065,97 +1601,3 @@ s32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {
}
return SPIFFS_OK;
}
// Scans all object look up. For each entry, corresponding page header is checked for validity.
// If an object index header page is found, this is checked
s32_t spiffs_area_check(spiffs *fs, u8_t check_all_objects) {
s32_t res = SPIFFS_OK;
s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs);
spiffs_block_ix cur_block = 0;
u32_t cur_block_addr = SPIFFS_BLOCK_TO_PADDR(fs, 0);
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
int cur_entry = 0;
spiffs_page_ix cur_pix;
u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
// check each block
while (res == SPIFFS_OK && entry_count > 0) {
int obj_lookup_page = cur_entry / entries_per_page;
// check each object lookup page
while (res == SPIFFS_OK && obj_lookup_page < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
int entry_offset = obj_lookup_page * entries_per_page;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | 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 && // for non-last obj lookup pages
cur_entry < SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) // for last obj lookup page
{
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
spiffs_page_header p_hdr;
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
// load header
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
SPIFFS_CHECK_RES(res);
if (obj_id == SPIFFS_OBJ_ID_ERASED) {
// TODO
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
print("WARNING: pix %04x deleted in lu but not on page\n", cur_pix);
}
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
// TODO
if (p_hdr.flags != 0xff) {
print("WARNING: pix %04x free in lu but not on page\n", cur_pix);
}
} else {
// TODO
if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) == 0) {
print("WARNING: pix %04x busy in lu but free on page\n", cur_pix);
}
if ((p_hdr.flags & SPIFFS_PH_FLAG_FINAL)) {
print("WARNING: pix %04x busy but not final\n", cur_pix);
}
if (p_hdr.obj_id != obj_id) {
print("WARNING: pix %04x has id %04x in lu but %04x on page\n", cur_pix, obj_id, p_hdr.obj_id);
}
if (obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
// index page
if (p_hdr.flags & SPIFFS_PH_FLAG_INDEX) {
print("WARNING: pix %04x marked as index in lu but as data on page\n", cur_pix);
}
} else {
// data page
if ((p_hdr.flags & SPIFFS_PH_FLAG_INDEX) == 0) {
print("WARNING: pix %04x as data in lu but as index on page\n", cur_pix);
}
}
}
entry_count--;
cur_entry++;
} // per entry
obj_lookup_page++;
} // per object lookup page
cur_entry = 0;
cur_block++;
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
} // per block
SPIFFS_CHECK_RES(res);
return SPIFFS_OK;
}
// Scans all object look up for consistency within given object id. When an index is found, it is loaded
// and checked for validity against each referenced page. When an object index header is found, size is
// checked.
// When an index points to a bad page (deleted, other id, bad span index, etc), the whole area is searched
// for correct page, followed by an index update. If no such page is found, a free page is allocated and
// referenced instead meaning there will be a "hole" with 0xff in the file.
s32_t spiffs_object_check(spiffs *fs, spiffs_obj_id objid) {
}
+47 -7
View File
@@ -110,6 +110,9 @@
#ifndef SPIFFS_NUCLEUS_H_
#define SPIFFS_NUCLEUS_H_
#define SPIFFS_VIS_COUNTINUE -11000
#define SPIFFS_VIS_END -11001
#define SPIFFS_EV_IX_UPD 0
#define SPIFFS_EV_IX_NEW 1
#define SPIFFS_EV_IX_DEL 2
@@ -217,12 +220,20 @@
// if 0, this is an index page, else a data page
#define SPIFFS_PH_FLAG_INDEX (1<<3)
#define SPIFFS_CHECK_MOUNT(fs) \
((fs)->block_count > 0)
#define SPIFFS_CHECK_RES(res) \
do { \
if ((res) < SPIFFS_OK) return (res); \
} while (0);
#define SPIFFS_API_CHECK_MOUNT(fs) \
if (!SPIFFS_CHECK_MOUNT((fs))) { \
(fs)->errno = SPIFFS_ERR_NOT_MOUNTED; \
return -1; \
}
#define SPIFFS_API_CHECK_RES(fs, res) \
if ((res) < SPIFFS_OK) { \
(fs)->errno = (res); \
@@ -236,6 +247,22 @@
return -1; \
}
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;\
if (((ph).obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != ((objid) & ~SPIFFS_OBJ_ID_IX_FLAG)) return SPIFFS_ERR_INDEX_WRONG_ID;
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH; \
if (((ph).obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != ((objid) & ~SPIFFS_OBJ_ID_IX_FLAG)) return SPIFFS_ERR_DATA_WRONG_ID;
#define SPIFFS_VIS_CHECK_ID (1<<0)
#define SPIFFS_VIS_NO_WRAP (1<<1)
@@ -390,14 +417,14 @@ s32_t spiffs_phys_wr(
u32_t addr,
u32_t len,
u8_t *src);
#if 0
s32_t spiffs_phys_cpy(
spiffs *fs,
spiffs_file fh,
u32_t dst,
u32_t src,
u32_t len);
#endif
s32_t spiffs_phys_count_free_blocks(
spiffs *fs);
@@ -570,12 +597,25 @@ s32_t spiffs_fd_get(
spiffs_fd **fd);
#if SPIFFS_CACHE
void spiffs_cache_init(spiffs *fs);
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix);
void spiffs_cache_init(
spiffs *fs);
void spiffs_cache_drop_page(
spiffs *fs,
spiffs_page_ix pix);
#if SPIFFS_CACHE_WR
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd);
void spiffs_cache_fh_release(spiffs *fs, spiffs_cache_page *cp);
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd);
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
spiffs *fs,
spiffs_fd *fd);
void spiffs_cache_fd_release(
spiffs *fs,
spiffs_cache_page *cp);
spiffs_cache_page *spiffs_cache_page_get_by_fd(
spiffs *fs,
spiffs_fd *fd);
#endif
#endif
+31 -165
View File
@@ -1370,175 +1370,41 @@ void setup() {
void teardown() {
_teardown();
}
#if 0
TEST(write_small_file_chunks_1)
{
int res = test_create_and_write_file("smallfile", 600, 1);
TEST(check1) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("smallfile");
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", 0, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify lu entry data page index 1
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_index(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, &pix);
TEST_CHECK(res >= 0);
// reset lu entry to being erased, but keep page data
spiffs_obj_id obj_id = SPIFFS_OBJ_ID_ERASED;
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry*sizeof(spiffs_obj_id);
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
spiffs_cache *cache = get_cache(FS);
cache->cpage_use_map = 0;
SPIFFS_check(FS);
return TEST_RES_OK;
}
TEST_END(write_small_file_chunks_1)
} TEST_END(check1)
TEST(write_big_file_chunks_page)
{
int size = ((50*(FS)->cfg.phys_size)/100);
printf(" filesize %i\n", size);
int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS));
TEST_CHECK(res >= 0);
res = read_and_verify("bigfile");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
}
TEST_END(write_big_file_chunks_page)
#else
TEST(long_run_config_many_small)
{
tfile_conf cfgs[] = {
{ .tsize = SMALL, .ttype = APPENDED, .tlife = LONG
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = LONG
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM
},
{ .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT
},
};
int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 115, 6, 1);
TEST_CHECK(res >= 0);
return TEST_RES_OK;
}
TEST_END(long_run_config_many_small)
#endif
SUITE_END(dev_tests)
+8 -1
View File
@@ -244,6 +244,13 @@ int read_and_verify(char *name) {
return 0;
}
void area_write(u32_t addr, u8_t *buf, u32_t size) {
int i;
for (i = 0; i < size; i++) {
area[addr + i] = *buf++;
}
}
void fs_reset() {
memset(area, 0xff, sizeof(area));
spiffs_config c;
@@ -257,7 +264,7 @@ void fs_reset() {
c.phys_size = sizeof(area);
memset(erases,0,sizeof(erases));
memset(_cache,0,sizeof(_cache));
SPIFFS_init(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache));
SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache));
}
void real_assert(int c, const char *n, const char *file, int l) {
+2
View File
@@ -20,6 +20,8 @@ void dump_page(spiffs *fs, spiffs_page_ix p);
void hexdump(u32_t addr, u32_t len);
char *make_test_fname(const char *name);
void clear_test_path();
u8_t area_read(u32_t addr);
void area_write(u32_t addr, u8_t *buf, u32_t size);
#endif /* TEST_SPIFFS_H_ */
+2 -2
View File
@@ -8,6 +8,6 @@
#include "testrunner.h"
void add_suites() {
ADD_SUITE(hydrogen_tests)
//ADD_SUITE(dev_tests);
//ADD_SUITE(hydrogen_tests)
ADD_SUITE(dev_tests);
}