-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
littlefs: make block size configurable at compile time #18141
littlefs: make block size configurable at compile time #18141
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, let´s do it like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
= 1536
This 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.
@@ -95,7 +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; | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
@@ -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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
littlefs
andlittlefs2
on myat24c256
EEPROM.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
littlefs
documentation 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
at24c256
onstm32
like me, you must configure the block size to be128
bytes, elsewill fire.
Issues/PRs references