The following test failed becasuse the level of child node is not correct. In repair mode, when update parent's ptr in btrfs_search_slot->btrfs_cow_block->__btrfs_cow_block, it use path[level+1] to get the parent, and not judge whether path[level+1] is NULL.
$sudo TEST=003\* make test-fuzz failed (ignored, ret=139): /home/adam/btrfs/btrfs-progs/btrfs check --init-csum-tree /home/adam/btrfs/btrfs-progs/tests/fuzz-tests/images/bko-161821.raw.restored mayfail: returned code 139 (SEGFAULT), not ignored Signed-off-by: Gu Jinxiang <g...@cn.fujitsu.com> --- cmds-check.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cmds-check.c b/cmds-check.c index 71b15de4..ac0375e5 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -2085,6 +2085,7 @@ static void reada_walk_down(struct btrfs_root *root, * in parent. * 2. block in parent node should match the child node/leaf. * 3. generation of parent node and child's header should be consistent. + * 4. level of parent node should not smaller than the child node/leaf. * * Or the child node/leaf pointed by the key in parent is not valid. * @@ -2125,6 +2126,17 @@ static int check_child_node(struct extent_buffer *parent, int slot, btrfs_header_generation(child), btrfs_node_ptr_generation(parent, slot)); } + /* If level of child is not correct, it will lead to + * Segmentation fault when repair parent. + * Because when update parent's ptr in + * btrfs_search_slot->btrfs_cow_block->__btrfs_cow_block, + * it use path[level+1] to get the parent + */ + if (btrfs_header_level(parent) <= btrfs_header_level(child)) { + ret = -EFAULT; + fprintf(stderr, "Wrong level of child node/leaf, wanted: %d, have: %d\n", + btrfs_header_level(parent)-1, btrfs_header_level(child)); + } return ret; } @@ -4067,6 +4079,12 @@ static int check_fs_root(struct btrfs_root *root, wret = walk_down_tree(root, &path, wc, &level, &nrefs); if (wret < 0) ret = wret; + /* When return value is -EFAULT, it indicate that level + * in path is incorrect. And it will lead to Segmentation fault + * in repair mod. + */ + if (wret == -EFAULT && repair) + goto out; if (wret != 0) break; @@ -4123,6 +4141,7 @@ skip_walking: if (!ret) ret = err; +out: free_corrupt_blocks_tree(&corrupt_blocks); root->fs_info->corrupt_blocks = NULL; free_orphan_data_extents(&root->orphan_data_extents); -- 2.14.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html