Skip to content

Commit dfb9268

Browse files
adam900710kdave
authored andcommitted
btrfs: tree-checker: reject inline extent items with 0 ref count
[BUG] There is a bug report in the mailing list where btrfs_run_delayed_refs() failed to drop the ref count for logical 25870311358464 num_bytes 2113536. The involved leaf dump looks like this: item 166 key (25870311358464 168 2113536) itemoff 10091 itemsize 50 extent refs 1 gen 84178 flags 1 ref#0: shared data backref parent 32399126528000 count 0 <<< ref#1: shared data backref parent 31808973717504 count 1 Notice the count number is 0. [CAUSE] There is no concrete evidence yet, but considering 0 -> 1 is also a single bit flipped, it's possible that hardware memory bitflip is involved, causing the on-disk extent tree to be corrupted. [FIX] To prevent us reading such corrupted extent item, or writing such damaged extent item back to disk, enhance the handling of BTRFS_EXTENT_DATA_REF_KEY and BTRFS_SHARED_DATA_REF_KEY keys for both inlined and key items, to detect such 0 ref count and reject them. CC: [email protected] # 5.4+ Link: https://lore.kernel.org/linux-btrfs/[email protected]/ Reported-by: Frankie Fisher <[email protected]> Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent be691b5 commit dfb9268

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

fs/btrfs/tree-checker.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,11 @@ static int check_extent_item(struct extent_buffer *leaf,
15271527
dref_offset, fs_info->sectorsize);
15281528
return -EUCLEAN;
15291529
}
1530+
if (unlikely(btrfs_extent_data_ref_count(leaf, dref) == 0)) {
1531+
extent_err(leaf, slot,
1532+
"invalid data ref count, should have non-zero value");
1533+
return -EUCLEAN;
1534+
}
15301535
inline_refs += btrfs_extent_data_ref_count(leaf, dref);
15311536
break;
15321537
/* Contains parent bytenr and ref count */
@@ -1539,6 +1544,11 @@ static int check_extent_item(struct extent_buffer *leaf,
15391544
inline_offset, fs_info->sectorsize);
15401545
return -EUCLEAN;
15411546
}
1547+
if (unlikely(btrfs_shared_data_ref_count(leaf, sref) == 0)) {
1548+
extent_err(leaf, slot,
1549+
"invalid shared data ref count, should have non-zero value");
1550+
return -EUCLEAN;
1551+
}
15421552
inline_refs += btrfs_shared_data_ref_count(leaf, sref);
15431553
break;
15441554
case BTRFS_EXTENT_OWNER_REF_KEY:
@@ -1611,8 +1621,18 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf,
16111621
{
16121622
u32 expect_item_size = 0;
16131623

1614-
if (key->type == BTRFS_SHARED_DATA_REF_KEY)
1624+
if (key->type == BTRFS_SHARED_DATA_REF_KEY) {
1625+
struct btrfs_shared_data_ref *sref;
1626+
1627+
sref = btrfs_item_ptr(leaf, slot, struct btrfs_shared_data_ref);
1628+
if (unlikely(btrfs_shared_data_ref_count(leaf, sref) == 0)) {
1629+
extent_err(leaf, slot,
1630+
"invalid shared data backref count, should have non-zero value");
1631+
return -EUCLEAN;
1632+
}
1633+
16151634
expect_item_size = sizeof(struct btrfs_shared_data_ref);
1635+
}
16161636

16171637
if (unlikely(btrfs_item_size(leaf, slot) != expect_item_size)) {
16181638
generic_err(leaf, slot,
@@ -1689,6 +1709,11 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
16891709
offset, leaf->fs_info->sectorsize);
16901710
return -EUCLEAN;
16911711
}
1712+
if (unlikely(btrfs_extent_data_ref_count(leaf, dref) == 0)) {
1713+
extent_err(leaf, slot,
1714+
"invalid extent data backref count, should have non-zero value");
1715+
return -EUCLEAN;
1716+
}
16921717
}
16931718
return 0;
16941719
}

0 commit comments

Comments
 (0)