From 6664723e18034b3685d7d56374ec53b66cfcf47d Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 16 Nov 2017 14:53:45 -0600 Subject: [PATCH] Fixed issue with committing directories to bad-blocks that are stuck This is only an issue in the weird case that are worn down block is left in the odd state of not being able to change the data that resides on the block. That being said, this does pop up often when simulating wear on block devices. Currently, directory commits checked if the write succeeded by crcing the block to avoid the additional RAM cost for another buffer. However, before this commit, directory commits just checked if the block crc was valid, rather than comparing to the expected crc. This would usually work, unless the block was stuck in a state with valid crc. The fix is to simply compare with the expected crc to find errors. --- emubd/lfs_emubd.c | 8 ++++---- lfs.c | 9 +++++---- tests/test_corrupt.sh | 11 +++++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/emubd/lfs_emubd.c b/emubd/lfs_emubd.c index ca2b6b928e8..b87d6deba03 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 b043bd907df..d757ffbde44 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]); diff --git a/tests/test_corrupt.sh b/tests/test_corrupt.sh index d79a8c8964d..44f1caee320 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