Re: [PATCH v2 1/2] btrfs: do not try compression for data reloc inodes
Filipe Manana <[email protected]>
| Newsgroups | org.kernel.vger.linux-btrfs,org.kernel.vger.stable |
|---|---|
| Message-ID | <CAL3q7H70Wmq4WZJ4dbQ0stNFbs3XuTd9pk0qNHTQQ0y0-4u54Q@mail.gmail.com> |
On Mon, Jun 22, 2026 at 11:56 PM Qu Wenruo <[email protected]> wrote: > > [BUG] > There is a syzbot report that the check inside get_new_location() > triggered: > > BTRFS info (device loop0): found 31 extents, stage: move data extents > BTRFS info (device loop0): leaf 8908800 gen 16 total ptrs 28 free space 1676 owner 18446744073709551607 > item 0 key (256 INODE_ITEM 0) itemoff 3835 itemsize 160 > inode generation 5 transid 0 size 0 nbytes 0 > block group 0 mode 40755 links 1 uid 0 gid 0 > rdev 0 sequence 0 flags 0x0 > atime 1669132761.0 > ctime 1669132761.0 > mtime 1669132761.0 > otime 0.0 > item 1 key (256 INODE_REF 256) itemoff 3823 itemsize 12 > index 0 name_len 2 > item 2 key (258 INODE_ITEM 0) itemoff 3663 itemsize 160 > inode generation 1 transid 16 size 733184 nbytes 106496 > block group 0 mode 100600 links 0 uid 0 gid 0 > rdev 0 sequence 24 flags 0x18 > item 3 key (258 EXTENT_DATA 0) itemoff 3595 itemsize 68 > generation 16 type 0 > inline extent data size 47 ram_bytes 4096 compression 1 > [...] > item 27 key (18446744073709551611 ORPHAN_ITEM 258) itemoff 2376 itemsize 0 > BTRFS error (device loop0): unexpected non-zero offset in file extent item for data reloc inode 258 key offset 0 offset 9277520992061368337 > ------------[ cut here ]------------ > btrfs_abort_should_print_stack(__error) > > [CAUSE] > The above dump tree shows the first file extent item is inlined, which > should make no sense for data reloc inodes, as such inodes are just > representing where the data extents are in the relocation destination chunk. > > However the relocation path is just preallocate space for each block, "is just preallocate" is weird, more like "preallocates" > then dirty them, cluster by cluster. > It's possible to have a single block at the beginning of the block > group, and no other block in the same cluster. > > Then relocation will preallocate a file extent for that block, dirty the first block. > Then memory pressure forces the data reloc inode to be written back, before > any other blocks being dirtied/allocated. > > Finally commit 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated > delalloc helper") changed the timing of delalloc, before that commit we This isn't about changing the timing but rather changing the order of the rule set for inline/compression/nocow. Saying timing is confusing. > always try NOCOW first, so that dirtied block will be written back into > the preallocated space. > > But with that commit, we always try inline first, and since compression > is forced, we try compressing the first block, and then inline the > compressed data, resulting in the above inlined file extent in data > reloc tree. > > Then the check in get_new_location() will check the file offset, without > checking if the file extent is inlined or not, resulting the above > failure. > > [FIX] > Do not allow compression for data reloc inodes in the first place. I would add an explanation here about why disallowing compression prevents the inline extent, as this is non-obvious and involves a convoluted path. So adding this new check in btrfs_inode_can_compress() makes run_delalloc_inline() skip the compression `if` statement. Then, when it calls can_cow_file_range_inline() that returns false because the data size is >= sector size, causing run_delalloc_inline() to return 1, signaling to the caller, btrfs_run_delalloc_range(), it cannot inline and must follow the nocow path. Thanks. > > Reported-by: [email protected] > Link: https://lore.kernel.org/linux-btrfs/[email protected]/ > Fixes: 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated delalloc helper") > Cc: [email protected] > Signed-off-by: Qu Wenruo <[email protected]> > --- > fs/btrfs/btrfs_inode.h | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h > index d5d81f9546c3..fff72f6cc1e8 100644 > --- a/fs/btrfs/btrfs_inode.h > +++ b/fs/btrfs/btrfs_inode.h > @@ -476,6 +476,8 @@ static inline bool btrfs_inode_can_compress(const struct btrfs_inode *inode) > if (inode->flags & BTRFS_INODE_NODATACOW || > inode->flags & BTRFS_INODE_NODATASUM) > return false; > + if (btrfs_root_id(inode->root) == BTRFS_DATA_RELOC_TREE_OBJECTID) > + return false; > return true; > } > > -- > 2.54.0 > >