711a0b48683b71d61caffbd67a90ec8db5412675 is incomplete and missed some cases, where 'nritems' is outside its valid range, e.g. - insert_ptr(): inserting into an already full node - copy_for_split(): splitting more items than contained - btrfs_del_ptr(): deleting one item from an already empty node (*) - btrfs_del_items(): deleting more items than contained.
Use BUG_ON() checks to get more useful error messages in case those cases happen. (Here is the debug data from my corrupted file system triggering *:) > (gdb) bt > #3 btrfs_del_ptr (root=root@entry=0x6fcfa0, path=path@entry=0x7fffffffd7d0, > level=level@entry=0, slot=<optimized out>) at ctree.c:2607 > #4 0x00000000004516a1 in repair_btree (corrupt_blocks=0x7fffffffd970, > root=0x6fcfa0) at cmds-check.c:3847 > #5 check_fs_root (root=root@entry=0x6fcfa0, > root_cache=root_cache@entry=0x7fffffffde60, wc=wc@entry=0x7fffffffdbb0) at > cmds-check.c:4009 > #6 0x000000000045da04 in check_fs_roots (root_cache=0x7fffffffde60, > root=0x6e2770) at cmds-check.c:4115 > #7 cmd_check (argc=<optimized out>, argv=<optimized out>) at > cmds-check.c:13079 > #8 0x000000000040aae9 in main (argc=4, argv=0x7fffffffdfa8) at btrfs.c:302 > (gdb) frame 4 > #4 0x00000000004516a1 in repair_btree (corrupt_blocks=0x7fffffffd970, > root=0x6fcfa0) at cmds-check.c:3847 > 3847 ret = btrfs_del_ptr(root, &path, level, > path.slots[level]); > (gdb) info locals > corrupt = 0x52b2dd0 > key = {objectid = 78229979136, type = 168 '\250', offset = 16384} > ret = <optimized out> > trans = 0x8f0ac0 > path = {nodes = {0xd8ac7d0, 0xd8ccc50, 0x6bf010, 0x0, 0x0, 0x0, 0x0, 0x0}, > slots = {0, 417, 232, 0, 0, 0, 0, 0}, reada = 0 '\000', lowest_level = 0 > '\000', search_for_split = 0 '\000', skip_check_block = 0 '\000'} > cache = 0x52b2dd0 > level = 0 Signed-off-by: Philipp Hahn <h...@univention.de> --- ctree.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ctree.c b/ctree.c index 201f671..c5af7f6 100644 --- a/ctree.c +++ b/ctree.c @@ -1485,8 +1485,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root nritems = btrfs_header_nritems(lower); if (slot > nritems) BUG(); - if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root)) - BUG(); + BUG_ON(nritems >= BTRFS_NODEPTRS_PER_BLOCK(root)); if (slot < nritems) { /* shift the items */ memmove_extent_buffer(lower, @@ -1967,7 +1966,8 @@ static noinline int copy_for_split(struct btrfs_trans_handle *trans, int wret; struct btrfs_disk_key disk_key; - nritems = nritems - mid; + BUG_ON(mid > nritems); + nritems -= mid; btrfs_set_header_nritems(right, nritems); data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l); @@ -2604,6 +2604,7 @@ int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path, int ret = 0; nritems = btrfs_header_nritems(parent); + BUG_ON(nritems == 0); if (slot < nritems -1) { /* shift the items */ memmove_extent_buffer(parent, @@ -2678,7 +2679,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, dsize += btrfs_item_size_nr(leaf, slot + i); nritems = btrfs_header_nritems(leaf); - + BUG_ON(nritems < nr); if (slot + nr < nritems) { int data_end = leaf_data_end(root, leaf); -- 2.11.0 -- 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