diff --git a/lfs.c b/lfs.c index 874715be..3d128ff7 100644 --- a/lfs.c +++ b/lfs.c @@ -5233,12 +5233,41 @@ static int lfs_fs_gc_(lfs_t *lfs) { #endif #ifndef LFS_READONLY -static int lfs_fs_rewrite_block_count(lfs_t *lfs, lfs_size_t block_count) { +#ifdef LFS_SHRINKIFCHEAP +static int lfs_shrink_checkblock(void * data, lfs_block_t block) { + lfs_size_t threshold = *((lfs_size_t *) data); + if (block >= threshold) { + return LFS_ERR_NOTEMPTY; + } + return 0; +} +#endif + +static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) { + int err; + + if (block_count == lfs->block_count) { + return 0; + } + + +#ifndef LFS_SHRINKIFCHEAP + // shrinking is not supported + LFS_ASSERT(block_count >= lfs->block_count); +#endif +#ifdef LFS_SHRINKIFCHEAP + lfs_block_t threshold = block_count; + err = lfs_fs_traverse_(lfs, lfs_shrink_checkblock, &threshold, true); + if (err) { + return err; + } +#endif + lfs->block_count = block_count; // fetch the root lfs_mdir_t root; - int err = lfs_dir_fetch(lfs, &root, lfs->root); + err = lfs_dir_fetch(lfs, &root, lfs->root); if (err) { return err; } @@ -5263,41 +5292,6 @@ static int lfs_fs_rewrite_block_count(lfs_t *lfs, lfs_size_t block_count) { } return 0; } - -static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) { - // shrinking is not supported - LFS_ASSERT(block_count >= lfs->block_count); - - if (block_count > lfs->block_count) { - return lfs_fs_rewrite_block_count(lfs, block_count); - } - - return 0; -} - -static int lfs_shrink_check_block(void * data, lfs_block_t block) { - lfs_size_t threshold = *((lfs_size_t *) data); - if (block >= threshold) { - return LFS_ERR_NOTEMPTY; - } - return 0; -} - -static int lfs_fs_shrink_(lfs_t *lfs, lfs_size_t block_count) { - if (block_count != lfs->block_count) { - - lfs_block_t threshold = block_count; - - int err = lfs_fs_traverse_(lfs, lfs_shrink_check_block, &threshold, true); - if (err) { - return err; - } - - return lfs_fs_rewrite_block_count(lfs, block_count); - } - - return 0; -} #endif #ifdef LFS_MIGRATE @@ -6514,22 +6508,6 @@ int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count) { } #endif -#ifndef LFS_READONLY -int lfs_fs_shrink(lfs_t *lfs, lfs_size_t block_count) { - int err = LFS_LOCK(lfs->cfg); - if (err) { - return err; - } - LFS_TRACE("lfs_fs_shrink(%p, %"PRIu32")", (void*)lfs, block_count); - - err = lfs_fs_shrink_(lfs, block_count); - - LFS_TRACE("lfs_fs_shrink -> %d", err); - LFS_UNLOCK(lfs->cfg); - return err; -} -#endif - #ifdef LFS_MIGRATE int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { int err = LFS_LOCK(cfg); diff --git a/lfs.h b/lfs.h index 072b290b..be98b54b 100644 --- a/lfs.h +++ b/lfs.h @@ -766,23 +766,16 @@ int lfs_fs_gc(lfs_t *lfs); // Grows the filesystem to a new size, updating the superblock with the new // block count. // +// if LFS_SHRINKIFCHEAP is defined, this function will also accept +// block_counts smaller than the current configuration, after checking +// that none of the blocks that are being removed are in use. +// // Note: This is irreversible. // // Returns a negative error code on failure. int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count); #endif -#ifndef LFS_READONLY -// Shrinks the filesystem to a new size, updating the superblock with the new -// block count. -// -// Note: This first checks that none of the blocks that are being removed are in use -// and will fail if it is the case -// -// Returns a negative error code on failure. -int lfs_fs_shrink(lfs_t *lfs, lfs_size_t block_count); -#endif - #ifndef LFS_READONLY #ifdef LFS_MIGRATE // Attempts to migrate a previous version of littlefs diff --git a/tests/test_shrink.toml b/tests/test_shrink.toml index 0c317d66..10c00ae8 100644 --- a/tests/test_shrink.toml +++ b/tests/test_shrink.toml @@ -7,7 +7,7 @@ code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_fs_shrink(&lfs, AFTER_BLOCK_COUNT) => 0; + lfs_fs_grow(&lfs, AFTER_BLOCK_COUNT) => 0; lfs_unmount(&lfs); if (BLOCK_COUNT != AFTER_BLOCK_COUNT) { lfs_mount(&lfs, cfg) => LFS_ERR_INVAL; @@ -46,7 +46,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; } - int err = lfs_fs_shrink(&lfs, AFTER_BLOCK_COUNT); + int err = lfs_fs_grow(&lfs, AFTER_BLOCK_COUNT); if (err == 0) { for (int i = 0; i < FILES_COUNT + 1; i++) { lfs_file_t file; diff --git a/tests/test_superblocks.toml b/tests/test_superblocks.toml index 07961751..4daf764b 100644 --- a/tests/test_superblocks.toml +++ b/tests/test_superblocks.toml @@ -550,7 +550,7 @@ code = ''' // same size is a noop lfs_mount(&lfs, cfg) => 0; - lfs_fs_shrink(&lfs, BLOCK_COUNT) => 0; + lfs_fs_grow(&lfs, BLOCK_COUNT) => 0; lfs_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.block_size == BLOCK_SIZE); assert(fsinfo.block_count == BLOCK_COUNT); @@ -564,7 +564,7 @@ code = ''' // grow to new size lfs_mount(&lfs, cfg) => 0; - lfs_fs_shrink(&lfs, BLOCK_COUNT_2) => 0; + lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0; lfs_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.block_size == BLOCK_SIZE); assert(fsinfo.block_count == BLOCK_COUNT_2); @@ -594,7 +594,7 @@ code = ''' // same size is a noop lfs_mount(&lfs, cfg) => 0; - lfs_fs_shrink(&lfs, BLOCK_COUNT_2) => 0; + lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0; lfs_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.block_size == BLOCK_SIZE); assert(fsinfo.block_count == BLOCK_COUNT_2);