diff --git a/lfs.c b/lfs.c index 7e772bbb14b..b590c1e3918 100644 --- a/lfs.c +++ b/lfs.c @@ -232,7 +232,13 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { } // scan again or die trying - return lfs_alloc_scan(lfs, block); + err = lfs_alloc_scan(lfs, block); + if (err) { + LFS_WARN("No more free space%s", ""); + return err; + } + + return 0; } @@ -1010,11 +1016,25 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, file->size = 0; } + // add to list of files + file->next = lfs->files; + lfs->files = file; + return 0; } int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { - return lfs_file_sync(lfs, file); + int err = lfs_file_sync(lfs, file); + + // remove from list of files + for (lfs_file_t **p = &lfs->files; *p; p = &(*p)->next) { + if (*p == file) { + *p = file->next; + break; + } + } + + return err; } static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { @@ -1453,6 +1473,9 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { } } + // setup files as an empty list + lfs->files = NULL; + return 0; } @@ -1612,8 +1635,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { dir.off += entry.d.len; if ((0xf & entry.d.type) == LFS_TYPE_REG) { int err = lfs_index_traverse(lfs, - entry.d.u.file.head, entry.d.u.file.size, - cb, data); + entry.d.u.file.head, entry.d.u.file.size, cb, data); if (err) { return err; } @@ -1623,10 +1645,29 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { cwd[0] = dir.d.tail[0]; cwd[1] = dir.d.tail[1]; - if (!cwd[0]) { - return 0; + if (lfs_pairisnull(cwd)) { + break; } } + + // iterate over any open files + for (lfs_file_t *f = lfs->files; f; f = f->next) { + if (f->flags & LFS_O_DIRTY) { + int err = lfs_index_traverse(lfs, f->head, f->size, cb, data); + if (err) { + return err; + } + } + + if (f->wblock) { + int err = lfs_index_traverse(lfs, f->wblock, f->pos, cb, data); + if (err) { + return err; + } + } + } + + return 0; } static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2]) { diff --git a/lfs.h b/lfs.h index 0581844a886..a3b80cb4028 100644 --- a/lfs.h +++ b/lfs.h @@ -145,6 +145,7 @@ typedef struct lfs_entry { } lfs_entry_t; typedef struct lfs_file { + struct lfs_file *next; lfs_block_t pair[2]; lfs_off_t off; lfs_block_t head; @@ -194,6 +195,7 @@ typedef struct lfs { lfs_size_t words; // number of 32-bit words that can fit in a block lfs_block_t root[2]; + lfs_file_t *files; struct { lfs_block_t block; diff --git a/tests/test_alloc.sh b/tests/test_alloc.sh index 48ff72aaf17..e3e4fe0f21b 100755 --- a/tests/test_alloc.sh +++ b/tests/test_alloc.sh @@ -110,5 +110,88 @@ lfs_alloc_singleproc multiprocreuse lfs_verify multiprocreuse lfs_verify singleprocreuse +echo "--- Cleanup ---" +lfs_remove multiprocreuse +lfs_remove singleprocreuse + +echo "--- Exhaustion test ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + size = strlen("exhaustion"); + memcpy(buffer, "exhaustion", size); + lfs_file_write(&lfs, &file[0], buffer, size) => size; + + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + lfs_ssize_t res; + while (true) { + res = lfs_file_write(&lfs, &file[0], buffer, size); + if (res < 0) { + break; + } + + res => size; + } + res => LFS_ERR_NOSPC; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); + size = strlen("exhaustion"); + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "exhaustion", size) => 0; + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Exhaustion wraparound test ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "exhaustion") => 0; + + lfs_file_open(&lfs, &file[0], "padding", LFS_O_WRONLY | LFS_O_CREAT); + size = strlen("buffering"); + memcpy(buffer, "buffering", size); + for (int i = 0; i < $SIZE; i++) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + lfs_remove(&lfs, "padding") => 0; + + lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + size = strlen("exhaustion"); + memcpy(buffer, "exhaustion", size); + lfs_file_write(&lfs, &file[0], buffer, size) => size; + + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + lfs_ssize_t res; + while (true) { + res = lfs_file_write(&lfs, &file[0], buffer, size); + if (res < 0) { + break; + } + + res => size; + } + res => LFS_ERR_NOSPC; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); + size = strlen("exhaustion"); + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "exhaustion", size) => 0; + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + echo "--- Results ---" tests/stats.py