From 63b52c9f2e8305f983c9fc491c3d7e4a0f7bf670 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 30 Apr 2017 12:35:50 -0500 Subject: [PATCH] Added proper handling for removing open files Conveniently we previously added a linked-list of files for things like this. This should handle most of the corner cases where files are open during strange operations. This also brings up the point that we aren't doing anything similar for directories and don't even have a dir linked-list. After thinking about it for a while, I've decided to leave out this handling for dirs. It will likely be very complicated, with little gains as directories are less used in embedded systems. Additionally, dirs are only open for reading, and corruption will probably just cause the dir iteration to terminate. If needed, correct handling of open directories can be added later. --- Makefile | 3 +- lfs.c | 26 +++++- tests/test_parallel.sh | 186 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+), 2 deletions(-) create mode 100755 tests/test_parallel.sh diff --git a/Makefile b/Makefile index 4f8b79a..10afda9 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,8 @@ size: $(OBJ) $(SIZE) -t $^ .SUFFIXES: -test: test_format test_dirs test_files test_seek test_alloc test_paths test_orphan +test: test_format test_dirs test_files test_seek test_parallel \ + test_alloc test_paths test_orphan test_%: tests/test_%.sh ./$< diff --git a/lfs.c b/lfs.c index 5c8baea..da329fe 100644 --- a/lfs.c +++ b/lfs.c @@ -1155,7 +1155,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return err; } - if (file->flags & LFS_F_DIRTY) { + if ((file->flags & LFS_F_DIRTY) && !lfs_pairisnull(file->pair)) { // update dir entry lfs_dir_t cwd; int err = lfs_dir_fetch(lfs, &cwd, file->pair); @@ -1406,6 +1406,18 @@ int lfs_remove(lfs_t *lfs, const char *path) { return err; } + // shift over any files that are affected + for (lfs_file_t *f = lfs->files; f; f = f->next) { + if (lfs_paircmp(f->pair, cwd.pair) == 0) { + if (f->poff == entry.off) { + f->pair[0] = 0xffffffff; + f->pair[1] = 0xffffffff; + } else if (f->poff > entry.off) { + f->poff -= entry.d.len; + } + } + } + // if we were a directory, just run a deorphan step, this should // collect us, although is expensive if (entry.d.type == LFS_TYPE_DIR) { @@ -1498,6 +1510,18 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { return err; } + // shift over any files that are affected + for (lfs_file_t *f = lfs->files; f; f = f->next) { + if (lfs_paircmp(f->pair, oldcwd.pair) == 0) { + if (f->poff == oldentry.off) { + f->pair[0] = 0xffffffff; + f->pair[1] = 0xffffffff; + } else if (f->poff > oldentry.off) { + f->poff -= oldentry.d.len; + } + } + } + // if we were a directory, just run a deorphan step, this should // collect us, although is expensive if (prevexists && preventry.d.type == LFS_TYPE_DIR) { diff --git a/tests/test_parallel.sh b/tests/test_parallel.sh new file mode 100755 index 0000000..71c9c1f --- /dev/null +++ b/tests/test_parallel.sh @@ -0,0 +1,186 @@ +#!/bin/bash +set -eu + +echo "=== Parallel tests ===" +rm -rf blocks +tests/test.py << TEST + lfs_format(&lfs, &cfg) => 0; +TEST + +echo "--- Parallel file test ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_open(&lfs, &file[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_open(&lfs, &file[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_open(&lfs, &file[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0; + + for (int i = 0; i < 10; i++) { + lfs_file_write(&lfs, &file[0], (const void*)"a", 1) => 1; + lfs_file_write(&lfs, &file[1], (const void*)"b", 1) => 1; + lfs_file_write(&lfs, &file[2], (const void*)"c", 1) => 1; + lfs_file_write(&lfs, &file[3], (const void*)"d", 1) => 1; + } + + lfs_file_close(&lfs, &file[0]); + lfs_file_close(&lfs, &file[1]); + lfs_file_close(&lfs, &file[2]); + lfs_file_close(&lfs, &file[3]); + + lfs_dir_open(&lfs, &dir[0], "/") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, ".") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "..") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "a") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "b") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "c") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "d") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 0; + lfs_dir_close(&lfs, &dir[0]) => 0; + + lfs_file_open(&lfs, &file[0], "a", LFS_O_RDONLY) => 0; + lfs_file_open(&lfs, &file[1], "b", LFS_O_RDONLY) => 0; + lfs_file_open(&lfs, &file[2], "c", LFS_O_RDONLY) => 0; + lfs_file_open(&lfs, &file[3], "d", LFS_O_RDONLY) => 0; + + for (int i = 0; i < 10; i++) { + lfs_file_read(&lfs, &file[0], buffer, 1) => 1; + buffer[0] => 'a'; + lfs_file_read(&lfs, &file[1], buffer, 1) => 1; + buffer[0] => 'b'; + lfs_file_read(&lfs, &file[2], buffer, 1) => 1; + buffer[0] => 'c'; + lfs_file_read(&lfs, &file[3], buffer, 1) => 1; + buffer[0] => 'd'; + } + + lfs_file_close(&lfs, &file[0]); + lfs_file_close(&lfs, &file[1]); + lfs_file_close(&lfs, &file[2]); + lfs_file_close(&lfs, &file[3]); + + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Parallel remove file test ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; + + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; + } + + lfs_remove(&lfs, "a") => 0; + lfs_remove(&lfs, "b") => 0; + lfs_remove(&lfs, "c") => 0; + lfs_remove(&lfs, "d") => 0; + + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; + } + + lfs_file_close(&lfs, &file[0]); + + lfs_dir_open(&lfs, &dir[0], "/") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, ".") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "..") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "e") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 0; + lfs_dir_close(&lfs, &dir[0]) => 0; + + lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0; + + for (int i = 0; i < 10; i++) { + lfs_file_read(&lfs, &file[0], buffer, 1) => 1; + buffer[0] => 'e'; + } + + lfs_file_close(&lfs, &file[0]); + + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Remove inconveniently test ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0; + lfs_file_open(&lfs, &file[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_open(&lfs, &file[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; + + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; + lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1; + lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1; + } + + lfs_remove(&lfs, "f") => 0; + + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; + lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1; + lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1; + } + + lfs_file_close(&lfs, &file[0]); + lfs_file_close(&lfs, &file[1]); + lfs_file_close(&lfs, &file[2]); + + lfs_dir_open(&lfs, &dir[0], "/") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, ".") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "..") => 0; + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "e") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "g") => 0; + info.type => LFS_TYPE_REG; + info.size => 10; + lfs_dir_read(&lfs, &dir[0], &info) => 0; + lfs_dir_close(&lfs, &dir[0]) => 0; + + lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0; + lfs_file_open(&lfs, &file[1], "g", LFS_O_RDONLY) => 0; + + for (int i = 0; i < 10; i++) { + lfs_file_read(&lfs, &file[0], buffer, 1) => 1; + buffer[0] => 'e'; + lfs_file_read(&lfs, &file[1], buffer, 1) => 1; + buffer[0] => 'g'; + } + + lfs_file_close(&lfs, &file[0]); + lfs_file_close(&lfs, &file[1]); + + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Results ---" +tests/stats.py