littlefs: make block size configurable at compile time#18141
littlefs: make block size configurable at compile time#18141benpicco merged 4 commits intoRIOT-OS:masterfrom
Conversation
c858fce to
d036448
Compare
cc16c16 to
ebc4b42
Compare
ebc4b42 to
af45ba0
Compare
pkg/littlefs2/Kconfig
Outdated
| int "Minimum acceptable block size" | ||
| default 512 | ||
| help | ||
| Sets the minimum acceptable block size which must be a power of two. |
There was a problem hiding this comment.
Isn't it safer to express this as the exponent of 2^n? Then we don't have to do any checks
There was a problem hiding this comment.
Yes, let´s do it like that.
There was a problem hiding this comment.
And let´s have a special value that sets the block size to the sector size and chose this value as default. So nobody will be forced to reformat an existing FS. However the tests must also pass with different block sizes of course.
There was a problem hiding this comment.
special value
let´s choose < 0.
1b2990b to
ef8da60
Compare
pkg/littlefs2/fs/littlefs2_fs.c
Outdated
| if (!(block_size = ((1u << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP) / block_size) * block_size)) { | ||
| block_size = fs->dev->pages_per_sector * fs->dev->page_size; | ||
| } |
There was a problem hiding this comment.
This needs some explaining.
I think we need the least common multiple here, so
block_size = (1 << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP) * block_size
/ gcd(block_size, 1 << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP);There was a problem hiding this comment.
size_t block_size = fs->dev->pages_per_sector * fs->dev->page_size;
block_size = (1 << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP) * block_size
/ gcd(block_size, 1 << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP);Example (desired block size is 512):
block_size = 3 * 128;
block_size = (1 << 9) * 384 / gcd(384, 1 << 9);
= 512 * 384 / 128
= 1536This ensures that the actual block size is not smaller then 1 << CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP, but this is not really the the result I had expected.
I had something different in mind. Right now, the resulting block size is the next smaller multiple of the sector size (<=). But the documentation reads that CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP is the "minimum acceptable" block size, so it should be the next bigger multiple of the sector size. In the example above, it would be 768.
| * if set to 0, the total number of sectors from the mtd is used */ | ||
| uint32_t base_addr; | ||
| uint8_t sectors_per_block; /**< number of sectors per block */ | ||
| uint16_t sectors_per_block; /**< number of sectors per block */ |
There was a problem hiding this comment.
I made this a uint16_t because I chose the maximum of CONFIG_LITTLEFS2_MIN_BLOCK_SIZE_EXP to be 2^15 in Kconfig.
59a94eb to
81e6478
Compare
81e6478 to
578e628
Compare
benpicco
left a comment
There was a problem hiding this comment.
Changes look good and existing file systems still mount fine with this change.
|
Thank you very much |
|
It looks like this PR broke in the future the |
|
Just to clarify it also fixes things, it just exposes other things. |
| * 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 */ |
There was a problem hiding this comment.
This addition resulted in the subsequent buffers no longer being aligned two 4 bytes by accident, which triggered unaligned memory accesses. On Cortex M0+, such as used by the samr21-xpro, this then resulted in hard faults.
But the issue really is that alignment requirements need to be communicated to the compiler. It was just luck that this worked before.
There was a problem hiding this comment.
Well not so much luck since the uint32_t will always be word-aligned.
Moving sectors_per_block to end end of the struct should be the simple fix. (The buffers are already word-multiples)
There was a problem hiding this comment.
I doubt anyone placed them after a uint32_t member to align them without adding a comment to warn about breakage. To me, this looks like we got lucky here :)
(E.g. iolist_t and pkt_snip_t have a common memory layout, but that is documented to avoid anyone from breaking it. I would expect similar comments here if that was inentionally.)
Contribution description
The reason for me to create this PR was that I was experiencing problems when I tried to run
littlefsandlittlefs2on myat24c256EEPROM.Currently, the block size is always equal to
mtd->page_size * mtd->pages_per_sector, but in practice the block size must only be a multiple of the sector size.In my case, the resulting block size was 64 bytes, equal to the sector size, equal to the page size.
I read some
littlefsdocumentation and found out that the minimum block size must be 104 bytes.With this patch, resulting in a block size of 128 bytes, problems seemed to be gone.
However, this is not a proper fix to set an imaginary sector size, that just happens to work for some filesystem.
So I concluded that the proper fix would be to have the opportunity to configure a reasonable logical block size for a filesystem and keep the device properties untouched, like it is the case for most common filesystems that run on Linux.
For
fatfs, I did not find a way to configure the block size at first glace. Maybe they don´t support it.Testing procedure
A
freshly formattedfilesystem must still work.Existing filesystems may need to be formatted.If you are using an
at24c256onstm32like me, you must configure the block size to be128bytes, elsewill fire.
Issues/PRs references