diff --git a/lfs.c b/lfs.c index 63be7fb8..55276b22 100644 --- a/lfs.c +++ b/lfs.c @@ -4001,7 +4001,6 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { LFS_ASSERT(lfs->cfg->prog_size != 0); LFS_ASSERT(lfs->cfg->cache_size != 0); LFS_ASSERT(lfs->cfg->erase_size != 0 || lfs->cfg->block_size != 0); - LFS_ASSERT(lfs->cfg->erase_count != 0 || lfs->cfg->block_count != 0); // check that cache_size is a multiple of prog_size and read_size LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0); @@ -4222,21 +4221,23 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { if (!lfs->block_size) { lfs->block_size = lfs->erase_size; // make sure this doesn't overflow - lfs_size_t limit = lfs->block_count - ? lfs->block_count/2 - : lfs->erase_count/2; - if (limit > ((lfs_size_t)-1) / lfs->block_size) { + if (!lfs->erase_count || lfs->erase_count/2 + > ((lfs_size_t)-1) / lfs->erase_size) { block_size_limit = ((lfs_size_t)-1); } else { - block_size_limit = limit * lfs->block_size; + block_size_limit = (lfs->erase_count/2) * lfs->erase_size; } } // search for the correct block_size while (true) { // setup block_size/count so underlying operations work - lfs->block_count = lfs->erase_count - / (lfs->block_size/lfs->erase_size); + if (!lfs->erase_count) { + lfs->block_count = (lfs_size_t)-1; + } else { + lfs->block_count = lfs->erase_count + / (lfs->block_size/lfs->erase_size); + } // scan directory blocks for superblock and any global updates lfs_mdir_t dir = {.tail = {0, 1}}; @@ -4301,7 +4302,7 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { } if (superblock.block_count != lfs->block_count) { - if ((lfs->cfg->block_size && lfs->cfg->block_count) + if (lfs->cfg->block_count || superblock.block_count > lfs->block_count) { LFS_ERROR("Invalid block count %"PRIu32, superblock.block_count); @@ -4383,9 +4384,9 @@ next_block_size: } // if block_count is set, skip block_sizes that aren't a factor, - // this brings our search down from O(n) to O(d(n)), and - // O(log(n)) for powers of 2 - if (lfs->cfg->block_count && lfs->cfg->block_count + // this brings our search down from O(n) to O(d(n)), O(log(n)) + // on average, and O(log(n)) for powers of 2 + if (lfs->erase_count && lfs->erase_count % (lfs->block_size/lfs->erase_size) != 0) { goto next_block_size; } diff --git a/lfs.h b/lfs.h index d5927bca..6b2780ed 100644 --- a/lfs.h +++ b/lfs.h @@ -209,6 +209,11 @@ struct lfs_config { // // If zero, the block_count is used as the erase_count. This is mostly for // backwards compatibility. + // + // If zero and block_count is zero, this is treated as unknown. + // + // If non-zero, littlefs will assume block_size is a factor of + // erase_size*erase_count to speed up mount when no superblock is found. lfs_size_t erase_count; // Size of a logical block in bytes. This does not impact RAM consumption @@ -223,18 +228,14 @@ struct lfs_config { // block_size, but it can take time to fail if a superblock is not found: // // - O(block_size) if a superblock is found - // - O(d(block_count)) if block_count is non-zero - // - O(log(block_count)) if block_count is a power of 2 - // - O(erase_count) if block_count is zero + // - O(d(erase_count)) if erase_count is non-zero + // - O(log(erase_count)) if erase_count is a power of 2 + // - O(erase_count) if erase_count is zero lfs_size_t block_size; // Number of logical blocks on the device. // // If zero, littlefs uses the block_count stored in the superblock. - // - // If non-zero and block_size is zero, littlefs will assume block_size - // is a factor of erase_size*block_count to speed up mount when no - // superblock is found. lfs_size_t block_count; // Number of erase cycles before littlefs evicts metadata logs and moves