Dropped erase_count, block_count makes it redundant

Aside from asserts (which can be implemented in block devices), erase_count
provides no useful info aside from what's known with block_count and
risks mistakes during configuration.

Each set of known/unknown block_size-related variables has a well-defined
mount behavior:

  block_size  block_count
  known       known       => known bs, O(1)
  known       unknown     => known bs, O(1)
  unknown     known       => bs search, O(d(n))
  unknown     unknown     => bs search, O(n)

If block_size is unknown, block_count uses the erase_size as a unit,
which is the only reasonable option since block_size must be
>= prog/read/cache_size.
This commit is contained in:
Christopher Haster
2022-11-11 12:49:36 -06:00
parent 03beff6c54
commit c16120bf5f
2 changed files with 32 additions and 49 deletions
+26 -34
View File
@@ -43,7 +43,6 @@ static int lfs_bd_rawread(lfs_t *lfs, lfs_block_t block,
// read in erase_size chunks
while (size > 0) {
lfs_size_t delta = lfs_min(size, off + lfs->erase_size);
LFS_ASSERT(block <= lfs->erase_count);
LFS_ASSERT(off + size <= lfs->erase_size);
LFS_ASSERT(size % lfs->cfg->read_size == 0);
int err = lfs->cfg->read(lfs->cfg, block, off, buffer_, delta);
@@ -79,7 +78,6 @@ static int lfs_bd_rawprog(lfs_t *lfs, lfs_block_t block,
// prog in erase_size chunks
while (size > 0) {
lfs_size_t delta = lfs_min(size, off + lfs->erase_size);
LFS_ASSERT(block <= lfs->erase_count);
LFS_ASSERT(off + size <= lfs->erase_size);
LFS_ASSERT(size % lfs->cfg->prog_size == 0);
int err = lfs->cfg->prog(lfs->cfg, block, off, buffer_, delta);
@@ -107,7 +105,6 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
// adjust to physical erase size
block = block * (lfs->block_size/lfs->erase_size);
for (lfs_block_t i = 0; i < lfs->block_size/lfs->erase_size; i++) {
LFS_ASSERT(block + i <= lfs->erase_count);
int err = lfs->cfg->erase(lfs->cfg, block + i);
LFS_ASSERT(err <= 0);
if (err < 0) {
@@ -4006,30 +4003,20 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0);
LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0);
// setup erase_size/count, these can be zero for backwards compatibility
// setup erase_size, this can be zero for backwards compatibility
lfs->erase_size = lfs->cfg->erase_size;
lfs->erase_count = lfs->cfg->erase_count;
lfs->block_size = lfs->cfg->block_size;
lfs->block_count = lfs->cfg->block_count;
if (!lfs->erase_size) {
lfs->erase_size = lfs->block_size;
}
if (!lfs->erase_count) {
lfs->erase_count = lfs->block_count;
lfs->erase_size = lfs->cfg->block_size;
}
// check that block_size is a multiple of erase_size is a mulitiple of
// cache_size, this implies everything is a multiple of read_size and
// prog_size
LFS_ASSERT(lfs->erase_size % lfs->cfg->cache_size == 0);
if (lfs->block_size) {
LFS_ASSERT(lfs->block_size % lfs->erase_size == 0);
if (lfs->cfg->block_size) {
LFS_ASSERT(lfs->cfg->block_size % lfs->erase_size == 0);
}
// check that the block size is large enough to fit ctz pointers
LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->block_size-2*4))
<= lfs->block_size);
// block_cycles = 0 is no longer supported.
//
// block_cycles is the number of erase cycles before littlefs evicts
@@ -4145,13 +4132,17 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
return err;
}
// if block_size/block_count not specified, assume equal to erase blocks
// if block_size not specified, assume equal to erase blocks
lfs->block_size = lfs->cfg->block_size;
if (!lfs->block_size) {
lfs->block_size = lfs->erase_size;
}
if (!lfs->block_count) {
lfs->block_count = lfs->erase_count;
}
lfs->block_count = lfs->cfg->block_count;
LFS_ASSERT(lfs->block_count != 0);
// check that the block size is large enough to fit ctz pointers
LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->block_size-2*4))
<= lfs->block_size);
// create free lookahead
memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
@@ -4217,26 +4208,27 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
}
// if block_size is unknown we need to search for it
lfs_size_t block_size_limit = lfs->block_size;
lfs->block_size = lfs->cfg->block_size;
lfs_size_t block_size_limit = lfs->cfg->block_size;
if (!lfs->block_size) {
lfs->block_size = lfs->erase_size;
// make sure this doesn't overflow
if (!lfs->erase_count || lfs->erase_count/2
if (!lfs->cfg->block_count || lfs->cfg->block_count/2
> ((lfs_size_t)-1) / lfs->erase_size) {
block_size_limit = ((lfs_size_t)-1);
} else {
block_size_limit = (lfs->erase_count/2) * lfs->erase_size;
block_size_limit = (lfs->cfg->block_count/2) * lfs->erase_size;
}
}
// search for the correct block_size
while (true) {
// setup block_size/count so underlying operations work
if (!lfs->erase_count) {
lfs->block_count = lfs->cfg->block_count;
if (!lfs->block_count) {
lfs->block_count = (lfs_size_t)-1;
} else {
lfs->block_count = lfs->erase_count
/ (lfs->block_size/lfs->erase_size);
} else if (!lfs->cfg->block_size) {
lfs->block_count /= lfs->block_size/lfs->erase_size;
}
// scan directory blocks for superblock and any global updates
@@ -4383,10 +4375,10 @@ next_block_size:
goto cleanup;
}
// if block_count is set, skip block_sizes that aren't a factor,
// if block_count is non-zero, skip block_sizes that aren't a factor,
// 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
if (lfs->cfg->block_count && lfs->cfg->block_count
% (lfs->block_size/lfs->erase_size) != 0) {
goto next_block_size;
}
@@ -5503,7 +5495,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
LFS_TRACE("lfs_format(%p, %p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
".erase_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32", "
".block_cycles=%"PRIu32", .cache_size=%"PRIu32", "
".lookahead_size=%"PRIu32", .read_buffer=%p, "
@@ -5513,7 +5505,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
(void*)lfs, (void*)cfg, cfg->context,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
cfg->read_size, cfg->prog_size, cfg->erase_size,
cfg->block_size, cfg->block_count, cfg->block_cycles,
cfg->cache_size, cfg->lookahead_size,
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
@@ -5535,7 +5527,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
LFS_TRACE("lfs_mount(%p, %p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
".erase_size=%"PRIu32", "
".block_size=%"PRIu32", .block_count=%"PRIu32", "
".block_cycles=%"PRIu32", .cache_size=%"PRIu32", "
".lookahead_size=%"PRIu32", .read_buffer=%p, "
@@ -5545,7 +5537,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
(void*)lfs, (void*)cfg, cfg->context,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
cfg->read_size, cfg->prog_size, cfg->erase_size, cfg->erase_count,
cfg->read_size, cfg->prog_size, cfg->erase_size,
cfg->block_size, cfg->block_count, cfg->block_cycles,
cfg->cache_size, cfg->lookahead_size,
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
+6 -15
View File
@@ -205,17 +205,6 @@ struct lfs_config {
// backwards compatibility.
lfs_size_t erase_size;
// Number of erase blocks on the device.
//
// 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
// and may be a multiple of the physical erase_size.
//
@@ -228,14 +217,17 @@ 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(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
// - O(d(block_count)) if block_count is non-zero
// - O(log(block_count)) if block_count is a power of 2
// - O(block_count) if block_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, 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 block_count;
// Number of erase cycles before littlefs evicts metadata logs and moves
@@ -441,7 +433,6 @@ typedef struct lfs {
const struct lfs_config *cfg;
lfs_size_t erase_size;
lfs_size_t erase_count;
lfs_size_t block_size;
lfs_size_t block_count;
lfs_size_t name_max;