diff --git a/src/default/spiffs_config.h b/src/default/spiffs_config.h index 5a6574a..33a712e 100644 --- a/src/default/spiffs_config.h +++ b/src/default/spiffs_config.h @@ -30,7 +30,7 @@ #endif // Set spiffs debug output call for caching. #ifndef SPIFFS_CACHE_DGB -#define SPIFFS_CACHE_DBG(...) //printf("CA: " __VA_ARGS__) +#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__) #endif // Set spiffs debug output call for system consistency checks. #ifndef SPIFFS_CHECK_DGB diff --git a/src/spiffs_gc.c b/src/spiffs_gc.c index e122624..b4d8d19 100644 --- a/src/spiffs_gc.c +++ b/src/spiffs_gc.c @@ -129,6 +129,11 @@ s32_t spiffs_gc_check( return SPIFFS_OK; } + u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs); + if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) { + return SPIFFS_ERR_FULL; + } + //printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len); do { diff --git a/src/spiffs_hydrogen.c b/src/spiffs_hydrogen.c index 34178e5..9eee1f4 100644 --- a/src/spiffs_hydrogen.c +++ b/src/spiffs_hydrogen.c @@ -330,7 +330,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page { // boundary violation, write back cache first and allocate new - SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:&04x, boundary viol, offs:%i size:%i\n", + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, boundary viol, offs:%i size:%i\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); res = spiffs_hydro_write(fs, fd, spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), @@ -382,6 +382,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES(fs, res); res = spiffs_hydro_write(fs, fd, buf, offset, len); SPIFFS_API_CHECK_RES(fs, res); } diff --git a/src/spiffs_nucleus.c b/src/spiffs_nucleus.c index 2476046..c93337b 100644 --- a/src/spiffs_nucleus.c +++ b/src/spiffs_nucleus.c @@ -614,7 +614,7 @@ s32_t spiffs_object_create( spiffs_page_object_ix_header oix_hdr; int entry; - res = spiffs_gc_check(fs, 0); + res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs)); SPIFFS_CHECK_RES(res); obj_id |= SPIFFS_OBJ_ID_IX_FLAG; @@ -811,7 +811,17 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { s32_t res = SPIFFS_OK; u32_t written = 0; + SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size); + + if (offset > fd->size) { + SPIFFS_DBG("append: offset reversed to size\n"); + offset = fd->size; + } + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta + if (res != SPIFFS_OK) { + SPIFFS_DBG("append: gc check fail %i\n", res); + } SPIFFS_CHECK_RES(res); spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; @@ -1042,7 +1052,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { s32_t res = SPIFFS_OK; u32_t written = 0; - res = spiffs_gc_check(fs, len); + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); SPIFFS_CHECK_RES(res); spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; @@ -1308,7 +1318,7 @@ s32_t spiffs_object_truncate( s32_t res = SPIFFS_OK; spiffs *fs = fd->fs; - res = spiffs_gc_check(fs, 0); + res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs)); SPIFFS_CHECK_RES(res); spiffs_page_ix objix_pix = fd->objix_hdr_pix; @@ -1391,12 +1401,18 @@ s32_t spiffs_object_truncate( if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) { // delete full data page res = spiffs_page_data_check(fs, fd, data_pix, data_spix); - if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK) break; + if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) { + SPIFFS_DBG("truncate: err validating data pix %i\n", res); + break; + } if (res == SPIFFS_OK) { res = spiffs_page_delete(fs, data_pix); - if (res != SPIFFS_OK) break; - } else if (res == SPIFFS_ERR_DELETED) { + if (res != SPIFFS_OK) { + SPIFFS_DBG("truncate: err deleting data pix %i\n", res); + break; + } + } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) { res = SPIFFS_OK; } diff --git a/src/test/test_bugreports.c b/src/test/test_bugreports.c index 44f03b8..b577e6f 100644 --- a/src/test/test_bugreports.c +++ b/src/test/test_bugreports.c @@ -26,8 +26,8 @@ void teardown() { _teardown(); } -TEST(nodemcu_full_fs) { - fs_reset_specific(0, 65536, 4096, 4096, 256); +TEST(nodemcu_full_fs_1) { + fs_reset_specific(0, 4096*20, 4096, 4096, 256); int res; spiffs_file fd; @@ -38,7 +38,7 @@ TEST(nodemcu_full_fs) { int i; spiffs_stat s; res = SPIFFS_OK; - for (i = 0; res >= 0 && SPIFFS_errno(FS) == SPIFFS_OK && i < 100*1000; i++) { + for (i = 0; i < 100*1000; i++) { u8_t buf = 'x'; res = SPIFFS_write(FS, fd, &buf, 1); } @@ -51,10 +51,11 @@ TEST(nodemcu_full_fs) { TEST_CHECK(errno == SPIFFS_ERR_FULL); SPIFFS_close(FS, fd); - printf(" remove big file\n"); res = SPIFFS_remove(FS, "test1.txt"); + printf("res:%i errno:%i\n",res, SPIFFS_errno(FS)); + TEST_CHECK(res == SPIFFS_OK); res2 = SPIFFS_fstat(FS, fd, &s); TEST_CHECK(res2 == -1); @@ -82,6 +83,78 @@ TEST(nodemcu_full_fs) { return TEST_RES_OK; -} TEST_END(nodemcu_full_fs) +} TEST_END(nodemcu_full_fs_1) + +TEST(nodemcu_full_fs_2) { + fs_reset_specific(0, 4096*22, 4096, 4096, 256); + + int res; + spiffs_file fd; + + printf(" fill up system by writing one byte a lot\n"); + fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + int i; + spiffs_stat s; + res = SPIFFS_OK; + for (i = 0; i < 100*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + int errno = SPIFFS_errno(FS); + int res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(errno == SPIFFS_ERR_FULL); + SPIFFS_close(FS, fd); + + res2 = SPIFFS_stat(FS, "test1.txt", &s); + TEST_CHECK(res2 == SPIFFS_OK); + + SPIFFS_clearerr(FS); + printf(" create small file\n"); + fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + TEST_CHECK(fd > 0); + + for (i = 0; i < 1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL); + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + TEST_CHECK(s.size == 0); + SPIFFS_clearerr(FS); + + printf(" remove files\n"); + res = SPIFFS_remove(FS, "test1.txt"); + TEST_CHECK(res == SPIFFS_OK); + res = SPIFFS_remove(FS, "test2.txt"); + TEST_CHECK(res == SPIFFS_OK); + + printf(" create medium file\n"); + fd = SPIFFS_open(FS, "test3.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + TEST_CHECK(fd > 0); + + for (i = 0; i < 20*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + TEST_CHECK(s.size == 20*1000); + + return TEST_RES_OK; + +} TEST_END(nodemcu_full_fs_2) SUITE_END(bug_tests)