You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
btrfs: fix double accounting of ordered extents during errors
[BUG]
Btrfs will fail generic/750 randomly if its sector size is smaller than
page size.
One of the warning looks like this:
------------[ cut here ]------------
WARNING: CPU: 1 PID: 90263 at fs/btrfs/ordered-data.c:360 can_finish_ordered_extent+0x33c/0x390 [btrfs]
CPU: 1 UID: 0 PID: 90263 Comm: kworker/u18:1 Tainted: G OE 6.12.0-rc3-custom+ torvalds#79
Workqueue: events_unbound btrfs_async_reclaim_metadata_space [btrfs]
pc : can_finish_ordered_extent+0x33c/0x390 [btrfs]
lr : can_finish_ordered_extent+0xdc/0x390 [btrfs]
Call trace:
can_finish_ordered_extent+0x33c/0x390 [btrfs]
btrfs_mark_ordered_io_finished+0x130/0x2b8 [btrfs]
extent_writepage+0xfc/0x338 [btrfs]
extent_write_cache_pages+0x1d4/0x4b8 [btrfs]
btrfs_writepages+0x94/0x158 [btrfs]
do_writepages+0x74/0x190
filemap_fdatawrite_wbc+0x88/0xc8
start_delalloc_inodes+0x180/0x3b0 [btrfs]
btrfs_start_delalloc_roots+0x17c/0x288 [btrfs]
shrink_delalloc+0x11c/0x280 [btrfs]
flush_space+0x27c/0x310 [btrfs]
btrfs_async_reclaim_metadata_space+0xcc/0x208 [btrfs]
process_one_work+0x228/0x670
worker_thread+0x1bc/0x360
kthread+0x100/0x118
ret_from_fork+0x10/0x20
irq event stamp: 9784200
hardirqs last enabled at (9784199): [<ffffd21ec54dc01c>] _raw_spin_unlock_irqrestore+0x74/0x80
hardirqs last disabled at (9784200): [<ffffd21ec54db374>] _raw_spin_lock_irqsave+0x8c/0xa0
softirqs last enabled at (9784148): [<ffffd21ec472ff44>] handle_softirqs+0x45c/0x4b0
softirqs last disabled at (9784141): [<ffffd21ec46d01e4>] __do_softirq+0x1c/0x28
---[ end trace 0000000000000000 ]---
BTRFS critical (device dm-2): bad ordered extent accounting, root=5 ino=1492 OE offset=1654784 OE len=57344 to_dec=49152 left=0
[CAUSE]
The function btrfs_mark_ordered_io_finished() is called for marking all
ordered extents in the page range as finished, for error handling.
But for sector size < page size cases, we can have multiple ordered
extents in one page.
If extent_writepage_io() failed (the only possible case is
submit_one_sector() failed to grab an extent map), then the call site
inside extent_writepage() will call btrfs_mark_ordered_io_finished() to
finish the created ordered extents.
However some range of the ordered extent may have been submitted already,
then btrfs_mark_ordered_io_finished() is called on the same range, causing
double accounting.
[FIX]
- Introduce a new member btrfs_bio_ctrl::last_submitted
This will trace the last sector submitted through
extent_writepage_io().
So for the above extent_writepage() case, we will know exactly which
sectors are submitted and should not do the ordered extent accounting.
- Introduce a helper cleanup_ordered_extents()
This will do a sector-by-sector cleanup with
btrfs_bio_ctrl::last_submitted and btrfs_bio_ctrl::submit_bitmap into
consideartion.
Using @last_submitted is to avoid double accounting on the submitted
ranges.
Meanwhile using @submit_bitmap is to avoid touching ranges going
through compression.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
0 commit comments