From 41c0b1e7f0d9828aa8afbf56becb67915ca8f968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sat, 28 May 2022 11:28:54 +0200 Subject: [PATCH 1/4] pkg/littlefs: make block size configurable --- pkg/littlefs/fs/littlefs_fs.c | 34 ++++++++++++++++++++++------------ sys/include/fs/littlefs_fs.h | 8 ++++++++ tests/pkg_littlefs/main.c | 10 ++++++++-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/pkg/littlefs/fs/littlefs_fs.c b/pkg/littlefs/fs/littlefs_fs.c index 85a249d4d4..4c31e55544 100644 --- a/pkg/littlefs/fs/littlefs_fs.c +++ b/pkg/littlefs/fs/littlefs_fs.c @@ -62,7 +62,7 @@ static int littlefs_err_to_errno(ssize_t err) } static int _dev_read(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) + lfs_off_t off, void *buffer, lfs_size_t size) { littlefs_desc_t *fs = c->context; mtd_dev_t *mtd = fs->dev; @@ -70,12 +70,12 @@ static int _dev_read(const struct lfs_config *c, lfs_block_t block, DEBUG("lfs_read: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n", (void *)c, block, off, buffer, size); - return mtd_read_page(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector, - off, size); + uint32_t page = (fs->base_addr + block) * fs->sectors_per_block * mtd->pages_per_sector; + return mtd_read_page(mtd, buffer, page, off, size); } static int _dev_write(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) + lfs_off_t off, const void *buffer, lfs_size_t size) { littlefs_desc_t *fs = c->context; mtd_dev_t *mtd = fs->dev; @@ -83,8 +83,8 @@ static int _dev_write(const struct lfs_config *c, lfs_block_t block, DEBUG("lfs_write: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n", (void *)c, block, off, buffer, size); - return mtd_write_page_raw(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector, - off, size); + uint32_t page = (fs->base_addr + block) * fs->sectors_per_block * mtd->pages_per_sector; + return mtd_write_page_raw(mtd, buffer, page, off, size); } static int _dev_erase(const struct lfs_config *c, lfs_block_t block) @@ -94,7 +94,8 @@ static int _dev_erase(const struct lfs_config *c, lfs_block_t block) DEBUG("lfs_erase: c=%p, block=%" PRIu32 "\n", (void *)c, block); - return mtd_erase_sector(mtd, fs->base_addr + block, 1); + uint32_t sector = (fs->base_addr + block) * fs->sectors_per_block; + return mtd_erase_sector(mtd, sector, fs->sectors_per_block); } static int _dev_sync(const struct lfs_config *c) @@ -117,11 +118,19 @@ static int prepare(littlefs_desc_t *fs) memset(&fs->fs, 0, sizeof(fs->fs)); - if (!fs->config.block_count) { - fs->config.block_count = fs->dev->sector_count - fs->base_addr; - } + size_t block_size = fs->dev->pages_per_sector * fs->dev->page_size; +#if LITTLEFS_MIN_BLOCK_SIZE_EXP >= 0 + block_size = ((block_size - 1) + (1u << LITTLEFS_MIN_BLOCK_SIZE_EXP)) + / block_size * block_size; +#endif + fs->sectors_per_block = block_size / (fs->dev->pages_per_sector * fs->dev->page_size); + size_t block_count = fs->dev->sector_count / fs->sectors_per_block; + if (!fs->config.block_size) { - fs->config.block_size = fs->dev->page_size * fs->dev->pages_per_sector; + fs->config.block_size = block_size; + } + if (!fs->config.block_count) { + fs->config.block_count = block_count - fs->base_addr; } if (!fs->config.prog_size) { fs->config.prog_size = fs->dev->page_size; @@ -443,7 +452,8 @@ static int _statvfs(vfs_mount_t *mountp, const char *restrict path, struct statv mutex_unlock(&fs->lock); buf->f_bsize = fs->fs.cfg->block_size; /* block size */ - buf->f_frsize = fs->fs.cfg->block_size; /* fundamental block size */ + buf->f_frsize = fs->dev->page_size * + fs->dev->pages_per_sector; /* fundamental block size */ buf->f_blocks = fs->fs.cfg->block_count; /* Blocks total */ buf->f_bfree = buf->f_blocks - nb_blocks; /* Blocks free */ buf->f_bavail = buf->f_blocks - nb_blocks; /* Blocks available to non-privileged processes */ diff --git a/sys/include/fs/littlefs_fs.h b/sys/include/fs/littlefs_fs.h index df25b0b331..0d1eecd927 100644 --- a/sys/include/fs/littlefs_fs.h +++ b/sys/include/fs/littlefs_fs.h @@ -58,6 +58,13 @@ extern "C" { * If set, it must be program size */ #define LITTLEFS_PROG_BUFFER_SIZE (0) #endif + +#ifndef LITTLEFS_MIN_BLOCK_SIZE_EXP +/** + * The exponent of the minimum acceptable block size in bytes (2^n). + * The desired block size is not guaranteed to be applicable but will be respected. */ +#define LITTLEFS_MIN_BLOCK_SIZE_EXP (-1) +#endif /** @} */ /** @@ -72,6 +79,7 @@ typedef struct { * total number of block is defined in @p config. * if set to 0, the total number of sectors from the mtd is used */ uint32_t base_addr; + uint16_t sectors_per_block; /**< number of sectors per block */ #if LITTLEFS_FILE_BUFFER_SIZE || DOXYGEN /** file buffer to use internally if LITTLEFS_FILE_BUFFER_SIZE is set */ uint8_t file_buf[LITTLEFS_FILE_BUFFER_SIZE]; diff --git a/tests/pkg_littlefs/main.c b/tests/pkg_littlefs/main.c index 4c39317ef9..b9669b3d06 100644 --- a/tests/pkg_littlefs/main.c +++ b/tests/pkg_littlefs/main.c @@ -383,7 +383,10 @@ static void tests_littlefs_statvfs(void) int res = vfs_statvfs("/test-littlefs/", &stat1); TEST_ASSERT_EQUAL_INT(0, res); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat1.f_bsize); + TEST_ASSERT_EQUAL_INT(_dev->page_size * + _dev->pages_per_sector * + littlefs_desc.sectors_per_block, + stat1.f_bsize); TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat1.f_frsize); TEST_ASSERT((_dev->pages_per_sector * _dev->page_size * _dev->sector_count) >= stat1.f_blocks); @@ -400,7 +403,10 @@ static void tests_littlefs_statvfs(void) res = vfs_statvfs("/test-littlefs/", &stat2); TEST_ASSERT_EQUAL_INT(0, res); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat2.f_bsize); + TEST_ASSERT_EQUAL_INT(_dev->page_size * + _dev->pages_per_sector * + littlefs_desc.sectors_per_block, + stat2.f_bsize); TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat2.f_frsize); TEST_ASSERT(stat1.f_bfree > stat2.f_bfree); TEST_ASSERT(stat1.f_bavail > stat2.f_bavail); From a29d5c24cd635f46bae19165c46f3f62be1c1bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sat, 28 May 2022 11:30:01 +0200 Subject: [PATCH 2/4] pkg/littlefs2: make block size configurable --- pkg/littlefs2/Kconfig | 9 +++++++++ pkg/littlefs2/fs/littlefs2_fs.c | 35 +++++++++++++++++++++------------ sys/include/fs/littlefs2_fs.h | 8 ++++++++ tests/pkg_littlefs2/main.c | 10 ++++++++-- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/pkg/littlefs2/Kconfig b/pkg/littlefs2/Kconfig index 26deab41e8..8e554c84a6 100644 --- a/pkg/littlefs2/Kconfig +++ b/pkg/littlefs2/Kconfig @@ -54,4 +54,13 @@ config LITTLEFS2_BLOCK_CYCLES Sets the maximum number of erase cycles before blocks are evicted as a part of wear leveling. -1 disables wear-leveling. +config LITTLEFS2_MIN_BLOCK_SIZE_EXP + int "Minimum acceptable block size" + range -1 15 + default -1 + help + Sets the exponent of the minimum acceptable block size in bytes (2^n). + The actual block size may be larger due to device properties. + The default value (-1) sets the block size to the smalles possible value. + endif # MODULE_LITTLEFS2_FS diff --git a/pkg/littlefs2/fs/littlefs2_fs.c b/pkg/littlefs2/fs/littlefs2_fs.c index 5c65cd6ce3..abf65e7f4a 100644 --- a/pkg/littlefs2/fs/littlefs2_fs.c +++ b/pkg/littlefs2/fs/littlefs2_fs.c @@ -62,7 +62,7 @@ static int littlefs_err_to_errno(ssize_t err) } static int _dev_read(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) + lfs_off_t off, void *buffer, lfs_size_t size) { littlefs2_desc_t *fs = c->context; mtd_dev_t *mtd = fs->dev; @@ -70,12 +70,12 @@ static int _dev_read(const struct lfs_config *c, lfs_block_t block, DEBUG("lfs_read: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n", (void *)c, block, off, buffer, size); - return mtd_read_page(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector, - off, size); + uint32_t page = (fs->base_addr + block) * fs->sectors_per_block * mtd->pages_per_sector; + return mtd_read_page(mtd, buffer, page, off, size); } static int _dev_write(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) + lfs_off_t off, const void *buffer, lfs_size_t size) { littlefs2_desc_t *fs = c->context; mtd_dev_t *mtd = fs->dev; @@ -83,8 +83,8 @@ static int _dev_write(const struct lfs_config *c, lfs_block_t block, DEBUG("lfs_write: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n", (void *)c, block, off, buffer, size); - return mtd_write_page_raw(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector, - off, size); + uint32_t page = (fs->base_addr + block) * fs->sectors_per_block * mtd->pages_per_sector; + return mtd_write_page_raw(mtd, buffer, page, off, size); } static int _dev_erase(const struct lfs_config *c, lfs_block_t block) @@ -94,8 +94,8 @@ static int _dev_erase(const struct lfs_config *c, lfs_block_t block) DEBUG("lfs_erase: c=%p, block=%" PRIu32 "\n", (void *)c, block); - return mtd_erase_sector(mtd, fs->base_addr + block, 1); -} + uint32_t sector = (fs->base_addr + block) * fs->sectors_per_block; + return mtd_erase_sector(mtd, sector, fs->sectors_per_block);} static int _dev_sync(const struct lfs_config *c) { @@ -117,11 +117,19 @@ static int prepare(littlefs2_desc_t *fs) memset(&fs->fs, 0, sizeof(fs->fs)); - if (!fs->config.block_count) { - fs->config.block_count = fs->dev->sector_count - fs->base_addr; - } + size_t block_size = fs->dev->pages_per_sector * fs->dev->page_size; +#if CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP >= 0 + block_size = ((block_size - 1) + (1u << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP)) + / block_size * block_size; +#endif + fs->sectors_per_block = block_size / (fs->dev->pages_per_sector * fs->dev->page_size); + size_t block_count = fs->dev->sector_count / fs->sectors_per_block; + if (!fs->config.block_size) { - fs->config.block_size = fs->dev->page_size * fs->dev->pages_per_sector; + fs->config.block_size = block_size; + } + if (!fs->config.block_count) { + fs->config.block_count = block_count - fs->base_addr; } if (!fs->config.prog_size) { fs->config.prog_size = fs->dev->page_size; @@ -449,7 +457,8 @@ static int _statvfs(vfs_mount_t *mountp, const char *restrict path, struct statv mutex_unlock(&fs->lock); buf->f_bsize = fs->fs.cfg->block_size; /* block size */ - buf->f_frsize = fs->fs.cfg->block_size; /* fundamental block size */ + buf->f_frsize = fs->dev->page_size * + fs->dev->pages_per_sector; /* fundamental block size */ buf->f_blocks = fs->fs.cfg->block_count; /* Blocks total */ buf->f_bfree = buf->f_blocks - nb_blocks; /* Blocks free */ buf->f_bavail = buf->f_blocks - nb_blocks; /* Blocks available to non-privileged processes */ diff --git a/sys/include/fs/littlefs2_fs.h b/sys/include/fs/littlefs2_fs.h index 2f66763c0a..78fff4b74a 100644 --- a/sys/include/fs/littlefs2_fs.h +++ b/sys/include/fs/littlefs2_fs.h @@ -74,6 +74,13 @@ extern "C" { * of wear leveling. -1 disables wear-leveling. */ #define CONFIG_LITTLEFS2_BLOCK_CYCLES (512) #endif + +#ifndef CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP +/** + * The exponent of the minimum acceptable block size in bytes (2^n). + * The desired block size is not guaranteed to be applicable but will be respected. */ +#define CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP (-1) +#endif /** @} */ /** @@ -88,6 +95,7 @@ typedef struct { * total number of block is defined in @p config. * if set to 0, the total number of sectors from the mtd is used */ uint32_t base_addr; + uint16_t sectors_per_block; /**< number of sectors per block */ #if CONFIG_LITTLEFS2_FILE_BUFFER_SIZE || DOXYGEN /** file buffer to use internally if CONFIG_LITTLEFS2_FILE_BUFFER_SIZE * is set */ diff --git a/tests/pkg_littlefs2/main.c b/tests/pkg_littlefs2/main.c index 6f48cf7bd3..01716715b0 100644 --- a/tests/pkg_littlefs2/main.c +++ b/tests/pkg_littlefs2/main.c @@ -383,7 +383,10 @@ static void tests_littlefs_statvfs(void) int res = vfs_statvfs("/test-littlefs/", &stat1); TEST_ASSERT_EQUAL_INT(0, res); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat1.f_bsize); + TEST_ASSERT_EQUAL_INT(_dev->page_size * + _dev->pages_per_sector * + littlefs_desc.sectors_per_block, + stat1.f_bsize); TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat1.f_frsize); TEST_ASSERT((_dev->pages_per_sector * _dev->page_size * _dev->sector_count) >= stat1.f_blocks); @@ -402,7 +405,10 @@ static void tests_littlefs_statvfs(void) res = vfs_statvfs("/test-littlefs/", &stat2); TEST_ASSERT_EQUAL_INT(0, res); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat2.f_bsize); + TEST_ASSERT_EQUAL_INT(_dev->page_size * + _dev->pages_per_sector * + littlefs_desc.sectors_per_block, + stat2.f_bsize); TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat2.f_frsize); TEST_ASSERT(stat1.f_bfree > stat2.f_bfree); TEST_ASSERT(stat1.f_bavail > stat2.f_bavail); From 4dd5cb3e084d34597cd9d90165077ddc7321ecfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sat, 18 Jun 2022 10:22:43 +0200 Subject: [PATCH 3/4] pkg/littlefs2: add warning if block size is not reasonable --- pkg/littlefs2/fs/littlefs2_fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/littlefs2/fs/littlefs2_fs.c b/pkg/littlefs2/fs/littlefs2_fs.c index abf65e7f4a..18109fc5c7 100644 --- a/pkg/littlefs2/fs/littlefs2_fs.c +++ b/pkg/littlefs2/fs/littlefs2_fs.c @@ -117,6 +117,11 @@ static int prepare(littlefs2_desc_t *fs) memset(&fs->fs, 0, sizeof(fs->fs)); + static_assert(0 > CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP || + 6 < CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP, + "CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP must be at least 7, " + "to configure a reasonable block size of at least 128 bytes."); + size_t block_size = fs->dev->pages_per_sector * fs->dev->page_size; #if CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP >= 0 block_size = ((block_size - 1) + (1u << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP)) From 578e6280e3ab665867dc44506f847b889e033fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sat, 18 Jun 2022 10:24:17 +0200 Subject: [PATCH 4/4] pkg/littlefs: add warning if block size is not reasonable --- pkg/littlefs/fs/littlefs_fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/littlefs/fs/littlefs_fs.c b/pkg/littlefs/fs/littlefs_fs.c index 4c31e55544..72d3a97e4e 100644 --- a/pkg/littlefs/fs/littlefs_fs.c +++ b/pkg/littlefs/fs/littlefs_fs.c @@ -118,6 +118,11 @@ static int prepare(littlefs_desc_t *fs) memset(&fs->fs, 0, sizeof(fs->fs)); + static_assert(0 > LITTLEFS_MIN_BLOCK_SIZE_EXP || + 6 < LITTLEFS_MIN_BLOCK_SIZE_EXP, + "LITTLEFS_MIN_BLOCK_SIZE_EXP must be at least 7, " + "to configure a reasonable block size of at least 128 bytes."); + size_t block_size = fs->dev->pages_per_sector * fs->dev->page_size; #if LITTLEFS_MIN_BLOCK_SIZE_EXP >= 0 block_size = ((block_size - 1) + (1u << LITTLEFS_MIN_BLOCK_SIZE_EXP))