Commit eed31172a351856ad18081f501946e1670b6a1f6

Authored by Liu Bo
Committed by Greg Kroah-Hartman
1 parent 6d2a63f3d1

Btrfs: fix scrub_print_warning to handle skinny metadata extents

commit 6eda71d0c030af0fc2f68aaa676e6d445600855b upstream.

The skinny extents are intepreted incorrectly in scrub_print_warning(),
and end up hitting the BUG() in btrfs_extent_inline_ref_size.

Reported-by: Konstantinos Skarlatos <k.skarlatos@gmail.com>
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: Chris Mason <clm@fb.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 3 changed files with 24 additions and 15 deletions Side-by-side Diff

... ... @@ -1405,9 +1405,10 @@
1405 1405 * returns <0 on error
1406 1406 */
1407 1407 static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
1408   - struct btrfs_extent_item *ei, u32 item_size,
1409   - struct btrfs_extent_inline_ref **out_eiref,
1410   - int *out_type)
  1408 + struct btrfs_key *key,
  1409 + struct btrfs_extent_item *ei, u32 item_size,
  1410 + struct btrfs_extent_inline_ref **out_eiref,
  1411 + int *out_type)
1411 1412 {
1412 1413 unsigned long end;
1413 1414 u64 flags;
... ... @@ -1417,9 +1418,16 @@
1417 1418 /* first call */
1418 1419 flags = btrfs_extent_flags(eb, ei);
1419 1420 if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
1420   - info = (struct btrfs_tree_block_info *)(ei + 1);
1421   - *out_eiref =
1422   - (struct btrfs_extent_inline_ref *)(info + 1);
  1421 + if (key->type == BTRFS_METADATA_ITEM_KEY) {
  1422 + /* a skinny metadata extent */
  1423 + *out_eiref =
  1424 + (struct btrfs_extent_inline_ref *)(ei + 1);
  1425 + } else {
  1426 + WARN_ON(key->type != BTRFS_EXTENT_ITEM_KEY);
  1427 + info = (struct btrfs_tree_block_info *)(ei + 1);
  1428 + *out_eiref =
  1429 + (struct btrfs_extent_inline_ref *)(info + 1);
  1430 + }
1423 1431 } else {
1424 1432 *out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1);
1425 1433 }
... ... @@ -1429,7 +1437,7 @@
1429 1437 }
1430 1438  
1431 1439 end = (unsigned long)ei + item_size;
1432   - *out_eiref = (struct btrfs_extent_inline_ref *)*ptr;
  1440 + *out_eiref = (struct btrfs_extent_inline_ref *)(*ptr);
1433 1441 *out_type = btrfs_extent_inline_ref_type(eb, *out_eiref);
1434 1442  
1435 1443 *ptr += btrfs_extent_inline_ref_size(*out_type);
... ... @@ -1448,8 +1456,8 @@
1448 1456 * <0 on error.
1449 1457 */
1450 1458 int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
1451   - struct btrfs_extent_item *ei, u32 item_size,
1452   - u64 *out_root, u8 *out_level)
  1459 + struct btrfs_key *key, struct btrfs_extent_item *ei,
  1460 + u32 item_size, u64 *out_root, u8 *out_level)
1453 1461 {
1454 1462 int ret;
1455 1463 int type;
... ... @@ -1460,8 +1468,8 @@
1460 1468 return 1;
1461 1469  
1462 1470 while (1) {
1463   - ret = __get_extent_inline_ref(ptr, eb, ei, item_size,
1464   - &eiref, &type);
  1471 + ret = __get_extent_inline_ref(ptr, eb, key, ei, item_size,
  1472 + &eiref, &type);
1465 1473 if (ret < 0)
1466 1474 return ret;
1467 1475  
... ... @@ -40,8 +40,8 @@
40 40 u64 *flags);
41 41  
42 42 int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
43   - struct btrfs_extent_item *ei, u32 item_size,
44   - u64 *out_root, u8 *out_level);
  43 + struct btrfs_key *key, struct btrfs_extent_item *ei,
  44 + u32 item_size, u64 *out_root, u8 *out_level);
45 45  
46 46 int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
47 47 u64 extent_item_objectid,
... ... @@ -588,8 +588,9 @@
588 588  
589 589 if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
590 590 do {
591   - ret = tree_backref_for_extent(&ptr, eb, ei, item_size,
592   - &ref_root, &ref_level);
  591 + ret = tree_backref_for_extent(&ptr, eb, &found_key, ei,
  592 + item_size, &ref_root,
  593 + &ref_level);
593 594 printk_in_rcu(KERN_WARNING
594 595 "BTRFS: %s at logical %llu on dev %s, "
595 596 "sector %llu: metadata %s (level %d) in tree "