I'm currently facing an error stating: "corrupted dir pair at 3 2".
Little fs is running on an e.mmc device, but the same problem has occured when using a SD card.
Mounting the filesystem is successful, but when I try to open a file I get the above mentioned error.
I tried writing a line of code to format little fs and remounting it, but the error is consistent.
It seems to have occured out of nowhere, since I have previously been able to read and write files. The only access to the storage device is read/write to a boot count file as shown in the little fs example.
My question is how can I fix this, and what can I do runtime to fix corruption of little fs without formatting the entire e.mmc device?
Thanks in advance
Hi @iverdiver, that's an interesting issue.
The littlefs should be fixing its own corruption. If you see "corrupted dir pair at 3 2", that means something is unrecoverable. However, format doesn't care and should be resetting the storage to a clean slate.
Are you able to post the code you are using to call format? Is it the same as the example?
Have you tested your block device layer? Would you be able to post the read/prog/erase functions? It could be that erasing block 0 is unintentionally erasing block 2, since those are the only two blocks written during a format.
Long post incomming!
I've been looking into the problem and I believe that it happens when a file sync fails due to some issue within the block device layer as you suggested.
I'm currently testing on an SD card at the moment where I've set the lfs config struct to have a read_size, write_size and block_size of 4096 bytes. SD card block size is 512.
Following is a log output where lfs is formattet then remounted. It attempts to open boot_count first, but fails since it doesn't yet exist. I then print how many sdcard blocks is being read/written/erased and from which address. 8 blocks corresponds to 1 lfs block (512*8 = 4096)
SD Card initialized
Mounting file system..
LFS initialized
Read 8 blocks starting from block 0
Read 8 blocks starting from block 8
Read 8 blocks starting from block 0
Read 8 blocks starting from block 0
Read 8 blocks starting from block 16
Read 8 blocks starting from block 24
Read 8 blocks starting from block 16
Failed to open file
Create file
Read 8 blocks starting from block 0
Read 8 blocks starting from block 8
Read 8 blocks starting from block 0
Read 8 blocks starting from block 24
Read 8 blocks starting from block 16
Read 8 blocks starting from block 0
Read 8 blocks starting from block 8
Read 8 blocks starting from block 0
Read 8 blocks starting from block 24
Read 8 blocks starting from block 16
erase from block 16 to 24 from SD card
Write 8 blocks starting from block 16
File opened
Read 8 blocks starting from block 0
Read 8 blocks starting from block 8
Read 8 blocks starting from block 0
Read 8 blocks starting from block 24
Read 8 blocks starting from block 16
erase from block 32 to 40 from SD card
New boot count: 1
Close file
Write 8 blocks starting from block 32
Corrupted dir pair at 2 3 (lfs.c line 495)
Failed to close file
The corruption could be because the sd/mmc card does not allow block erase of only 4096 bytes. I'm not sure this is actually the problem, but this does raise a new question:
Example:
SD/MMC device read/write block_size: 512 bytes.
SD/MMC device erase size: 65536.
LFS settings:
Read size: 4096 bytes. (8xSD/MMC read/write)
Write size: 4096 bytes.
Block_size: 65536 bytes
When read or write is called on a file that is located on for example lfs block 2 (SD/MMC block address 16 (2x8)) a corresponding erase should erase 16 lfs blocks(65536/4096=16) from block 0 to 15 or 128 SD/MMC blocks(0-128), however when the erase function is called it parses block 2 to be erased, as if it should only erase a block of 4096 bytes. But since the block_size is set to 65536 it will however attempt to erase 16 blocks (2 to 17).
I would expect the erase function to parse "erase block 0" since block 2 is within the erase sector(block 0-15).
It seems as if the next read/write functions does not know that the an erase is 65536 bytes, and therefore reads will attempt to access different 4096 bytes blocks within the erased block of 65536 bytes.
I must have missed some crucial configuration or maybe I need to adapt my block device layer somehow.
Any advice is very much appreciated.
The corruption could be because the sd/mmc card does not allow block erase of only 4096 bytes.
This is not true in most of the cases. Most SD cards allow you to erase 512 byte long blocks. Whether it's the case can be determined from ERASE_BLK_EN field in the CSD register.
If ERASE_BLK_EN=1 the host can erase one or multiple units of 512 bytes.
For SD v2.0 cards (I suspect all cards which are available today) this field is always 1, which means that "new" cards can always be erased in 512 bytes long blocks.
However if your card does not support this, you should just set block size to 64 kB (do note that the so-called "sector size" does not have to be 64 kB long - this value is also available in the CSD), and read/prog sizes to 512 bytes (or a multiple of 512).
Here you can find my implementations of the lfs functions operating on the block devices - maybe you can use that as a reference.
https://github.com/DISTORTEC/distortos/blob/master/source/FileSystem/littlefs/LittlefsFileSystem.cpp#L103
Thanks to both of you for replying.
The SD card does allow block erases of 512 bytes. So as you stated this could not be causing the corruption error.
I looked at your implementation FreedieChopin and compared it to my own. As Geky suggested there was a bug in my block device layor. It works perfectly now.
Thanks again.
@iverdiver Glad you were able to get it working!
Most helpful comment
This is not true in most of the cases. Most SD cards allow you to erase 512 byte long blocks. Whether it's the case can be determined from ERASE_BLK_EN field in the CSD register.
For SD v2.0 cards (I suspect all cards which are available today) this field is always 1, which means that "new" cards can always be erased in 512 bytes long blocks.
However if your card does not support this, you should just set block size to 64 kB (do note that the so-called "sector size" does not have to be 64 kB long - this value is also available in the CSD), and read/prog sizes to 512 bytes (or a multiple of 512).
Here you can find my implementations of the lfs functions operating on the block devices - maybe you can use that as a reference.
https://github.com/DISTORTEC/distortos/blob/master/source/FileSystem/littlefs/LittlefsFileSystem.cpp#L103