summaryrefslogtreecommitdiff
path: root/check
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2018-08-03 13:50:20 +0800
committerDavid Sterba <dsterba@suse.com>2018-10-23 14:48:40 +0200
commitb02b426a784cb327b13a15df752ca285652a45c4 (patch)
treed14eb6a51a9ebc7b8b5caff32c80ba7ef8445104 /check
parent6dbc43b8670d03f7b87f7d3f056c3771b8865e48 (diff)
btrfs-progs: fix infinite loop when bad key order repair fails
An infinite loop can be triggered during fuzz/003: ====== RUN MAYFAIL btrfs check --repair tests/fuzz-tests/images/bko-199833-reloc-recovery-crash.raw.restored [1/7] checking root items Fixed 0 roots. [2/7] checking extents ctree.c:1650: leaf_space_used: Warning: assertion `data_len < 0` failed, value 1 bad key ordering 18 19 ctree.c:1650: leaf_space_used: Warning: assertion `data_len < 0` failed, value 1 bad key ordering 18 19 ctree.c:1650: leaf_space_used: Warning: assertion `data_len < 0` failed, value 1 bad key ordering 18 19 [CAUSE] In try_to_fix_bad_block() it's possible that btrfs_find_all_roots() finds no root referring to that tree block, thus we can't do any repair. However in that case, we still return 0 since the last caller assigning @ret is btrfs_find_all_roots(), and the ulist while loop doesn't get run at all. And since try_to_fix_bad_block() returns 0, check_block() in check/main.c will return -EAGAIN to re-check the tree block. This leads to the infinite loop. [FIX] Change the default return value from 0 to -EIO in try_to_fix_bad_block(), so if there is no tree referring to the bad tree block, it won't cause infinite loop anymore. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'check')
-rw-r--r--check/main.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/check/main.c b/check/main.c
index 3de997e4..40056f50 100644
--- a/check/main.c
+++ b/check/main.c
@@ -4051,6 +4051,11 @@ static int try_to_fix_bad_block(struct btrfs_root *root,
btrfs_init_path(&path);
ULIST_ITER_INIT(&iter);
+ /*
+ * If we found no roots referrening to this tree block, there is no
+ * chance to fix. So our default ret is -EIO.
+ */
+ ret = -EIO;
while ((node = ulist_next(roots, &iter))) {
root_key.objectid = node->val;
root_key.type = BTRFS_ROOT_ITEM_KEY;