From 05354fa428bfd9a2268bde45ab0efab73b5a8db4 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Mon, 15 Feb 2016 23:00:54 +0100 Subject: [PATCH] Fixed a stat bug with obj id. Added user callback file func. New API functions: SPIFFS_set_file_callback_func --- src/spiffs.h | 35 ++++++++++- src/spiffs_hydrogen.c | 12 +++- src/spiffs_nucleus.c | 20 ++++++- src/test/test_hydrogen.c | 125 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+), 5 deletions(-) diff --git a/src/spiffs.h b/src/spiffs.h index 496c8f6..c43d831 100644 --- a/src/spiffs.h +++ b/src/spiffs.h @@ -68,9 +68,10 @@ typedef u16_t spiffs_mode; // object type typedef u8_t spiffs_obj_type; -#if SPIFFS_HAL_CALLBACK_EXTRA struct spiffs_t; +#if SPIFFS_HAL_CALLBACK_EXTRA + /* spi read call function type */ typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst); /* spi write call function type */ @@ -115,6 +116,19 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor u32_t arg1, u32_t arg2); #endif // SPIFFS_HAL_CALLBACK_EXTRA +/* file system listener callback operation */ +typedef enum { + /* the file has been created */ + SPIFFS_CB_CREATED = 0, + /* the file has been updated or moved to another page */ + SPIFFS_CB_UPDATED, + /* the file has been deleted */ + SPIFFS_CB_DELETED, +} spiffs_fileop_type; + +/* file system listener callback function */ +typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix); + #ifndef SPIFFS_DBG #define SPIFFS_DBG(...) \ print(__VA_ARGS__) @@ -252,7 +266,8 @@ typedef struct spiffs_t { // check callback function spiffs_check_callback check_cb_f; - + // file callback function + spiffs_file_callback file_cb_f; // mounted flag u8_t mounted; // user data @@ -266,6 +281,7 @@ typedef struct { spiffs_obj_id obj_id; u32_t size; spiffs_obj_type type; + spiffs_page_ix pix; u8_t name[SPIFFS_OBJ_NAME_LEN]; } spiffs_stat; @@ -616,6 +632,21 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh); */ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh); +/** + * Registers a callback function that keeps track on operations on file + * headers. Do note, that this callback is called from within internal spiffs + * mechanisms. Any operations on the actual file system being callbacked from + * in this callback will mess things up for sure - do not do this. + * This can be used to track where files are and move around during garbage + * collection, which in turn can be used to build location tables in ram. + * Used in conjuction with SPIFFS_open_by_page this may improve performance + * when opening a lot of files. + * + * @param fs the file system struct + * @param cb_func the callback on file operations + */ +s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func); + #if SPIFFS_TEST_VISUALISATION /** * Prints out a visualization of the filesystem. diff --git a/src/spiffs_hydrogen.c b/src/spiffs_hydrogen.c index 68bbd0d..99e5deb 100644 --- a/src/spiffs_hydrogen.c +++ b/src/spiffs_hydrogen.c @@ -80,11 +80,14 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, void *cache, u32_t cache_size, spiffs_check_callback check_cb_f) { void *user_data; + spiffs_file_callback fcb; SPIFFS_LOCK(fs); user_data = fs->user_data; + fcb = fs->file_cb_f; memset(fs, 0, sizeof(spiffs)); memcpy(&fs->cfg, config, sizeof(spiffs_config)); fs->user_data = user_data; + fs->file_cb_f = fcb; 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)]; @@ -692,9 +695,10 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id); SPIFFS_API_CHECK_RES(fs, res); - s->obj_id = obj_id; + s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; s->type = objix_hdr.type; s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; + s->pix = pix; strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN); return res; @@ -1081,6 +1085,12 @@ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { return res; } +s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) { + SPIFFS_LOCK(fs); + fs->file_cb_f = cb_func; + SPIFFS_UNLOCK(fs); + return 0; +} #if SPIFFS_TEST_VISUALISATION s32_t SPIFFS_vis(spiffs *fs) { diff --git a/src/spiffs_nucleus.c b/src/spiffs_nucleus.c index e12650c..27bfb7b 100644 --- a/src/spiffs_nucleus.c +++ b/src/spiffs_nucleus.c @@ -871,13 +871,13 @@ void spiffs_cb_object_event( spiffs *fs, spiffs_fd *fd, int ev, - spiffs_obj_id obj_id, + spiffs_obj_id obj_id_raw, spiffs_span_ix spix, spiffs_page_ix new_pix, u32_t new_size) { (void)fd; // update index caches in all file descriptors - obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; + spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG; u32_t i; spiffs_fd *fds = (spiffs_fd *)fs->fd_space; for (i = 0; i < fs->fd_count; i++) { @@ -904,6 +904,22 @@ void spiffs_cb_object_event( } } } + + // callback to user if object index header + if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_fileop_type op; + if (ev == SPIFFS_EV_IX_NEW) { + op = SPIFFS_CB_CREATED; + } else if (ev == SPIFFS_EV_IX_UPD) { + op = SPIFFS_CB_UPDATED; + } else if (ev == SPIFFS_EV_IX_DEL) { + op = SPIFFS_CB_DELETED; + } else { + SPIFFS_DBG(" callback: WARNING unknown callback event %02x\n", ev); + return; // bail out + } + fs->file_cb_f(fs, op, obj_id, new_pix); + } } // Open object by id diff --git a/src/test/test_hydrogen.c b/src/test/test_hydrogen.c index 71e755c..a5e6a4f 100644 --- a/src/test/test_hydrogen.c +++ b/src/test/test_hydrogen.c @@ -546,6 +546,131 @@ TEST(open_by_page) { } TEST_END(open_by_page) +static struct { + u32_t calls; + spiffs_fileop_type op; + spiffs_obj_id obj_id; + spiffs_page_ix pix; +} ucb; + +void test_cb(spiffs *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix) { + ucb.calls++; + ucb.op = op; + ucb.obj_id = obj_id; + ucb.pix = pix; + //printf("%4i op:%i objid:%04x pix:%04x\n", ucb.calls, ucb.op, ucb.obj_id, ucb.pix); +} + +TEST(user_callback_basic) { + SPIFFS_set_file_callback_func(FS, test_cb); + int res; + memset(&ucb, 0, sizeof(ucb)); + spiffs_file fd = SPIFFS_open(FS, "foo", SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK_GE(fd, 0); + TEST_CHECK_EQ(ucb.calls, 1); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_CREATED); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_write(FS, fd, "howdy partner", 14); + TEST_CHECK_GE(res, 0); + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 2); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_UPDATED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_fremove(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 3); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_DELETED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + return TEST_RES_OK; +} TEST_END(user_callback_basic) + + +TEST(user_callback_gc) { + SPIFFS_set_file_callback_func(FS, test_cb); + + char name[32]; + int f; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + int pages_per_block = SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS); + int files = (pages_per_block-1)/2; + int res; + + // fill block with files + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + // remove all files in block + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = SPIFFS_remove(FS, name); + TEST_CHECK(res >= 0); + } + + memset(&ucb, 0, sizeof(ucb)); + spiffs_file fd = SPIFFS_open(FS, "foo", SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK_GE(fd, 0); + TEST_CHECK_EQ(ucb.calls, 1); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_CREATED); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_write(FS, fd, "howdy partner", 14); + TEST_CHECK_GE(res, 0); + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 2); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_UPDATED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + u32_t tot, us; + SPIFFS_info(FS, &tot, &us); + + // do a hard gc, should move our file + res = SPIFFS_gc(FS, tot-us*2); + TEST_CHECK_GE(res, 0); + + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 3); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_UPDATED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_NEQ(ucb.pix, s.pix); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_fremove(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 4); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_DELETED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + return TEST_RES_OK; +} TEST_END(user_callback_gc) + + TEST(rename) { int res;