From 0f4e334388e0e05554a78d14d0a5ef73f02209b2 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 16 Nov 2017 18:16:32 -0600 Subject: [PATCH] Squashed 'littlefs/' changes from 3f31c8c..78c79ec 78c79ec Added QUIET flag to tests so CI is readable f9f4f5c Fixed standard name mismatch LFS_ERR_EXISTS -> LFS_ERR_EXIST 843e3c6 Added sticky-bit for preventing file syncs after write errors 2612e1b Modified lfs_ctz_extend to be a little bit safer 6664723 Fixed issue with committing directories to bad-blocks that are stuck git-subtree-dir: littlefs git-subtree-split: 78c79ecb9e6b8dd0e7cfd7ac86934e43fb026924 --- .travis.yml | 12 +++++------ Makefile | 4 ++++ emubd/lfs_emubd.c | 8 +++---- lfs.c | 50 +++++++++++++++++++++++++++---------------- lfs.h | 3 ++- tests/test_alloc.sh | 28 ++++++++++++++++-------- tests/test_corrupt.sh | 11 ++++++++++ tests/test_dirs.sh | 2 +- 8 files changed, 78 insertions(+), 40 deletions(-) diff --git a/.travis.yml b/.travis.yml index 552f7cc9a7..d673c159ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,13 @@ script: -include stdio.h -Werror' make all size # run tests - - make test + - make test QUIET=1 # run tests with a few different configurations - - CFLAGS="-DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1" make test - - CFLAGS="-DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512" make test - - CFLAGS="-DLFS_BLOCK_COUNT=1023" make test - - CFLAGS="-DLFS_LOOKAHEAD=2048" make test + - CFLAGS="-DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1" make test QUIET=1 + - CFLAGS="-DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512" make test QUIET=1 + - CFLAGS="-DLFS_BLOCK_COUNT=1023" make test QUIET=1 + - CFLAGS="-DLFS_LOOKAHEAD=2048" make test QUIET=1 # self-host with littlefs-fuse for fuzz test - make -C littlefs-fuse @@ -28,7 +28,7 @@ script: - cp -r $(git ls-tree --name-only HEAD) mount/littlefs - cd mount/littlefs - ls - - make -B test_dirs + - make -B test_dirs QUIET=1 before_install: - fusermount -V diff --git a/Makefile b/Makefile index bd5bd905a1..2ef12876ee 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,11 @@ size: $(OBJ) test: test_format test_dirs test_files test_seek test_parallel \ test_alloc test_paths test_orphan test_move test_corrupt test_%: tests/test_%.sh +ifdef QUIET + ./$< | sed '/^[^-=]/d' +else ./$< +endif -include $(DEP) diff --git a/emubd/lfs_emubd.c b/emubd/lfs_emubd.c index ca2b6b928e..b87d6deba0 100644 --- a/emubd/lfs_emubd.c +++ b/emubd/lfs_emubd.c @@ -138,8 +138,8 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, snprintf(emu->child, LFS_NAME_MAX, "%x", block); FILE *f = fopen(emu->path, "r+b"); - if (!f && errno != ENOENT) { - return -errno; + if (!f) { + return (errno == EACCES) ? 0 : -errno; } // Check that file was erased @@ -189,14 +189,14 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { return -errno; } - if (!err && S_ISREG(st.st_mode)) { + if (!err && S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode)) { int err = unlink(emu->path); if (err) { return -errno; } } - if (err || S_ISREG(st.st_mode)) { + if (errno == ENOENT || (S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode))) { FILE *f = fopen(emu->path, "w"); if (!f) { return -errno; diff --git a/lfs.c b/lfs.c index b043bd907d..cddc6fa7ff 100644 --- a/lfs.c +++ b/lfs.c @@ -531,18 +531,19 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, } // successful commit, check checksum to make sure - crc = 0xffffffff; + uint32_t ncrc = 0xffffffff; err = lfs_bd_crc(lfs, dir->pair[0], 0, - 0x7fffffff & dir->d.size, &crc); + (0x7fffffff & dir->d.size)-4, &ncrc); if (err) { return err; } - if (crc == 0) { - break; + if (ncrc != crc) { + goto relocate; } } + break; relocate: //commit was corrupted LFS_DEBUG("Bad block at %d", dir->pair[0]); @@ -818,7 +819,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { lfs_entry_t entry; err = lfs_dir_find(lfs, &cwd, &entry, &path); if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) { - return err ? err : LFS_ERR_EXISTS; + return err ? err : LFS_ERR_EXIST; } // build up new directory @@ -1053,17 +1054,18 @@ static int lfs_ctz_find(lfs_t *lfs, static int lfs_ctz_extend(lfs_t *lfs, lfs_cache_t *rcache, lfs_cache_t *pcache, lfs_block_t head, lfs_size_t size, - lfs_off_t *block, lfs_block_t *off) { + lfs_block_t *block, lfs_off_t *off) { while (true) { - if (true) { - // go ahead and grab a block - int err = lfs_alloc(lfs, block); - if (err) { - return err; - } - assert(*block >= 2 && *block <= lfs->cfg->block_count); + // go ahead and grab a block + lfs_block_t nblock; + int err = lfs_alloc(lfs, &nblock); + if (err) { + return err; + } + assert(nblock >= 2 && nblock <= lfs->cfg->block_count); - err = lfs_bd_erase(lfs, *block); + if (true) { + err = lfs_bd_erase(lfs, nblock); if (err) { if (err == LFS_ERR_CORRUPT) { goto relocate; @@ -1072,6 +1074,7 @@ static int lfs_ctz_extend(lfs_t *lfs, } if (size == 0) { + *block = nblock; *off = 0; return 0; } @@ -1091,7 +1094,7 @@ static int lfs_ctz_extend(lfs_t *lfs, } err = lfs_cache_prog(lfs, pcache, rcache, - *block, i, &data, 1); + nblock, i, &data, 1); if (err) { if (err == LFS_ERR_CORRUPT) { goto relocate; @@ -1100,6 +1103,7 @@ static int lfs_ctz_extend(lfs_t *lfs, } } + *block = nblock; *off = size; return 0; } @@ -1110,7 +1114,7 @@ static int lfs_ctz_extend(lfs_t *lfs, for (lfs_off_t i = 0; i < skips; i++) { int err = lfs_cache_prog(lfs, pcache, rcache, - *block, 4*i, &head, 4); + nblock, 4*i, &head, 4); if (err) { if (err == LFS_ERR_CORRUPT) { goto relocate; @@ -1129,12 +1133,13 @@ static int lfs_ctz_extend(lfs_t *lfs, assert(head >= 2 && head <= lfs->cfg->block_count); } + *block = nblock; *off = 4*skips; return 0; } relocate: - LFS_DEBUG("Bad block at %d", *block); + LFS_DEBUG("Bad block at %d", nblock); // just clear cache and try a new block pcache->block = 0xffffffff; @@ -1214,7 +1219,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, } else if (entry.d.type == LFS_TYPE_DIR) { return LFS_ERR_ISDIR; } else if (flags & LFS_O_EXCL) { - return LFS_ERR_EXISTS; + return LFS_ERR_EXIST; } // setup file struct @@ -1398,7 +1403,9 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return err; } - if ((file->flags & LFS_F_DIRTY) && !lfs_pairisnull(file->pair)) { + if ((file->flags & LFS_F_DIRTY) && + !(file->flags & LFS_F_ERRED) && + !lfs_pairisnull(file->pair)) { // update dir entry lfs_dir_t cwd; int err = lfs_dir_fetch(lfs, &cwd, file->pair); @@ -1532,6 +1539,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->head, file->size, file->pos-1, &file->block, &file->off); if (err) { + file->flags |= LFS_F_ERRED; return err; } @@ -1545,6 +1553,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->block, file->pos, &file->block, &file->off); if (err) { + file->flags |= LFS_F_ERRED; return err; } @@ -1560,6 +1569,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if (err == LFS_ERR_CORRUPT) { goto relocate; } + file->flags |= LFS_F_ERRED; return err; } @@ -1567,6 +1577,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, relocate: err = lfs_file_relocate(lfs, file); if (err) { + file->flags |= LFS_F_ERRED; return err; } } @@ -1579,6 +1590,7 @@ relocate: lfs_alloc_ack(lfs); } + file->flags &= ~LFS_F_ERRED; return size; } diff --git a/lfs.h b/lfs.h index e4aab0e4b2..7757f8b9b4 100644 --- a/lfs.h +++ b/lfs.h @@ -45,7 +45,7 @@ enum lfs_error { LFS_ERR_IO = -5, // Error during device operation LFS_ERR_CORRUPT = -52, // Corrupted LFS_ERR_NOENT = -2, // No directory entry - LFS_ERR_EXISTS = -17, // Entry already exists + LFS_ERR_EXIST = -17, // Entry already exists LFS_ERR_NOTDIR = -20, // Entry is not a dir LFS_ERR_ISDIR = -21, // Entry is a dir LFS_ERR_INVAL = -22, // Invalid parameter @@ -75,6 +75,7 @@ enum lfs_open_flags { LFS_F_DIRTY = 0x10000, // File does not match storage LFS_F_WRITING = 0x20000, // File has been written since last flush LFS_F_READING = 0x40000, // File has been read since last flush + LFS_F_ERRED = 0x80000, // An error occured during write }; // File seek flags diff --git a/tests/test_alloc.sh b/tests/test_alloc.sh index 630be2a1bc..aaae6551e1 100755 --- a/tests/test_alloc.sh +++ b/tests/test_alloc.sh @@ -121,6 +121,7 @@ tests/test.py << TEST size = strlen("exhaustion"); memcpy(buffer, "exhaustion", size); lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs_file_sync(&lfs, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); @@ -142,6 +143,7 @@ tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); size = strlen("exhaustion"); + lfs_file_size(&lfs, &file[0]) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "exhaustion", size) => 0; lfs_file_close(&lfs, &file[0]) => 0; @@ -166,6 +168,7 @@ tests/test.py << TEST size = strlen("exhaustion"); memcpy(buffer, "exhaustion", size); lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs_file_sync(&lfs, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); @@ -187,6 +190,7 @@ tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); size = strlen("exhaustion"); + lfs_file_size(&lfs, &file[0]) => size; lfs_file_read(&lfs, &file[0], buffer, size) => size; memcmp(buffer, "exhaustion", size) => 0; lfs_file_close(&lfs, &file[0]) => 0; @@ -196,14 +200,14 @@ TEST echo "--- Dir exhaustion test ---" tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "exhaustion", &info) => 0; - lfs_size_t fullsize = info.size; lfs_remove(&lfs, "exhaustion") => 0; lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; i < fullsize - 2*512; i += size) { + for (lfs_size_t i = 0; + i < (cfg.block_count-6)*(cfg.block_size-8); + i += size) { lfs_file_write(&lfs, &file[0], buffer, size) => size; } lfs_file_close(&lfs, &file[0]) => 0; @@ -214,7 +218,11 @@ tests/test.py << TEST lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_APPEND); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - lfs_file_write(&lfs, &file[0], buffer, size) => size; + for (lfs_size_t i = 0; + i < (cfg.block_size-8); + i += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } lfs_file_close(&lfs, &file[0]) => 0; lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; @@ -224,14 +232,14 @@ TEST echo "--- Chained dir exhaustion test ---" tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "exhaustion", &info) => 0; - lfs_size_t fullsize = info.size; - lfs_remove(&lfs, "exhaustion") => 0; + lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; i < fullsize - 19*512; i += size) { + for (lfs_size_t i = 0; + i < (cfg.block_count-24)*(cfg.block_size-8); + i += size) { lfs_file_write(&lfs, &file[0], buffer, size) => size; } lfs_file_close(&lfs, &file[0]) => 0; @@ -247,7 +255,9 @@ tests/test.py << TEST lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; i < fullsize - 20*512; i += size) { + for (lfs_size_t i = 0; + i < (cfg.block_count-26)*(cfg.block_size-8); + i += size) { lfs_file_write(&lfs, &file[0], buffer, size) => size; } lfs_file_close(&lfs, &file[0]) => 0; diff --git a/tests/test_corrupt.sh b/tests/test_corrupt.sh index d79a8c8964..44f1caee32 100755 --- a/tests/test_corrupt.sh +++ b/tests/test_corrupt.sh @@ -82,6 +82,17 @@ do lfs_chktree done +echo "--- Block persistance ---" +for i in {0..33} +do + rm -rf blocks + mkdir blocks + lfs_mktree + chmod a-w blocks/$(printf '%x' $i) + lfs_mktree + lfs_chktree +done + echo "--- Big region corruption ---" rm -rf blocks mkdir blocks diff --git a/tests/test_dirs.sh b/tests/test_dirs.sh index 5a7ea58b7e..8b69e7e8ce 100755 --- a/tests/test_dirs.sh +++ b/tests/test_dirs.sh @@ -56,7 +56,7 @@ TEST echo "--- Directory failures ---" tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "potato") => LFS_ERR_EXISTS; + lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERR_NOTDIR; lfs_file_open(&lfs, &file[0], "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT;