summaryrefslogtreecommitdiff
path: root/fs/btrfs/disk-io.c
AgeCommit message (Collapse)Author
47 hoursMerge tag 'for-7.2-rc6-fixup-worker-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull Btrfs Fixes 2: Electric Boogaloo from David Sterba: "This brings back the fixup worker infrastructure. It's a mechanism to detect pages/folios that are marked dirty without filesystem knowledge and require COW fixup. The consequence of not doing so is silent data loss. The first patch covers the scenarios in detail, also reflecting folio API port and subpage block size support added in recent years. The original fixup worker was only for pages. The patch is relatively big, half of the code is debugging and support code, the rest is the core design around the detection and fix. The second patch handles an unlikely case when there's work left during unmount" * tag 'for-7.2-rc6-fixup-worker-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: flush the fixup workers during close_ctree btrfs: trigger cow fixup via dirty_folio()
47 hoursMerge tag 'for-7.2-rc6-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: - fix leak in encoded ioctl write - disable large folios on systems with highmem - disable block size > page size when there's no transparent hugepage support (under experimental config) - reject compressed inline extents without valid LZO headers - properly initialize cached inode mapping (if block size > page size) * tag 'for-7.2-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: initialize inode mapping flags for cached inodes btrfs: disable bs > ps support if no transparent hugepage support btrfs: fix memory leak in btrfs_do_encoded_write() btrfs: lzo: reject inline extents without valid headers btrfs: disable large folios for systems with highmem
5 daysbtrfs: flush the fixup workers during close_ctreeBoris Burkov
Reintroducing the COW fixup worker brought back the unmount race fixed by commit 41fd1e94066a ("btrfs: wait for fixup workers before stopping cleaner kthread during umount") without bringing back the fix. A fixup work item queued by the final writeback pass can still be in flight when close_ctree() stops the cleaner kthread and frees the fs roots. While destroy_workqueue() drains the queue, that happens after the cleaner thread was freed, so btrfs_add_delayed_iput() called from the fixup worker is no longer safe (not to mention that we are already in BTRFS_FS_STATE_NO_DELAYED_IPUT when it runs). Therefore we need to bring back explicitly flushing the fixup workqueue as in Filipe's original fix. The first flush will catch all the fixup writeback queued during the final sync before umount, but some of that might hit memory allocation errors and stay fixup in the blocks/folio, leading any subsequent writeback triggered *inside* umount (e.g. reclaim workers shutting down) to hit it and queue again. To fix that, and the possibility of any really long-lived pinned folios getting marked, deny queueing new fixup during umount. That allows us to flush twice (once before doing a real writeback pass to get the actual data, second time to clean up any rather unlikely stragglers right before declaring BTRFS_FS_STATE_NO_DELAYED_IPUT) and be certain nothing got re-queued. Reproduced by injecting a one-shot 30s sleep at the head of btrfs_writepage_fixup_worker() on a KASAN kernel, running the normal reproducing read dio workload before unmount and then observing: BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x35/0x50 Read of size 1 at addr ffff88810b4b08f8 by task kworker/u32:5/219 Workqueue: btrfs-fixup btrfs_writepage_fixup_worker [btrfs] Call Trace: _raw_spin_lock_irqsave+0x35/0x50 try_to_wake_up+0xc0/0x18c0 btrfs_writepage_fixup_worker+0x7f3/0xf20 [btrfs] ... Fixes: 4be9c7da6860 ("btrfs: trigger cow fixup via dirty_folio()") Assisted-by: LLM (reproduction, analysis) Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
8 daysbtrfs: disable large folios for systems with highmemQu Wenruo
[BUG] There is a bug report that on 32bit systems (i686), btrfs crashes when trying to do zstd compression: BUG: unable to handle page fault for address: fffbc000 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page CPU: 0 UID: 0 PID: 61 Comm: kworker/u8:5 Tainted: G N 7.2.0-rc3-P3 #2 PREEMPTLAZY Hardware name: LENOVO 2007F2G/2007F2G, BIOS 79ETE7WW (2.27 ) 03/21/2011 Workqueue: btrfs-delalloc btrfs_work_helper EIP: ZSTD_compressStream2+0x221/0x5fc Call Trace: ZSTD_compressStream+0xd/0x48 zstd_compress_stream+0x8/0x10 zstd_compress_bio+0x20a/0x564 btrfs_compress_bio+0x94/0xc0 compress_file_range+0x20a/0x380 btrfs_work_helper+0xc1/0x1b4 process_scheduled_works+0x15f/0x204 worker_thread+0x10c/0x178 kthread+0xe1/0xe8 ret_from_fork+0x1d/0x14c ret_from_fork_asm+0x12/0x18 entry_INT80_32+0xf0/0xf0 CR2: 00000000fffbc000 ---[ end trace 0000000000000000 ]--- [CAUSE] Inside zstd_compress_bio(), we assume the whole page cache folio can be mapped in one go. However that assumption is not true on systems with CONFIG_HIGHMEM, the pages of the large folio can be in HIGHMEM, which needs to be mapped before access. Meanwhile zstd_compress_bio() only map the page of a large folio where the start filepos is, the remaining pages are not mapped, and accessing the remaining pages will trigger the above crash. [FIX] Do not enable large folios when the kernel has CONFIG_HIGHMEM enabled. This is the same handling for bs > ps support. Link: https://github.com/kdave/btrfs-progs/issues/1146 Reported-by: Erhard Furtner <erhard_f@mailbox.org> Fixes: 9bce95edb1b4 ("btrfs: move large data folios out of experimental features") Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
9 daysbtrfs: trigger cow fixup via dirty_folio()Boris Burkov
The problem scenario: If we have a folio mmapped shared and then somebody does a dio read with that folio as the read destination, then it is possible that the dio will see a dirty destination page when it starts (and thus skip dirtying and just GUP pin it) but then while it is doing the read, btrfs finishes writing it back and by the endio, the folio is clean. In that case, the dio read must re-dirty the folio with aops->dirty_folio(): btrfs_check_read_bio() |- __iomap_dio_bio_end_io() from btrfs_bio_end_io() |- bio_check_pages_dirty() |- bio_dirty_fn() |- bio_release_pages(bio, true) |- __bio_release_pages(bio, mark_dirty == true) |- folio_lock() |- folio_mark_dirty() |- aops->dirty_folio() |- folio_unlock() A data block normally moves through writeback as follows: TASK folio_lock write clean -> dirty bit + delalloc folio_unlock WRITEBACK for-each-dirty-folio: folio_lock run_delalloc delalloc consumed -> dirty bit + OE submission dirty bit consumed -> writeback bit + OE folio_unlock ENDIO endio OE bytes accounted OE finish writeback -> clean; destroy OE Three critical invariants that this path maintains are: I1. Any dirty block is covered by delalloc xor an ordered extent I2. Any dirty block covered by an OE will be submitted into that OE I3. Any dirty block already submitted into an OE will not be submitted again into the same OE. These ensure that the block will be written exactly once. It is clear that not reserving delalloc for the re-dirty case violates I1. This situation, even without bs < folio_size, has long required btrfs to fixup such dirty pages during writeback with an asynchronous worker that is allowed to do this expensive work and writeback does not proceed for a folio while it is doing this work. Commit 247e743cbe6e ("Btrfs: Use async helpers to deal with pages that have been improperly dirtied") introduced the COW fixup to catch exactly this class at writeback, way back in 2008. Since then, there have been many advances to prevent most of the causes of such re-dirtying and we thought we could get away with removing the annoying cow-fixup in the hope of simplifying writeback for large folio support. Commit b2a9f217ad3f ("btrfs: remove the COW fixup mechanism") Commit 4927b141877c ("btrfs: remove folio ordered flag and subpage bitmap") Since it turns out this assumption was incorrect, as evidenced by the report and attendant reproducers, we must reintroduce the fixup concept. This is of course critically further complicated by bs < folio_size. In that case, rather than just a folio dirty bit, we have a bitmap for the dirty blocks in the folio. And the (also broken) invariant is: I4. folio dirty IFF at least one block bitmap dirty. The original report of a stall on a misinterpreted empty bitmap is exactly evidence of a violation of I4. It is exactly because of bs < folio_size we don't want to simply revert the removal patches. The original fixup was not properly bs < folio_size aware, which motivated removal in the first place. So we wish to build a bs < folio_size aware fixup. One other important detail from the old design, any normal write that happens after a re-dirty but before a fixup is racing with the cow fixup to do the delalloc reservation, therefore it must cancel the fixup state. If it arrives after the reservation exists, it will be a normal dirty overwrite. This critically informs the design in a pretty clear way. fixup requiring re-dirty has folio granularity, while cancellation has delalloc (block) granularity so while we only ever produce fixup in chunks of folios, we must be able to clear it in blocks. Therefore we must track the blocks needing fixup at block granularity. The obvious way to do this is with a new bitmap in btrfs_folio_state, but it is desirable to avoid that if possible. Unfortunately, I don't think it is possible and the reason is subtle and leans on a sort of extreme reproducer, but I think can be explained relatively succinctly. Consider a folio whose two halves will land in different ordered extents (can be accomplished with tricks using nodatasum) and a dio read is running with it as the shared mmap destination. 1. The front half: a. folio comes clean on a normal write b. dio read completes into the folio marking it fixup. c. a write comes for the previous folio for a range extending into this folio, this is a cancellation of the fixup which reserves space. d. writeback runs on the range *not* overlapping the folio. This half remains dirty but is now covered by an OE and is awaiting writeback running on its range to be submitted and finish the OE. 2. The back half: a. the folio is part of an OE that gets far enough along to clear writeback. b. dio read completes into the folio marking it fixup. After this, the folio's front half is dirty in the "normal" sense, it needs to be submitted to the OE waiting for it. It's a cancelled fixup. Meanwhile, the second half is a true fresh fixup. So at this point if we run writeback on this folio, we genuinely can't know what to do without block level information. If we submit it, we submit unreserved dirty from the back half. If we don't, we will never finish the OE waiting for it. So it's either a corruption or a deadlock. Thus, the full high level design picture: - btrfs_data_dirty_folio(): For out of band non-reserving dirties, mark still-clean blocks inside EOF dirty and set their fixup bits (the event carries no range, so every clean block is suspect). Already-dirty blocks are covered or pending and are left alone. - Writeback: skip fixup blocks and enqueue work for them - writepage_fixup(): for each fixup block do the fixup reservation in a worker, after which the blocks can be written back normally. - Typical reserving write paths cancel fixup state for the ranges they cover with btrfs_folio_cancel_fixup() Link: https://lore.kernel.org/linux-btrfs/20260721191152.101118-1-borntraeger@linux.ibm.com/ Assisted-by: LLM Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
11 daysMerge tag 'for-7.2-rc5-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "Zoned mode: - fix assertion and handle case of finished zone and truncated extent - fix zone metadata write pointer on actual zone reset - fix deadlock caused metadata writeback and transaction commit - fix return value reuse leading to confusion about chunk reservations raid56 scrub: - fix tracking of sector checksums when there are not checksums found - fix inverted logic when submitting parity read bio mount/remount fixes: - fix leaking 'remount in progress' state which can break other operations to work (qgroup rescan, autodefrag, reclaim) - adjust using global block reserve after read-only mount when using rescue= option - handle missing raid stripe tree when mounted with 'ignorebadroots' Misc: - fix -Wmaybe-uninitialized warning in GET_CSUMS ioctl" * tag 'for-7.2-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: raid56: fix scrub read assembly submitting no reads btrfs: zoned: skip fully truncated ordered extents at zone finish btrfs: initialize 'args' to avoid compiler warning in btrfs_ioctl_get_csums() btrfs: zoned: fix missing chunk metadata reservation btrfs: raid56: fix an incorrect csum skip during scrub btrfs: report missing raid stripe tree root during lookup btrfs: skip global block reserve accounting for rescue mounts btrfs: zoned: reset meta_write_pointer on zone reset btrfs: zoned: fix deadlock between metadata writeback and transaction commit btrfs: fix leaking BTRFS_FS_STATE_REMOUNTING flag
2026-07-21btrfs: skip global block reserve accounting for rescue mountsDongjiang Zhu
[BUG] Mounting with rescue=ibadroots after corrupting the block group tree root triggers a NULL pointer dereference: BUG: kernel NULL pointer dereference, address: 0000000000000100 RIP: 0010:btrfs_update_global_block_rsv+0x9d/0x1c0 [btrfs] Call Trace: fill_dummy_bgs+0xd4/0x120 [btrfs] open_ctree+0xc6e/0x1ca0 [btrfs] btrfs_get_tree+0x50d/0xa40 [btrfs] The same crash occurs with a corrupted raid stripe tree root, via btrfs_read_block_groups() instead of fill_dummy_bgs(). [CAUSE] With rescue=ibadroots, btrfs_read_roots() allows the mount to continue when either root cannot be read, leaving the corresponding root pointer NULL while its on-disk feature bit remains set. btrfs_update_global_block_rsv() then dereferences the missing root based on the feature bit alone. [FIX] Rescue mounts are fully read-only and cannot start transactions, so the global reserve is never consumed. Under btrfs_is_full_ro(), mark the reserve as full and return before performing the accounting. And since we need to check if the fs is mount fully RO, export fs_is_full_ro() as btrfs_is_full_ro(), and move it to fs.h. Fixes: 8dbfc14fc736 ("btrfs: account block group tree when calculating global reserve size") Fixes: 515020900d44 ("btrfs: read raid stripe tree from disk") Suggested-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Dongjiang Zhu <zhudongjiang@fnnas.com> [ Squash the fs_is_full_ro() export commit into this one. ] Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-17Merge tag 'wq-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wqLinus Torvalds
Pull workqueue updates from Tejun Heo: - Continued progress toward making alloc_workqueue() unbound by default: more callers converted to WQ_PERCPU / system_percpu_wq / system_dfl_wq, and new warnings for queues that use neither WQ_PERCPU nor WQ_UNBOUND or the legacy system_wq / system_unbound_wq. - Misc: drop the now-trivial apply_wqattrs_lock()/unlock() wrappers, forbid the TEST_WORKQUEUE benchmark from being built-in, and fix a spurious pointer level in the worker debug-dump path. * tag 'wq-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: drm/bridge: anx7625: Add WQ_PERCPU add to alloc_workqueue wifi: ath6kl: fix invalid workqueue flags in ath6kl_usb_create() btrfs: Drop WQ_PERCPU from ordered_flags in btrfs_init_workqueues() workqueue: Add warnings and ensure one among WQ_PERCPU or WQ_UNBOUND is present workqueue: Add warnings and fallback if system_{unbound}_wq is used workqueue: drop spurious '*' from print_worker_info() fn declaration workqueue: forbid TEST_WORKQUEUE from being built-in workqueue: drop apply_wqattrs_lock()/unlock() wrappers umh: replace use of system_unbound_wq with system_dfl_wq rapidio: rio: add WQ_PERCPU to alloc_workqueue users media: ddbridge: add WQ_PERCPU to alloc_workqueue users platform: cznic: turris-omnia-mcu: replace use of system_wq with system_percpu_wq media: synopsys: hdmirx: replace use of system_unbound_wq with system_dfl_wq virt: acrn: Add WQ_PERCPU to alloc_workqueue users
2026-06-14btrfs: Drop WQ_PERCPU from ordered_flags in btrfs_init_workqueues()Nathan Chancellor
After commit 21c05ca88a54 ("workqueue: Add warnings and ensure one among WQ_PERCPU or WQ_UNBOUND is present"), there is a warning from the btrfs-qgroup-rescan workqueue at run time: workqueue: btrfs-qgroup-rescan uses both WQ_PERCPU and WQ_UNBOUND. Dropped WQ_PERCPU, keeping WQ_UNBOUND. WQ_PERCPU is included in ordered_flags after commit 69635d7f4b34 ("fs: WQ_PERCPU added to alloc_workqueue users") and WQ_UNBOUND is set in alloc_ordered_workqueue(), which btrfs_alloc_ordered_workqueue() calls. Drop WQ_PERCPU from ordered_flags, as alloc_ordered_workqueue() notes that only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful. Fixes: 69635d7f4b34 ("fs: WQ_PERCPU added to alloc_workqueue users") Fixes: 21c05ca88a54 ("workqueue: Add warnings and ensure one among WQ_PERCPU or WQ_UNBOUND is present") Signed-off-by: Nathan Chancellor <nathan@kernel.org> Reviewed-by: Breno Leitao <leitao@debian.org> Acked-by: Marco Crivellari <marco.crivellari@suse.com> Acked-by: David Sterba <dsterba@suse.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-06-09btrfs: fix use-after-free after relocation failure with concurrent COWFilipe Manana
If we get a failure during relocation, before we update all the extent buffers that have file extent items pointing to extents from the block group being relocated, we can trigger a user-after-free on the reloc control structure (fs_info->reloc_control) if we have a concurrent task that is COWing a subvolume leaf. This happens like this: 1) Relocation of data block group X starts; 2) Relocation changes its state to UPDATE_DATA_PTRS; 3) A task doing a rename for example, COWs leaf A from a subvolume tree and ends up at btrfs_reloc_cow_block() and extracts fs_info->reloc_ctl into a local variable, which then passes to replace_file_extents(); 4) The relocation task gets an error and under the label 'out_put_bg' in btrfs_relocate_block_group() calls free_reloc_control(), which frees the reloc control structure that the rename task is using; 5) The rename task triggers a use-after-free on the reloc control structure that was just freed. Syzbot reported this recently, with the following stack trace: [ 88.389822][ T5325] BTRFS error (device loop0 state A): Transaction aborted (error -5) [ 88.389842][ T5325] BTRFS: error (device loop0 state A) in cleanup_transaction:2067: errno=-5 IO failure [ 88.389864][ T5325] BTRFS info (device loop0 state EA): forced readonly [ 88.392277][ T5324] BTRFS: error (device loop0 state EA) in btrfs_sync_log:3572: errno=-5 IO failure [ 88.396630][ T5325] BTRFS info (device loop0 state EA): balance: ended with status: -5 [ 88.400135][ T5346] ================================================================== [ 88.400148][ T5346] BUG: KASAN: slab-use-after-free in replace_file_extents+0x85f/0x1590 [ 88.400288][ T5346] Read of size 8 at addr ffff888012312010 by task syz.0.0/5346 [ 88.400299][ T5346] [ 88.400306][ T5346] CPU: 0 UID: 0 PID: 5346 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) [ 88.400319][ T5346] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 88.400325][ T5346] Call Trace: [ 88.400331][ T5346] <TASK> [ 88.400336][ T5346] dump_stack_lvl+0xe8/0x150 [ 88.400351][ T5346] print_address_description+0x55/0x1e0 [ 88.400364][ T5346] ? replace_file_extents+0x85f/0x1590 [ 88.400378][ T5346] print_report+0x58/0x70 [ 88.400389][ T5346] kasan_report+0x117/0x150 [ 88.400405][ T5346] ? replace_file_extents+0x85f/0x1590 [ 88.400420][ T5346] replace_file_extents+0x85f/0x1590 [ 88.400440][ T5346] ? __pfx_replace_file_extents+0x10/0x10 [ 88.400452][ T5346] ? update_ref_for_cow+0xa71/0x1270 [ 88.400473][ T5346] btrfs_force_cow_block+0xa4d/0x2450 [ 88.400492][ T5346] ? __pfx_btrfs_force_cow_block+0x10/0x10 [ 88.400508][ T5346] ? __pfx_btrfs_get_32+0x10/0x10 [ 88.400523][ T5346] btrfs_cow_block+0x3c4/0xa90 [ 88.400542][ T5346] push_leaf_left+0x2ac/0x4a0 [ 88.400561][ T5346] split_leaf+0xd16/0x12e0 [ 88.400574][ T5346] ? btrfs_bin_search+0x924/0xc70 [ 88.400592][ T5346] ? __pfx_split_leaf+0x10/0x10 [ 88.400602][ T5346] ? leaf_space_used+0x177/0x1e0 [ 88.400618][ T5346] ? btrfs_leaf_free_space+0x14a/0x2f0 [ 88.400634][ T5346] btrfs_search_slot+0x2641/0x2d20 [ 88.400654][ T5346] ? __pfx_btrfs_search_slot+0x10/0x10 [ 88.400669][ T5346] ? rcu_is_watching+0x15/0xb0 [ 88.400681][ T5346] ? trace_kmem_cache_alloc+0x29/0xe0 [ 88.400694][ T5346] btrfs_insert_empty_items+0x9c/0x190 [ 88.400711][ T5346] btrfs_insert_inode_ref+0x229/0xcb0 [ 88.400724][ T5346] ? __pfx_btrfs_insert_inode_ref+0x10/0x10 [ 88.400736][ T5346] ? __pfx_btrfs_qgroup_convert_reserved_meta+0x10/0x10 [ 88.400751][ T5346] ? btrfs_record_root_in_trans+0x124/0x180 [ 88.400767][ T5346] ? start_transaction+0x8a0/0x1820 [ 88.400778][ T5346] ? btrfs_set_inode_index+0x5e/0x100 [ 88.400787][ T5346] btrfs_rename2+0x17bb/0x40d0 [ 88.400800][ T5346] ? check_noncircular+0xda/0x150 [ 88.400814][ T5346] ? add_lock_to_list+0xc7/0x100 [ 88.400828][ T5346] ? __pfx_btrfs_rename2+0x10/0x10 [ 88.400842][ T5346] ? lockdep_hardirqs_on+0x7a/0x110 [ 88.400901][ T5346] ? lock_acquire+0x221/0x350 [ 88.400915][ T5346] ? down_write_nested+0x174/0x210 [ 88.400931][ T5346] ? __pfx_down_write_nested+0x10/0x10 [ 88.400941][ T5346] ? do_raw_spin_unlock+0x4d/0x210 [ 88.400952][ T5346] ? try_break_deleg+0x5b/0x180 [ 88.400963][ T5346] ? __pfx_btrfs_rename2+0x10/0x10 [ 88.400973][ T5346] vfs_rename+0xa96/0xeb0 [ 88.400992][ T5346] ? __pfx_vfs_rename+0x10/0x10 [ 88.401010][ T5346] ovl_fill_super+0x46b7/0x5e20 [ 88.401030][ T5346] ? __pfx_ovl_fill_super+0x10/0x10 [ 88.401042][ T5346] ? xas_create+0x1902/0x1b90 [ 88.401060][ T5346] ? __pfx___mutex_trylock_common+0x10/0x10 [ 88.401076][ T5346] ? trace_contention_end+0x3d/0x140 [ 88.401094][ T5346] ? shrinker_register+0x124/0x230 [ 88.401111][ T5346] ? __mutex_unlock_slowpath+0x1be/0x6f0 [ 88.401127][ T5346] ? shrinker_register+0x61/0x230 [ 88.401143][ T5346] ? __pfx___mutex_lock+0x10/0x10 [ 88.401158][ T5346] ? __pfx___mutex_unlock_slowpath+0x10/0x10 [ 88.401177][ T5346] ? __raw_spin_lock_init+0x45/0x100 [ 88.401196][ T5346] ? sget_fc+0x962/0xa40 [ 88.401208][ T5346] ? __pfx_set_anon_super_fc+0x10/0x10 [ 88.401222][ T5346] ? __pfx_ovl_fill_super+0x10/0x10 [ 88.401241][ T5346] get_tree_nodev+0xbb/0x150 [ 88.401257][ T5346] vfs_get_tree+0x92/0x2a0 [ 88.401272][ T5346] do_new_mount+0x341/0xd30 [ 88.401283][ T5346] ? apparmor_capable+0x126/0x170 [ 88.401301][ T5346] ? __pfx_do_new_mount+0x10/0x10 [ 88.401311][ T5346] ? ns_capable+0x89/0xe0 [ 88.401322][ T5346] ? path_mount+0x690/0x10e0 [ 88.401333][ T5346] ? user_path_at+0xd4/0x160 [ 88.401346][ T5346] __se_sys_mount+0x31d/0x420 [ 88.401358][ T5346] ? __pfx___se_sys_mount+0x10/0x10 [ 88.401370][ T5346] ? __x64_sys_mount+0x20/0xc0 [ 88.401381][ T5346] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 88.401391][ T5346] do_syscall_64+0x15f/0xf80 [ 88.401403][ T5346] ? trace_irq_disable+0x3b/0x140 [ 88.401413][ T5346] ? clear_bhb_loop+0x40/0x90 [ 88.401421][ T5346] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 88.401429][ T5346] RIP: 0033:0x7fa1ff79ce59 [ 88.401436][ T5346] Code: ff c3 66 (...) [ 88.401443][ T5346] RSP: 002b:00007fa2005affe8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5 [ 88.401456][ T5346] RAX: ffffffffffffffda RBX: 00007fa1ffa16180 RCX: 00007fa1ff79ce59 [ 88.401464][ T5346] RDX: 0000200000000100 RSI: 0000200000002240 RDI: 0000000000000000 [ 88.401474][ T5346] RBP: 00007fa1ff832d6f R08: 0000200000000440 R09: 0000000000000000 [ 88.401481][ T5346] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 [ 88.401488][ T5346] R13: 00007fa1ffa16218 R14: 00007fa1ffa16180 R15: 00007ffc734fba78 [ 88.401500][ T5346] </TASK> [ 88.401506][ T5346] [ 88.401510][ T5346] Allocated by task 5325: [ 88.401516][ T5346] kasan_save_track+0x3e/0x80 [ 88.401529][ T5346] __kasan_kmalloc+0x93/0xb0 [ 88.401542][ T5346] __kmalloc_cache_noprof+0x31c/0x660 [ 88.401554][ T5346] btrfs_relocate_block_group+0x217/0xc40 [ 88.401568][ T5346] btrfs_relocate_chunk+0x115/0x820 [ 88.401577][ T5346] __btrfs_balance+0x1db0/0x2ae0 [ 88.401587][ T5346] btrfs_balance+0xaf3/0x11b0 [ 88.401596][ T5346] btrfs_ioctl_balance+0x3d3/0x610 [ 88.401612][ T5346] __se_sys_ioctl+0xfc/0x170 [ 88.401626][ T5346] do_syscall_64+0x15f/0xf80 [ 88.401640][ T5346] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 88.401650][ T5346] [ 88.401653][ T5346] Freed by task 5325: [ 88.401659][ T5346] kasan_save_track+0x3e/0x80 [ 88.401671][ T5346] kasan_save_free_info+0x46/0x50 [ 88.401680][ T5346] __kasan_slab_free+0x5c/0x80 [ 88.401692][ T5346] kfree+0x1c5/0x640 [ 88.401703][ T5346] btrfs_relocate_block_group+0x95d/0xc40 [ 88.401715][ T5346] btrfs_relocate_chunk+0x115/0x820 [ 88.401724][ T5346] __btrfs_balance+0x1db0/0x2ae0 [ 88.401733][ T5346] btrfs_balance+0xaf3/0x11b0 [ 88.401742][ T5346] btrfs_ioctl_balance+0x3d3/0x610 [ 88.401757][ T5346] __se_sys_ioctl+0xfc/0x170 [ 88.401770][ T5346] do_syscall_64+0x15f/0xf80 [ 88.401785][ T5346] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 88.401795][ T5346] [ 88.401798][ T5346] The buggy address belongs to the object at ffff888012312000 [ 88.401798][ T5346] which belongs to the cache kmalloc-2k of size 2048 [ 88.401807][ T5346] The buggy address is located 16 bytes inside of [ 88.401807][ T5346] freed 2048-byte region [ffff888012312000, ffff888012312800) [ 88.401819][ T5346] [ 88.401822][ T5346] The buggy address belongs to the physical page: [ 88.401829][ T5346] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x12310 [ 88.401840][ T5346] head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 [ 88.401849][ T5346] flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff) [ 88.401860][ T5346] page_type: f5(slab) [ 88.401871][ T5346] raw: 00fff00000000040 ffff88801ac42000 dead000000000100 dead000000000122 [ 88.401881][ T5346] raw: 0000000000000000 0000000800080008 00000000f5000000 0000000000000000 [ 88.401892][ T5346] head: 00fff00000000040 ffff88801ac42000 dead000000000100 dead000000000122 [ 88.401902][ T5346] head: 0000000000000000 0000000800080008 00000000f5000000 0000000000000000 [ 88.401913][ T5346] head: 00fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff [ 88.401923][ T5346] head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008 [ 88.401929][ T5346] page dumped because: kasan: bad access detected [ 88.401935][ T5346] page_owner tracks the page as allocated [ 88.401941][ T5346] page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 9, tgid 9 (kworker/0:0), ts 83905464494, free_ts 83674944822 [ 88.401961][ T5346] post_alloc_hook+0x231/0x280 [ 88.401975][ T5346] get_page_from_freelist+0x24ba/0x2540 [ 88.401990][ T5346] __alloc_frozen_pages_noprof+0x18d/0x380 [ 88.402004][ T5346] allocate_slab+0x77/0x660 [ 88.402019][ T5346] refill_objects+0x339/0x3d0 [ 88.402033][ T5346] __pcs_replace_empty_main+0x321/0x720 [ 88.402043][ T5346] __kmalloc_node_track_caller_noprof+0x572/0x7b0 [ 88.402055][ T5346] __alloc_skb+0x2c1/0x7d0 [ 88.402067][ T5346] mld_newpack+0x14c/0xc90 [ 88.402080][ T5346] add_grhead+0x5a/0x2a0 [ 88.402093][ T5346] add_grec+0x1452/0x1740 [ 88.402105][ T5346] mld_ifc_work+0x6e6/0xe70 [ 88.402116][ T5346] process_scheduled_works+0xb5d/0x1860 [ 88.402127][ T5346] worker_thread+0xa53/0xfc0 [ 88.402138][ T5346] kthread+0x389/0x470 [ 88.402150][ T5346] ret_from_fork+0x514/0xb70 [ 88.402161][ T5346] page last free pid 5282 tgid 5282 stack trace: [ 88.402168][ T5346] __free_frozen_pages+0xbc7/0xd30 [ 88.402180][ T5346] __slab_free+0x274/0x2c0 [ 88.402191][ T5346] qlist_free_all+0x99/0x100 [ 88.402201][ T5346] kasan_quarantine_reduce+0x148/0x160 [ 88.402211][ T5346] __kasan_slab_alloc+0x22/0x80 [ 88.402221][ T5346] __kmalloc_cache_noprof+0x2ba/0x660 [ 88.402231][ T5346] kernfs_fop_open+0x3f0/0xda0 [ 88.402253][ T5346] do_dentry_open+0x785/0x14e0 [ 88.402262][ T5346] vfs_open+0x3b/0x340 [ 88.402270][ T5346] path_openat+0x2e08/0x3860 [ 88.402281][ T5346] do_file_open+0x23e/0x4a0 [ 88.402292][ T5346] do_sys_openat2+0x113/0x200 [ 88.402300][ T5346] __x64_sys_openat+0x138/0x170 [ 88.402309][ T5346] do_syscall_64+0x15f/0xf80 [ 88.402326][ T5346] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 88.402336][ T5346] [ 88.402339][ T5346] Memory state around the buggy address: [ 88.402345][ T5346] ffff888012311f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 88.402352][ T5346] ffff888012311f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 88.402359][ T5346] >ffff888012312000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 88.402365][ T5346] ^ [ 88.402370][ T5346] ffff888012312080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 88.402380][ T5346] ffff888012312100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 88.402385][ T5346] ================================================================== Fix this by: 1) Making the reloc control structure ref counted; 2) Make revery place that access fs_info->reloc_ctl outside the relocation code, which at the moment it's only replace_file_extents() and btrfs_init_reloc_root(), get a reference count on the structure. There's also btrfs_update_reloc_root() that is called outside the relocation code, but this case is safe because it's only called in the transaction commit path while under the fs_info->reloc_mutex protection, but nevertheless grab a reference to make the code more consistent and avoid false alerts from AI reviews; 3) Add a spinlock to protect fs_info->reloc_ctl, since we can not take the fs_info->reloc_mutex as that would cause a deadlock since that lock is taken in the transaction commit path. That spinlock is taken before setting fs_info->reloc_ctl to an allocated structure, setting it to NULL and reading fs_info->reloc_ctl; 4) Make sure the structure is freed only when its reference count drops to zero. Reported-by: syzbot+0eea49bba18051dea35e@syzkaller.appspotmail.com Link: https://lore.kernel.org/linux-btrfs/6a1df323.bb0696ed.125a22.000a.GAE@google.com/ Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-09btrfs: switch local indicator variables to boolsDavid Sterba
For all local indicator variables do simple switch to bool, done on all files. Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-09btrfs: use shifts for sectorsize and nodesizeDavid Sterba
Convert more multiplications of sectorsize or nodesize to use the shifts. The remaining cases are multiplications by constants that compiler can optimize by itself, and in tests. Reviewed-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-09btrfs: use on-disk uuid for s_uuid in temp_fsid mountsAnand Jain
When mounting a cloned filesystem with a temporary fsuuid (temp_fsid), layered modules like overlayfs require a persistent identifier. While internal in-memory fs_devices->fsid must remain unique to the kernel module, let s_uuid carry the original on-disk UUID. Signed-off-by: Anand Jain <asj@kernel.org> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-09btrfs: introduce support for huge foliosQu Wenruo
With all the previous preparations, it's finally time to enable the huge folio support. - The max folio size Here we define BTRFS_MAX_FOLIO_SIZE, which is fixed at 2MiB. This will ensure we have a large enough but not too large folio for btrfs. This limit applies to all systems regardless of page size. Then we also define BTRFS_MAX_BLOCKS_PER_FOLIO, which depends on CONFIG_BTRFS_EXPERIMENTAL. If it's an experimental build, BTRFS_MAX_BLOCKS_PER_FOLIO is 512, otherwise it's BITS_PER_LONG. The filemap max order will be calculated using both BTRFS_MAX_FOLIO_SIZE and BTRFS_MAX_BLOCKS_PER_FOLIO. E.g. for 64K page size with 64K fs block size, the limit will be BTRFS_MAX_FOLIO_SIZE (2M), which limits the filemap max order to 5. This will be lower than the old order (6), but folios larger than 2M are rarely any better for IO performance. Meanwhile excessively large folios can cause other problems like stalling the IO pipeline for too long. For 4K page size and 4K fs block size, the limit will be increased to 2M from the old 256K. This new size is constrained by both BTRFS_MAX_FOLIO_SIZE (2M) and BTRFS_MAX_BLOCKS_PER_FOLIO (512 * 4K), allowing x86_64 to achieve huge folio support, and the filemap max order will be 9. - btrfs_bio_ctrl::submit_bitmap This will be enlarged to contain BTRFS_MAX_BLOCKS_PER_FOLIO bits, and this will be on-stack memory. This will increase on-stack memory usage by 56 bytes compared to the baseline (before the first patch in the series). - Local @delalloc_bitmap inside writepage_delalloc() Unfortunately we cannot afford to handle an allocation error here, thus again we use on-stack memory. Thus this will increase on-stack memory usage by 56 bytes again. So unfortunately this means during the delalloc window, the writeback path will have +112 bytes on-stack memory usage, and for other cases the writeback path will have +56 bytes on-stack memory usage. The +56 bytes (btrfs_bio_ctrl::submit_bitmap) can be removed after we have reworked the compression submission, so the current on-stack submit_bitmap is mostly a workaround until then. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: remove call to transaction commit trace in btrfs_cleanup_transaction()Filipe Manana
We are not committing a transaction there, plus in subsequent patches we want to change the argument for the trace event to be a transaction handle instead of fs_info and in this context we don't have a transaction handle (struct btrfs_trans_handle, only a struct btrfs_transaction). So remove the call to the trace point. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: remove call to transaction commit trace in warn_about_uncommitted_trans()Filipe Manana
We are not committing a transaction there, plus in subsequent patches we want to change the argument for the trace event to be a transaction handle instead of fs_info and in this context we don't have a transaction handle (struct btrfs_trans_handle, only a struct btrfs_transaction). So remove the call to the trace point. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: simplify the btree folio wait during invalidationQu Wenruo
The btree inode is very different from regular data inodes, as the btree inode is never exposed to user space operations. All operations are either initiated by btrfs metadata operations, or MM layer like memory pressure to release folios. This means we never need to handle partial folio invalidation inside btree_invalidate_folio(). With that said, we can slightly simplify the btree folio invalidation by: - Add ASSERT()s to make sure the range covers the whole folio - Remove "if (start > end)" check As the range always covers the full folio, that check is always false and can be removed. - Open code extent_invalidate_folio() Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: unexport and move extent_invalidate_folio()Qu Wenruo
The function extent_invalidate_folio() has only a single caller inside btree_invalidate_folio(). There is no need to export such a function just for a single caller inside another file. Unexport extent_invalidate_folio() and move it to disk-io.c. And since we're moving the code, update the commit to match the current style, and remove the seemingly stale comment on the extent state removal, it's better explained by the comment just before btrfs_unlock_extent(). Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: warn about extent buffer that can not be releasedQu Wenruo
When we unmount the fs or during mount failures, btrfs will call invalidate_inode_pages() to release all btree inode folios. However that function can return -EBUSY if any folios can not be invalidated. This can be caused by: - Some extent buffers are still held by btrfs This is a logic error, as we should release all tree root nodes during unmount and mount failure handling. - Some extent buffers are under readahead and haven't yet finished These are much rarer but valid cases. In that case we should wait for those extent buffers. Introduce a new helper invalidate_and_check_btree_folios() which will: - Call invalidate_inode_pages2() and catch its return value If it returned 0 as expected, that's great and we can call it a day. - Otherwise go through each extent buffer in buffer_tree Increase the ref by one first for the eb we're checking. This is to ensure the eb won't be freed after the readahead is finished. For ebs that still have EXTENT_BUFFER_READING flag, wait for them to finish first. After waiting for the readahead, check the refs of the eb and if it's still dirty. If the eb ref count is greater than 2 (one for the buffer tree, one held by us), it means we are still holding the extent buffer somewhere else, which is a code bug. If the eb is still dirty, it means a bug in transaction handling, e.g. the bug fixed by patch "btrfs: only release the dirty pages io tree after successful writes". For either case, show a warning message about the eb, including its bytenr, owner, refs and flags. And if it's a debug build, also trigger WARN_ON_ONCE() so that fstests can properly catch such situation. Link: https://bugzilla.kernel.org/show_bug.cgi?id=221270 Reported-by: AHN SEOK-YOUNG <iamsyahn@gmail.com> CC: Teng Liu <27rabbitlt@gmail.com> Tested-by: Teng Liu <27rabbitlt@gmail.com> Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: limit size of bios submitted from writebackJan Kara
Currently btrfs_writepages() just accumulates as large bio as possible (within writeback_control constraints) and then submits it. This can however lead to significant latency in writeback IO submission (I have observed tens of milliseconds) because the submitted bio easily has over hundred of megabytes. Consequently this leads to IO pipeline stalls and reduced throughput. At the same time beyond certain size submitting so large bio provides diminishing returns because the bio is split by the block layer immediately anyway. So compute (estimate of) bio size beyond which we are unlikely to improve performance and just submit the bio for writeback once we accumulate that much to keep the IO pipeline busy. This improves writeback throughput for sequential writes by about 15% on the test machine I was using. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Jan Kara <jack@suse.cz> [ Fix the handling of missing device to avoid NULL pointer dereference. ] Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: add missing unlikely to if branches leading to a DEBUG_WARN()Filipe Manana
If statement branches that lead to a DEBUG_WARN() are unexpected to happen and in most places we surround their expressions with the unlikely tag, however a few places are missing. Add the unlikely tag to those missing places to make it explicit to a reader that it's not expected and to hint the compiler to generate better code. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-06-08btrfs: remove the COW fixup mechanismQu Wenruo
[BACKGROUND] Btrfs has a special mechanism called COW fixup, which detects dirty pages without an ordered extent (folio ordered flag). Normally a dirty folio must go through delayed allocation (delalloc) before it can be submitted, and delalloc will create an ordered extent for it and mark the range with ordered flag. However in older kernels, there are bugs related to get_user_pages() which can lead to some page marked dirty but without notifying the fs to properly prepare them for writeback. In that case without an ordered extent btrfs is unable to properly submit such dirty folios, thus the COW fixup mechanism is introduced, which do the extra space reservation so that they can be written back properly. [MODERN SOLUTIONS] The MM layer has solved it properly now with the introduction of pin_user_pages*(), so we're handling cases that are no longer valid. So commit 7ca3e84980ef ("btrfs: reject out-of-band dirty folios during writeback") is introduced to change the behavior from going through COW fixup to rejecting them directly for experimental builds. So far it works fine, but when errors are injected into the IO path, we have random failures triggering the new warnings. It looks like we have error path that cleared the ordered flag but leaves the folio dirty flag, which later triggers the warning. [REMOVAL OF COW FIXUP] Although I hope to fix all those known warnings cases, I just can not figure out the root cause yet. But on the other hand, if we remove the ordered and checked flags in the future, and purely rely on the dirty flags and ordered extent search, we can get a much cleaner handling. Considering it's no longer hitting the COW fixup for normal IO paths, I think it's finally the time to remove the COW fixup completely. Furthermore, the function name "btrfs_writepage_cow_fixup()" is no longer meaningful, and since it's pretty small, only a folio flag check with error message, there is no need to put it as a dedicated helper, just open code it inside extent_writepage_io(). Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-05-08btrfs: only release the dirty pages io tree after successful writesQu Wenruo
[WARNING] With extra warning on dirty extent buffers at umount (aka, the next patch in the series), test case generic/388 can trigger the following warning about dirty extent buffers at unmount time: BTRFS critical (device dm-2 state E): emergency shutdown BTRFS error (device dm-2 state E): error while writing out transaction: -30 BTRFS warning (device dm-2 state E): Skipping commit of aborted transaction. BTRFS error (device dm-2 state EA): Transaction 9 aborted (error -30) BTRFS: error (device dm-2 state EA) in cleanup_transaction:2068: errno=-30 Readonly filesystem BTRFS info (device dm-2 state EA): forced readonly BTRFS info (device dm-2 state EA): last unmount of filesystem 4fbf2e15-f941-49a0-bc7c-716315d2777c ------------[ cut here ]------------ WARNING: disk-io.c:3311 at invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs], CPU#8: umount/914368 CPU: 8 UID: 0 PID: 914368 Comm: umount Tainted: G OE 7.1.0-rc1-custom+ #372 PREEMPT(full) 2de38db8d1deae71fde295430a0ff3ab98ccf596 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022 RIP: 0010:invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs] Call Trace: <TASK> close_ctree+0x52e/0x574 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] generic_shutdown_super+0x89/0x1a0 kill_anon_super+0x16/0x40 btrfs_kill_super+0x16/0x20 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] deactivate_locked_super+0x2d/0xb0 cleanup_mnt+0xdc/0x140 task_work_run+0x5a/0xa0 exit_to_user_mode_loop+0x123/0x4b0 do_syscall_64+0x243/0x7c0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> ---[ end trace 0000000000000000 ]--- BTRFS warning (device dm-2 state EA): unable to release extent buffer 30539776 owner 9 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30621696 owner 257 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30638080 owner 258 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30654464 owner 7 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30703616 owner 2 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30720000 owner 10 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30736384 owner 4 gen 9 refs 2 flags 0x7 BTRFS warning (device dm-2 state EA): unable to release extent buffer 30752768 owner 11 gen 9 refs 2 flags 0x7 I'm using a stripped down version, which seems to trigger the warning more reliably: _fsstress_pid="" workload() { dmesg -C mkfs.btrfs -f -K $dev > /dev/null echo 1 > /sys/kernel/debug/clear_warn_once mount $dev $mnt $fsstress -w -n 1024 -p 4 -d $mnt & _fsstress_pid=$! sleep 0 $godown $mnt pkill --echo -PIPE fsstress > /dev/null wait $_fsstress_pid unset _fsstress_pid umount $mnt if dmesg | grep -q "WARNING"; then fail fi } for (( i = 0; i < $runtime; i++ )); do echo "=== $i/$runtime ===" workload done [CAUSE] Inside btrfs_write_and_wait_transaction(), we first try to write all dirty ebs, then wait for them to finish. After that we call btrfs_extent_io_tree_release() to free all extent states from dirty_pages io tree. However if we hit an error from btrfs_write_marked_extent(), then we still call btrfs_extent_io_tree_release() to clear that dirty_pages io tree, which may contain dirty records that we haven't yet submitted. Furthermore, the later transaction cleanup path will utilize that dirty_pages io tree to properly cleanup those dirty ebs, but since it's already empty, no dirty ebs are properly cleaned up, thus will later trigger the warnings inside invalidate_btree_folios(). [FIX] Normally such dirty ebs won't cause problems, as when the iput() is called on the btree inode, the dirty ebs will be forcibly written back, and since the fs is already in an error status, such writeback will not reach disk and finish immediately. But it's still better to get rid of such dirty ebs, if we ended up with dirty ebs but the fs is not in an error status, then such writeback at iput() time will be too late, as all workers are already stopped but writeback will utilize workers, which will lead to NULL pointer dereferences. Instead of unconditionally calling btrfs_extent_io_tree_release(), only call it if btrfs_write_and_wait_transaction() finished successfully, so that @dirty_pages extent io tree is kept untouched for transaction cleanup. CC: stable@vger.kernel.org # 6.1+ Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan checkDave Chen
The UUID tree rescan check in open_ctree() compares fs_info->generation with the superblock's uuid_tree_generation. This comparison is not reliable because fs_info->generation is bumped at transaction start time in join_transaction(), while uuid_tree_generation is only updated at commit time via update_super_roots(). Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the late rescan decision, mount operations such as file orphan cleanup from an unclean shutdown start transactions without committing them. This advances fs_info->generation past uuid_tree_generation and produces a false-positive mismatch. Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The flag was already set earlier in open_ctree() when the generations were known to match, and accurately represents "UUID tree is up to date" without being affected by subsequent transaction starts. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Dave Chen <davechen@synology.com> Signed-off-by: Robbie Ko <robbieko@synology.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: tag as unlikely if statements that check for fs in error stateFilipe Manana
Having the filesystem in an error state, meaning we had a transaction abort, is unexpected. Mark every check for the error state with the unlikely annotation to convey that and to allow the compiler to generate better code. On x86_64, using gcc 14.2.0-19 from Debian, resulted in a slightly reduced object size and better code. Before: $ size fs/btrfs/btrfs.ko text data bss dec hex filename 2008598 175912 15592 2200102 219226 fs/btrfs/btrfs.ko After: $ size fs/btrfs/btrfs.ko text data bss dec hex filename 2008450 175912 15592 2199954 219192 fs/btrfs/btrfs.ko Reviewed-by: Anand Jain <asj@kernel.org> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: only invalidate btree inode pages after all ebs are releasedQu Wenruo
In close_ctree(), we call invalidate_inode_pages2() to invalidate all pages from btree inode. But the problem is, it never returns 0, but always -EBUSY. The problem is that we are still holding all the essential tree root nodes, thus pages holding those tree blocks can not be invalidated thus invalidate_inode_pages2() always returns -EBUSY. This is also against the error cleanup path of open_ctree(), which properly frees all root pointers before calling invalidate_inode_pages(). So fix the order by delaying invalidate_inode_pages2() until we have freed all root pointers. Reviewed-by: Anand Jain <asj@kernel.org> Reviewed-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: remove atomic parameter from btrfs_buffer_uptodate()Qu Wenruo
That parameter was introduced by commit b9fab919b748 ("Btrfs: avoid sleeping in verify_parent_transid while atomic"). At that time we needed to lock the extent buffer range inside the io tree to avoid content changes, thus it could sleep. But that behavior is no longer there, as later commit 9e2aff90fc2a ("btrfs: stop using lock_extent in btrfs_buffer_uptodate") dropped the io tree lock. We can remove the @atomic parameter safely now. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: revalidate cached tree blocks on the uptodate pathZhengYuan Huang
read_extent_buffer_pages_nowait() returns immediately when an extent buffer is already marked uptodate. On that cache-hit path, the caller supplied btrfs_tree_parent_check is not re-run. This can let read_tree_root_path() accept a cached tree block whose actual header level/owner does not match the expected value derived from the parent. E.g. a corrupted root item that points to a tree block which doesn't even belong to that root, and has mismatching level/owner. But that tree block is already read and cached, later the corrupted tree root got read from disk and hit the cached tree block. Fix this by re-validating cached extent buffers against the supplied btrfs_tree_parent_check on the uptodate path, and make read_tree_root_path() pass its check to btrfs_buffer_uptodate(). This makes cache hits and fresh reads follow the same tree-parent verification rules, and turns the corruption into a read failure instead of constructing an inconsistent root object. Signed-off-by: ZhengYuan Huang <gality369@gmail.com> Reviewed-by: Qu Wenruo <wqu@suse.com> [ Resolve the conflict with extent_buffer_uptodate() helper, handle transid mismatch case ] Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: constify arguments of some functionsFilipe Manana
There are several functions that take pointer arguments but don't need to modify the objects they point to, so add the const qualifiers. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: remove duplicate include of delayed-inode.h in disk-io.cChen Ni
Remove duplicate inclusion of delayed-inode.h in disk-io.c to clean up redundant code. Signed-off-by: Chen Ni <nichen@iscas.ac.cn> Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: remove redundant extent_buffer_uptodate() checks after read_tree_block()Filipe Manana
We have several places that call extent_buffer_uptodate() after reading a tree block with read_tree_block(), but that is redundant since we already call extent_buffer_uptodate() in the call chain of read_tree_block(): read_tree_block() btrfs_read_extent_buffer() read_extent_buffer_pages() returns -EIO if extent_buffer_uptodate() returns false So remove those redundant checks. Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: remove duplicated eb uptodate check in btrfs_buffer_uptodate()Filipe Manana
We are calling extent_buffer_uptodate() twice, and the result will not change before the second call. So remove the second call. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: set written super flag once in write_all_supers()Filipe Manana
In case we have multiple devices, there is no point in setting the written flag in the super block on every iteration over the device list. Just do it once before the loop. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: remove max_mirrors argument from write_all_supers()Filipe Manana
There's no need to pass max_mirrors to write_all_supers() since from the given transaction handle we can infer if we are in a transaction commit or fsync context, so we can determine how many mirrors we need to use. So remove the max_mirror argument from write_all_supers() and stop adjusting it in the callees write_dev_supers() and wait_dev_supers(), simplifying them besides the parameter list for write_all_supers(). Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: tag error branches as unlikely during super block writesFilipe Manana
Mark all the unexpected error checks as unlikely, to make it more clear they are unexpected and to allow the compiler to potentially generate better code. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: abort transaction on error in write_all_supers()Filipe Manana
We are in a transaction context and have an handle, so instead of using the less preferred btrfs_handle_fs_error(), abort the transaction and log an error to give some context information. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: pass transaction handle to write_all_supers()Filipe Manana
We are holding a transaction In every context we call write_all_supers(), so pass the transaction handle instead of fs_info to it. This will allow us to abort the transaction in write_all_supers() instead of calling btrfs_handle_fs_error() in a later patch. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: mark all error and warning checks as unlikely in btrfs_validate_super()Filipe Manana
When validating a super block, either when mounting or every time we write a super block to disk, we do many checks for error and warnings and we don't expect to hit any. So mark each one as unlikely to reflect that and allow the compiler to potentially generate better code. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: move min sys chunk array size check to validate_sys_chunk_array()Filipe Manana
We check the minimum size of the sys chunk array in btrfs_validate_super() but we have a better place for that, the helper validate_sys_chunk_array() which we use for every other sys chunk array check. So move it there, also converting the return error from -EINVAL to -EUCLEAN, which is a better fit and also consistent with the other checks. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-04-07btrfs: remove duplicate system chunk array max size overflow checkFilipe Manana
We check it twice, once in validate_sys_chunk_array() and then again in its caller, btrfs_validate_super(), right after it calls validate_sys_chunk_array(). So remove the duplicated check from btrfs_validate_super(). Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-03-28Merge tag 'for-7.0-rc5-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "A few more fixes. There's one that stands out in size as it fixes an edge case in fsync. - fix issue on fsync where file with zero size appears as a non-zero after log replay - in zlib compression, handle a crash when data alignment causes folio reference issues - fix possible crash with enabled tracepoints on a overlayfs mount - handle device stats update error - on zoned filesystems, fix kobject leak on sub-block groups - fix super block offset in an error message in validation" * tag 'for-7.0-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix lost error when running device stats on multiple devices fs btrfs: tracepoints: get correct superblock from dentry in event btrfs_sync_file() btrfs: zlib: handle page aligned compressed size correctly btrfs: fix leak of kobject name for sub-group space_info btrfs: fix zero size inode with non-zero size after log replay btrfs: fix super block offset in error message in btrfs_validate_super()
2026-03-23btrfs: fix super block offset in error message in btrfs_validate_super()Mark Harmstone
Fix the superblock offset mismatch error message in btrfs_validate_super(): we changed it so that it considers all the superblocks, but the message still assumes we're only looking at the first one. The change from %u to %llu is because we're changing from a constant to a u64. Fixes: 069ec957c35e ("btrfs: Refactor btrfs_check_super_valid") Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Mark Harmstone <mark@harmstone.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-03-21Merge tag 'for-7.0-rc4-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "Another batch of fixes for problems that have been identified by tools analyzing code or by fuzzing. Most of them are short, two patches fix the same thing in many places so the diffs are bigger. - handle potential NULL pointer errors after attempting to read extent and checksum trees - prevent ENOSPC when creating many qgroups by ioctls in the same transaction - encoded write ioctl fixes (with 64K page and 4K block size): - fix unexpected bio length - do not let compressed bios and pages interfere with page cache - compression fixes on setups with 64K page and 4K block size: fix folio length assertions (zstd and lzo) - remap tree fixes: - make sure to hold block group reference while moving it - handle early exit when moving block group to unused list - handle deleted subvolumes with inconsistent state of deletion progress" * tag 'for-7.0-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: reject root items with drop_progress and zero drop_level btrfs: check block group before marking it unused in balance_remap_chunks() btrfs: hold block group reference during entire move_existing_remap() btrfs: fix an incorrect ASSERT() condition inside lzo_decompress_bio() btrfs: fix an incorrect ASSERT() condition inside zstd_decompress_bio() btrfs: do not touch page cache for encoded writes btrfs: fix a bug that makes encoded write bio larger than expected btrfs: reserve enough transaction items for qgroup ioctls btrfs: check for NULL root after calls to btrfs_csum_root() btrfs: check for NULL root after calls to btrfs_extent_root()
2026-03-17btrfs: check for NULL root after calls to btrfs_csum_root()Filipe Manana
btrfs_csum_root() can return a NULL pointer in case the root we are looking for is not in the rb tree that tracks roots. So add checks to every caller that is missing such check to log a message and return an error. Reported-by: Chris Mason <clm@meta.com> Link: https://lore.kernel.org/linux-btrfs/20260208161657.3972997-1-clm@meta.com/ Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-03-17btrfs: check for NULL root after calls to btrfs_extent_root()Filipe Manana
btrfs_extent_root() can return a NULL pointer in case the root we are looking for is not in the rb tree that tracks roots. So add checks to every caller that is missing such check to log a message and return an error. The same applies to callers of btrfs_block_group_root(), since it calls btrfs_extent_root(). Reported-by: Chris Mason <clm@meta.com> Link: https://lore.kernel.org/linux-btrfs/20260208161657.3972997-1-clm@meta.com/ Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-03-12Merge tag 'for-7.0-rc3-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: - detect possible file name hash collision earlier so it does not lead to transaction abort - handle b-tree leaf overflows when snapshotting a subvolume with set received UUID, leading to transaction abort - in zoned mode, reorder relocation block group initialization after the transaction kthread start - fix orphan cleanup state tracking of subvolume, this could lead to invalid dentries under some conditions - add locking around updates of dynamic reclain state update - in subpage mode, add missing RCU unlock when trying to releae extent buffer - remap tree fixes: - add missing description strings for the newly added remap tree - properly update search key when iterating backrefs * tag 'for-7.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: remove duplicated definition of btrfs_printk_in_rcu() btrfs: remove unnecessary transaction abort in the received subvol ioctl btrfs: abort transaction on failure to update root in the received subvol ioctl btrfs: fix transaction abort on set received ioctl due to item overflow btrfs: fix transaction abort when snapshotting received subvolumes btrfs: fix transaction abort on file creation due to name hash collision btrfs: read key again after incrementing slot in move_existing_remaps() btrfs: add missing RCU unlock in error path in try_release_subpage_extent_buffer() btrfs: set BTRFS_ROOT_ORPHAN_CLEANUP during subvol create btrfs: zoned: move btrfs_zoned_reserve_data_reloc_bg() after kthread start btrfs: hold space_info->lock when clearing periodic reclaim ready btrfs: print-tree: add remap tree definitions
2026-03-03Merge tag 'for-7.0-rc2-tag' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "One-liner or short fixes for minor/moderate problems reported recently: - fixes or level adjustments of error messages - fix leaked transaction handles after aborted transactions, when using the remap tree feature - fix a few leaked chunk maps after errors - fix leaked page array in io_uring encoded read if an error occurs and the 'finished' is not called - fix double release of reserved extents when doing a range COW - don't commit super block when the filesystem is in shutdown state - fix squota accounting condition when checking members vs parent usage - other error handling fixes" * tag 'for-7.0-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: check block group lookup in remove_range_from_remap_tree() btrfs: fix transaction handle leaks in btrfs_last_identity_remap_gone() btrfs: fix chunk map leak in btrfs_map_block() after btrfs_translate_remap() btrfs: fix chunk map leak in btrfs_map_block() after btrfs_chunk_map_num_copies() btrfs: fix compat mask in error messages in btrfs_check_features() btrfs: print correct subvol num if active swapfile prevents deletion btrfs: fix warning in scrub_verify_one_metadata() btrfs: fix objectid value in error message in check_extent_data_ref() btrfs: fix incorrect key offset in error message in check_dev_extent_item() btrfs: fix error message order of parameters in btrfs_delete_delayed_dir_index() btrfs: don't commit the super block when unmounting a shutdown filesystem btrfs: free pages on error in btrfs_uring_read_extent() btrfs: fix referenced/exclusive check in squota_check_parent_usage() btrfs: remove pointless WARN_ON() in cache_save_setup() btrfs: convert log messages to error level in btrfs_replay_log() btrfs: remove btrfs_handle_fs_error() after failure to recover log trees btrfs: remove redundant warning message in btrfs_check_uuid_tree() btrfs: change warning messages to error level in open_ctree() btrfs: fix a double release on reserved extents in cow_one_range() btrfs: handle discard errors in in btrfs_finish_extent_commit()
2026-03-03btrfs: zoned: move btrfs_zoned_reserve_data_reloc_bg() after kthread startJohannes Thumshirn
btrfs_zoned_reserve_data_reloc_bg() is called on each mount of a file system and allocates a new block-group, to assign it to be the dedicated relocation target, if no pre-existing usable block-group for this task is found. If for some reason the transaction is aborted, btrfs_end_transaction() will wake up the transaction kthread. But the transaction kthread is not yet initialized at the time btrfs_zoned_reserve_data_reloc_bg() is called, leading to the following NULL-pointer dereference: RSP: 0018:ffffc9000c617c98 EFLAGS: 00010046 RAX: 0000000000000000 RBX: 000000000000073c RCX: 0000000000000002 RDX: 0000000000000001 RSI: 0000000000000003 RDI: 0000000000000001 RBP: 0000000000000207 R08: ffffffff8223c71d R09: 0000000000000635 R10: ffff888108588000 R11: 0000000000000003 R12: 0000000000000003 R13: 000000000000073c R14: 0000000000000000 R15: ffff888114dd6000 FS: 00007f2993745840(0000) GS:ffff8882b508d000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000000073c CR3: 0000000121a82006 CR4: 0000000000770eb0 PKRU: 55555554 Call Trace: <TASK> try_to_wake_up (./include/linux/spinlock.h:557 kernel/sched/core.c:4106) __btrfs_end_transaction (fs/btrfs/transaction.c:1115 (discriminator 2)) btrfs_zoned_reserve_data_reloc_bg (fs/btrfs/zoned.c:2840) open_ctree (fs/btrfs/disk-io.c:3588) btrfs_get_tree.cold (fs/btrfs/super.c:982 fs/btrfs/super.c:1944 fs/btrfs/super.c:2087 fs/btrfs/super.c:2121) vfs_get_tree (fs/super.c:1752) __do_sys_fsconfig (fs/fsopen.c:231 fs/fsopen.c:295 fs/fsopen.c:473) do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:131) RIP: 0033:0x7f299392740e Move the call to btrfs_zoned_reserve_data_reloc_bg() after the transaction_kthread has been initialized to fix this problem. Fixes: 694ce5e143d6 ("btrfs: zoned: reserve data_reloc block group on mount") Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-02-26btrfs: fix compat mask in error messages in btrfs_check_features()Mark Harmstone
Commit d7f67ac9a928 ("btrfs: relax block-group-tree feature dependency checks") introduced a regression when it comes to handling unsupported incompat or compat_ro flags. Beforehand we only printed the flags that we didn't recognize, afterwards we printed them all, which is less useful. Fix the error handling so it behaves like it used to. Fixes: d7f67ac9a928 ("btrfs: relax block-group-tree feature dependency checks") Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Mark Harmstone <mark@harmstone.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
2026-02-26btrfs: don't commit the super block when unmounting a shutdown filesystemMiquel Sabaté Solà
When unmounting a filesystem we will try, among many other things, to commit the super block. On a filesystem that was shutdown, though, this will always fail with -EROFS as writes are forbidden on this context; and an error will be reported. Don't commit the super block on this situation, which should be fine as the filesystem is frozen before shutdown and, therefore, it should be at a consistent state. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com> Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>