littlefs-project / littlefs

A little fail-safe filesystem designed for microcontrollers
BSD 3-Clause "New" or "Revised" License
4.9k stars 771 forks source link

Fail to mkdir after mount #919

Closed Leonupup closed 5 months ago

Leonupup commented 6 months ago

Hi, I am using littlefs in a stm32 board now. I want to make a new dir but the function lfs_mkdir() doesn't work. After check, I find this function return LFS_ERR_NOSPC but there are enough block. I notice that when using lfs_format() and lfs_mount() the element's value in lookahead_buffer is 0x00 sometime, but when lfs_mkdir() they are always 0xff. No free block will be found when using lfs_alloc() . The picture shows the data in lookahead_buffer and lfs->free before using lfs_mkdir(). I dont know what to do to fix this problem, can you give me some advice? Thanks very much!

Leonupup commented 6 months ago
data

This is the picture. And there is the most important question: the value in lookahead_buffer is really ok? Thank you angin!

geky commented 5 months ago

Hi @Leonupup, thanks for creating an issue. Sorry if the following is a bit rambly, I'm just trying to write what thoughts come to mind reading your issue.

What is your filesystem configuration? block_size? block_count? lookahead_size? These would be useful to know what's going on.

When allocating blocks, littlefs performs a scan to see what blocks are in use. If it finds a block in use, it marks it as 1 in the lookahead buffer. The fact that the lookahead buffer is all 1s (0xffs) suggests that either the filesystem is full or the allocation code has a bug.

Keep in mind that directories require 2 blocks each. It could be that you're actually out of space because of this.

littlefs can also return LFS_ERR_NOSPC if metadata doesn't fit in a metadata log. There are plans to change this to a different error code (LFS_ERR_RANGE), but at the moment this error is a bit overloaded. To test for this case you could increase the block size, but the lookahead buffer being all 1s (0xffs) suggests this isn't the case...

Leonupup commented 5 months ago

Thanks very much! @geky The configuration code of my file system is as follows:

uint8_t read_buffer[1024];
uint8_t prog_buffer[1024];
uint8_t lookahead_buffer[1024];

const struct lfs_config lfs_cfg = {
    // block device operations
    .read  = lfs_flash_read,
    .prog  = lfs_flash_prog,
    .erase = lfs_flash_erase,
    .sync  = lfs_flash_sync,

    // block device configuration
    .read_size = 256,
    .prog_size = 256,
    .block_size = 4096,
    .block_count = 16,
    .cache_size = 4096,
    .lookahead_size = 1024,
    .block_cycles = 100,

    .read_buffer = read_buffer,
    .prog_buffer = prog_buffer,
    .lookahead_buffer = lookahead_buffer,
};
int err;
err = lfs_mount(&lfs, &lfs_cfg);
if(err)
{
    lfs_format(&lfs, &lfs_cfg);
    lfs_mount(&lfs, &lfs_cfg);
}

if(lfs_mkdir(&lfs, "/test"))
{
    while(1)
    {}
}

And this is my test code.

In my opinion, there should be enough blocks for me to create a new dir after lfs_format() and lfs_mount(), but it turns to bad result. I would try to check following your advice.

Anyway there is also another question: Do I need to modify the code about lfs_free() and lfs_malloc() for using static memory? Or just use LFS_NO_MALLOC and work with littlefs dirctly? Maybe I need to find the problem in lfs_free() or lfs_malloc() for the reason that I used to modify this part based on the information on the Internet.

Thanks for your advice, Thanks again!

geky commented 5 months ago

Hi @Leonupup, I think this might be the issue:

uint8_t read_buffer[1024];
uint8_t prog_buffer[1024];
uint8_t lookahead_buffer[1024];
    .cache_size = 4096,

The read_buffer and prog_buffer need to be cache_size. This is a bit confusing since there is also read_size/prog_size, but those control the minimum of what can be read/progged, while cache_size controls the maximum.

I could see a call to read_buffer overflowing into the lookahead_buffer in this case. 0xffs are also common here since this is usually the default state of flash after an erase.


As an aside, the lookahead_buffer doesn't really need to be 1024 bytes. Anything past block_count/8 bytes goes unused. There is currently a restrictive alignment requirement, so it does need to be at least 8 bytes, but this requirement is going away soon (https://github.com/littlefs-project/littlefs/pull/912).


Do I need to modify the code about lfs_free() and lfs_malloc() for using static memory? Or just use LFS_NO_MALLOC and work with littlefs dirctly?

It's up to you. Modifying lfs_free/lfs_malloc to return a single buffer may be an easy solution if you only ever have one file open at a time. Or you can define LFS_NO_MALLOC and provide read_buffer/prog_buffer/lookahead_buffer/file_buffer.

You have most of these already but need one more. Each open file needs its own buffer, which can be provided via lfs_file_opencfg and the buffer field in the lfs_file_config struct:

https://github.com/littlefs-project/littlefs/blob/3513ff1afc1d67adb2e6f492f0b9bc0d798fcb0d/lfs.h#L328-L330

But because this requires changing all lfs_file_open calls to lfs_file_opencfg, it may be easier to change lfs_malloc to return the buffer if you know you will only have one file open at a time. lfs_file_opencfg is more useful for more complex systems built on top of littlefs.

Leonupup commented 5 months ago

Thanks for your detailed reply! @geky

I'm sorry for taking so long to get back to you. Under your guidance, I find that it is really a overflow error happend in function lfs_cache_zero(), and I change read_buffer and prog_buffer from 1024 bytes to 4096 bytes. It works and I successfully make a dir!

My problem is fixed and I also understand how to use static memory! Thanks for your guidance again!