On Tue, Feb 16, 2021 at 8:46 PM Josef Bacik <jo...@toxicpanda.com> wrote: > > The tree checker checks the extent ref hash at read and write time to > make sure we do not corrupt the file system. Generally extent > references go inline, but if we have enough of them we need to make an > item, which looks like > > key.objectid = <bytenr> > key.type = <BTRFS_EXTENT_DATA_REF_KEY|BTRFS_TREE_BLOCK_REF_KEY> > key.offset = hash(tree, owner, offset) > > However if key.offset collide with an unrelated extent reference we'll > simply key.offset++ until we get something that doesn't collide. > Obviously this doesn't match at tree checker time, and thus we error > while writing out the transaction. This is relatively easy to > reproduce, simply do something like the following > > xfs_io -f -c "pwrite 0 1M" file > offset=2 > > for i in {0..10000} > do > xfs_io -c "reflink file 0 ${offset}M 1M" file > offset=$(( offset + 2 )) > done > > xfs_io -c "reflink file 0 17999258914816 1M" file > xfs_io -c "reflink file 0 35998517829632 1M" file > xfs_io -c "reflink file 0 53752752058368 1M" file > > btrfs filesystem sync > > And the sync will error out because we'll abort the transaction. The > magic values above are used because they generate hash collisions with > the first file in the main subvol. > > The fix for this is to remove the hash value check from tree checker, as > we have no idea which offset ours should belong to. > > Reported-by: Tuomas Lähdekorpi <tuomas.lahdeko...@gmail.com> > Signed-off-by: Josef Bacik <jo...@toxicpanda.com>
Reviewed-by: Filipe Manana <fdman...@suse.com> Looks good, thanks. > --- > fs/btrfs/tree-checker.c | 12 ------------ > 1 file changed, 12 deletions(-) > > diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c > index 582061c7b547..2429d668db46 100644 > --- a/fs/btrfs/tree-checker.c > +++ b/fs/btrfs/tree-checker.c > @@ -1453,22 +1453,10 @@ static int check_extent_data_ref(struct extent_buffer > *leaf, > return -EUCLEAN; > } > for (; ptr < end; ptr += sizeof(*dref)) { > - u64 root_objectid; > - u64 owner; > u64 offset; > - u64 hash; > > dref = (struct btrfs_extent_data_ref *)ptr; > - root_objectid = btrfs_extent_data_ref_root(leaf, dref); > - owner = btrfs_extent_data_ref_objectid(leaf, dref); > offset = btrfs_extent_data_ref_offset(leaf, dref); > - hash = hash_extent_data_ref(root_objectid, owner, offset); > - if (unlikely(hash != key->offset)) { > - extent_err(leaf, slot, > - "invalid extent data ref hash, item has 0x%016llx key has 0x%016llx", > - hash, key->offset); > - return -EUCLEAN; > - } > if (unlikely(!IS_ALIGNED(offset, leaf->fs_info->sectorsize))) > { > extent_err(leaf, slot, > "invalid extent data backref offset, have %llu expect aligned to %u", > -- > 2.26.2 > -- Filipe David Manana, “Whether you think you can, or you think you can't — you're right.”