Fixed issue with long names causing unbounded recursion

This was caused by any commit containing entries large enough to
_always_ force a compaction. This would cause littlefs to think that it
would need to split infinitely because there was no base case.

The fix here is pretty simple: treat any commit with only a single entry
as unsplittable. This forces littlefs to first try overcompacting
(fitting more in a block than what has optimal runtime), and then
failing that return LFS_ERR_NOSPC for higher layers to handle.

found by TheLoneWolfling
This commit is contained in:
Christopher Haster
2019-01-31 14:54:47 -06:00
parent 95c1a6339d
commit 10dfc36f08
2 changed files with 27 additions and 2 deletions

5
lfs.c
View File

@@ -1414,7 +1414,8 @@ static int lfs_dir_compact(lfs_t *lfs,
bool relocated = false; bool relocated = false;
bool exhausted = false; bool exhausted = false;
while (true) { // should we split?
while (end - begin > 1) {
// find size // find size
lfs_size_t size = 0; lfs_size_t size = 0;
int err = lfs_dir_traverse(lfs, int err = lfs_dir_traverse(lfs,
@@ -1429,7 +1430,7 @@ static int lfs_dir_compact(lfs_t *lfs,
// space is complicated, we need room for tail, crc, gstate, // space is complicated, we need room for tail, crc, gstate,
// cleanup delete, and we cap at half a block to give room // cleanup delete, and we cap at half a block to give room
// for metadata updates // for metadata updates.
if (size <= lfs_min(lfs->cfg->block_size - 36, if (size <= lfs_min(lfs->cfg->block_size - 36,
lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size))) { lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size))) {
break; break;

View File

@@ -165,5 +165,29 @@ tests/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Really big path test ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 'w', LFS_NAME_MAX);
buffer[LFS_NAME_MAX+1] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => 0;
lfs_remove(&lfs, (char*)buffer) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, (char*)buffer) => 0;
memcpy(buffer, "coffee/", strlen("coffee/"));
memset(buffer+strlen("coffee/"), 'w', LFS_NAME_MAX);
buffer[strlen("coffee/")+LFS_NAME_MAX+1] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => 0;
lfs_remove(&lfs, (char*)buffer) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, (char*)buffer) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---" echo "--- Results ---"
tests/stats.py tests/stats.py