diff options
author | Eric Biggers <ebiggers@google.com> | 2020-05-29 13:47:38 -0700 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2020-05-30 08:18:51 -0700 |
commit | e65d9c7adf52aae7d7e2eb132961c8373072c8c9 (patch) | |
tree | c80dedc80bd7282fe154798207014ffe6411d69b | |
parent | b23b2b97a662168ee364bc67965de08ffc1455bc (diff) | |
download | f2fs-tools-e65d9c7adf52aae7d7e2eb132961c8373072c8c9.tar.gz |
fsck.f2fs: fix dirent position check for encrypted+casefolded dentries
fsck.f2fs reports corruption if the filesystem contains any encrypted +
casefolded directories with any substantial number of dentries:
[ASSERT] (f2fs_check_dirent_position:1374) --> Wrong position of dirent pino:8, name:۟�[I�^*�(�5~�}�D��#]7�8�ˎ�, level:1, dir_level:0, pgofs:4, correct range:[2, 3]
The problem is that f2fs_check_dirent_position() computes the wrong hash
for encrypted+casefolded dentries. It's not actually possible for it to
compute the correct hash, because it would need the encryption key.
However, the on-disk dentry already contains the hash code, and its
correctness was already verified by f2fs_check_hash_code() if possible.
So, make f2fs_check_dirent_position() use the hash code from disk rather
than recompute it.
Also fix it to print the filename in human-readable form.
This bug was causing 'kvm-xfstests -c f2fs/encrypt -g casefold'
to fail with the test_dummy_encryption_v2 and encryption+casefolding
kernel patches applied.
Fixes: 7f3767ee8dc5 ("f2fs-tools: Casefolded Encryption support")
Cc: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | fsck/fsck.c | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c index 0389146..c249dfa 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1348,11 +1348,10 @@ static int __get_current_level(int dir_level, u32 pgofs) return i; } -static int f2fs_check_dirent_position(int encoding, int casefolded, - u8 *name, u16 name_len, u32 pgofs, - u8 dir_level, u32 pino) +static int f2fs_check_dirent_position(const struct f2fs_dir_entry *dentry, + const char *printable_name, + u32 pgofs, u8 dir_level, u32 pino) { - f2fs_hash_t namehash = f2fs_dentry_hash(encoding, casefolded, name, name_len); unsigned int nbucket, nblock; unsigned int bidx, end_block; int level; @@ -1363,7 +1362,7 @@ static int f2fs_check_dirent_position(int encoding, int casefolded, nblock = bucket_blocks(level); bidx = dir_block_index(level, dir_level, - le32_to_cpu(namehash) % nbucket); + le32_to_cpu(dentry->hash_code) % nbucket); end_block = bidx + nblock; if (pgofs >= bidx && pgofs < end_block) @@ -1371,7 +1370,8 @@ static int f2fs_check_dirent_position(int encoding, int casefolded, ASSERT_MSG("Wrong position of dirent pino:%u, name:%s, level:%d, " "dir_level:%d, pgofs:%u, correct range:[%u, %u]\n", - pino, name, level, dir_level, pgofs, bidx, end_block - 1); + pino, printable_name, level, dir_level, pgofs, bidx, + end_block - 1); return 1; } @@ -1552,10 +1552,12 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry + i, name, name_len, enc_name)) fixed = 1; + pretty_print_filename(name, name_len, en, enc_name); + if (max == NR_DENTRY_IN_BLOCK) { - ret = f2fs_check_dirent_position(get_encoding(sbi), casefolded, - name, name_len, child->pgofs, - child->dir_level, child->p_ino); + ret = f2fs_check_dirent_position(dentry + i, en, + child->pgofs, child->dir_level, + child->p_ino); if (ret) { if (c.fix_on) { FIX_MSG("Clear bad dentry 0x%x", i); @@ -1568,7 +1570,6 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, } } - pretty_print_filename(name, name_len, en, enc_name); DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n", fsck->dentry_depth, i, en, name_len, le32_to_cpu(dentry[i].ino), |