Skip to content
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

Corruption reported upon concurrent directory modification #1061

Open
tpwrules opened this issue Dec 31, 2024 · 0 comments
Open

Corruption reported upon concurrent directory modification #1061

tpwrules opened this issue Dec 31, 2024 · 0 comments

Comments

@tpwrules
Copy link

I have an embedded application where one part of the application might be iterating a directory while another deletes files from it. The outcome of the iteration isn't meaningful to the application in this case, but sometimes lfs_dir_read returns LFS_ERR_CORRUPT. I would expect it to return some subset of the files in the directory (possibly none at all) but complete without any errors.

POSIX says that a directory iteration is unspecified to report an entry if it's added or removed while the iteration is in progress, but otherwise I believe it's expected to. I'm not sure LittleFS needs to go that far and guarantee entries that aren't touched will be returned (it would be nice if it did), but it at least should not claim corruption.

Is there any actual corruption occurring? Can file operations safely be continued as long as the directory is closed after the error is reported? Can LittleFS be easily fixed to not claim corruption?

To put it another way, I would not expect the below tests to fail, but they do on v2.10.1 at least. Iteration shouldn't give an error if a file is removed before reads start, nor if multiple files are removed between reads.

[cases.test_dirs_read_remove_multi]
defines.K = [0, 5]
if = 'N < BLOCK_COUNT/2'
code = '''
    lfs_t lfs;
    lfs_format(&lfs, cfg) => 0;
    lfs_mount(&lfs, cfg) => 0;
    lfs_mkdir(&lfs, "prickly-pear") => 0;
    for (int i = 0; i < 10; i++) {
        char path[1024];
        sprintf(path, "prickly-pear/cactus%03d", i);
        lfs_file_t file;
        lfs_file_open(&lfs, &file, path,
                LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
        lfs_file_close(&lfs, &file) => 0;
    }

    lfs_dir_t dir;
    struct lfs_info info;
    char path[1024];

    lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
    lfs_dir_read(&lfs, &dir, &info) => 1;
    assert(info.type == LFS_TYPE_DIR);
    assert(strcmp(info.name, ".") == 0);
    lfs_dir_read(&lfs, &dir, &info) => 1;
    assert(info.type == LFS_TYPE_DIR);
    assert(strcmp(info.name, "..") == 0);

    lfs_dir_read(&lfs, &dir, &info) => 1;
    sprintf(path, "prickly-pear/cactus%03d", (int)F);
    lfs_remove(&lfs, path) => 0;
    sprintf(path, "prickly-pear/cactus%03d", (int)F+1);
    lfs_remove(&lfs, path) => 0;
    assert(lfs_dir_read(&lfs, &dir, &info) >= 0);

    lfs_dir_close(&lfs, &dir) => 0;
    lfs_unmount(&lfs) => 0;
'''

[cases.test_dirs_remove_read]
defines.F = [0, 5]
if = 'N < BLOCK_COUNT/2'
code = '''
    lfs_t lfs;
    lfs_format(&lfs, cfg) => 0;
    lfs_mount(&lfs, cfg) => 0;
    lfs_mkdir(&lfs, "prickly-pear") => 0;
    for (int i = 0; i < 10; i++) {
        char path[1024];
        sprintf(path, "prickly-pear/cactus%03d", i);
        lfs_file_t file;
        lfs_file_open(&lfs, &file, path,
                LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
        lfs_file_close(&lfs, &file) => 0;
    }

    lfs_dir_t dir;
    struct lfs_info info;
    char path[1024];

    lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
    lfs_dir_read(&lfs, &dir, &info) => 1;
    assert(info.type == LFS_TYPE_DIR);
    assert(strcmp(info.name, ".") == 0);
    lfs_dir_read(&lfs, &dir, &info) => 1;
    assert(info.type == LFS_TYPE_DIR);
    assert(strcmp(info.name, "..") == 0);

    sprintf(path, "prickly-pear/cactus%03d", (int)F);
    lfs_remove(&lfs, path) => 0;
    assert(lfs_dir_read(&lfs, &dir, &info) >= 0);

    lfs_dir_close(&lfs, &dir) => 0;
    lfs_unmount(&lfs) => 0;
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant