Changed block_size search to use erase_count when block_size is zero

This hopefully helps make it more clear that we are using erase_size as the
unit during the block_size search. However this does mean you need to
set erase_count to zero to allow any littlefs size, which might be a bit
confusing:

  block_size  block_count  erase_size  erase_count
  known       known        known       known       => known bs, O(1)
  known       unknown      known       known       => known bs, O(1)
  unknown     unknown      known       known       => bs search, O(d(n))
  unknown     unknown      known       unknown     => bs search, O(n)
This commit is contained in:
Christopher Haster
2022-11-11 00:53:44 -06:00
parent 75f80aabd7
commit 03beff6c54
2 changed files with 21 additions and 19 deletions

25
lfs.c
View File

@@ -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;
}

15
lfs.h
View File

@@ -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