diff --git a/lfs.c b/lfs.c index 4b41e94..b810e51 100644 --- a/lfs.c +++ b/lfs.c @@ -290,6 +290,15 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { // found a free block *block = (lfs->free.begin + off) % lfs->cfg->block_count; + + // eagerly find next off so an alloc ack can + // discredit old lookahead blocks + while (lfs->free.off != lfs->free.size && + (lfs->free.buffer[lfs->free.off / 32] & + (1U << (lfs->free.off % 32)))) { + lfs->free.off += 1; + } + return 0; } } @@ -315,7 +324,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { } static void lfs_alloc_ack(lfs_t *lfs) { - lfs->free.ack = lfs->free.off-1 + lfs->free.begin + lfs->cfg->block_count; + lfs->free.ack = lfs->free.begin+lfs->free.off + lfs->cfg->block_count; } diff --git a/tests/test_alloc.sh b/tests/test_alloc.sh index 493270d..8c81490 100755 --- a/tests/test_alloc.sh +++ b/tests/test_alloc.sh @@ -289,7 +289,7 @@ tests/test.py << TEST } lfs_file_close(&lfs, &file[0]) => 0; - // open whole + // open hole lfs_remove(&lfs, "bump") => 0; lfs_mkdir(&lfs, "splitdir") => 0; @@ -301,5 +301,128 @@ tests/test.py << TEST lfs_unmount(&lfs) => 0; TEST +echo "--- Outdated lookahead test ---" +rm -rf blocks +tests/test.py << TEST + lfs_format(&lfs, &cfg) => 0; + + lfs_mount(&lfs, &cfg) => 0; + + // fill completely with two files + lfs_file_open(&lfs, &file[0], "exhaustion1", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4)/2)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + + lfs_file_open(&lfs, &file[0], "exhaustion2", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + + // remount to force reset of lookahead + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + + // rewrite one file + lfs_file_open(&lfs, &file[0], "exhaustion1", + LFS_O_WRONLY | LFS_O_TRUNC) => 0; + lfs_file_sync(&lfs, &file[0]) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4)/2)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + + // rewrite second file, this requires lookahead does not + // use old population + lfs_file_open(&lfs, &file[0], "exhaustion2", + LFS_O_WRONLY | LFS_O_TRUNC) => 0; + lfs_file_sync(&lfs, &file[0]) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; +TEST + +echo "--- Outdated lookahead and split dir test ---" +rm -rf blocks +tests/test.py << TEST + lfs_format(&lfs, &cfg) => 0; + + lfs_mount(&lfs, &cfg) => 0; + + // fill completely with two files + lfs_file_open(&lfs, &file[0], "exhaustion1", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4)/2)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + + lfs_file_open(&lfs, &file[0], "exhaustion2", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + + // remount to force reset of lookahead + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + + // rewrite one file with a hole of one block + lfs_file_open(&lfs, &file[0], "exhaustion1", + LFS_O_WRONLY | LFS_O_TRUNC) => 0; + lfs_file_sync(&lfs, &file[0]) => 0; + size = strlen("blahblahblahblah"); + memcpy(buffer, "blahblahblahblah", size); + for (lfs_size_t i = 0; + i < ((cfg.block_count-4)/2 - 1)*(cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_close(&lfs, &file[0]) => 0; + + // try to allocate a directory, should fail! + lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; + + // file should not fail + lfs_file_open(&lfs, &file[0], "notasplit", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_write(&lfs, &file[0], "hi", 2) => 2; + lfs_file_close(&lfs, &file[0]) => 0; + + lfs_unmount(&lfs) => 0; +TEST + echo "--- Results ---" tests/stats.py