Skip to content

Commit

Permalink
Fixed issue with committing directories to bad-blocks that are stuck
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
geky committed Nov 16, 2017
1 parent 3f31c8c commit 6664723
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 8 deletions.
8 changes: 4 additions & 4 deletions emubd/lfs_emubd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 5 additions & 4 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
11 changes: 11 additions & 0 deletions tests/test_corrupt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 6664723

Please sign in to comment.