]> git.ipfire.org Git - thirdparty/kernel/stable.git/log
thirdparty/kernel/stable.git
2 weeks agowatchdog: ni903x_wdt: Convert to a platform driver
Rafael J. Wysocki [Sat, 14 Mar 2026 11:53:01 +0000 (12:53 +0100)] 
watchdog: ni903x_wdt: Convert to a platform driver

In all cases in which a struct acpi_driver is used for binding a driver
to an ACPI device object, a corresponding platform device is created by
the ACPI core and that device is regarded as a proper representation of
underlying hardware.  Accordingly, a struct platform_driver should be
used by driver code to bind to that device.  There are multiple reasons
why drivers should not bind directly to ACPI device objects [1].

In particular, registering a watchdog device under a struct acpi_device
is questionable because it causes the watchdog to be hidden in the ACPI
bus sysfs hierarchy and it goes against the general rule that a struct
acpi_device can only be a parent of another struct acpi_device.

Overall, it is better to bind drivers to platform devices than to their
ACPI companions, so convert the ni903x_wdt watchdog ACPI driver to a
platform one.

While this is not expected to alter functionality, it changes sysfs
layout and so it will be visible to user space.

Note that after this change it actually makes sense to look for
the "timeout-sec" property via device_property_read_u32() under the
device passed to watchdog_init_timeout() because it has an fwnode
handle (unlike a struct acpi_device which is an fwnode itself).

Link: https://lore.kernel.org/all/2396510.ElGaqSPkdT@rafael.j.wysocki/
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://patch.msgid.link/13996583.uLZWGnKmhe@rafael.j.wysocki
2 weeks agoACPI: PAD: xen: Convert to a platform driver
Rafael J. Wysocki [Sat, 14 Mar 2026 11:57:23 +0000 (12:57 +0100)] 
ACPI: PAD: xen: Convert to a platform driver

In all cases in which a struct acpi_driver is used for binding a driver
to an ACPI device object, a corresponding platform device is created by
the ACPI core and that device is regarded as a proper representation of
underlying hardware.  Accordingly, a struct platform_driver should be
used by driver code to bind to that device.  There are multiple reasons
why drivers should not bind directly to ACPI device objects [1].

Overall, it is better to bind drivers to platform devices than to their
ACPI companions, so convert the Xen ACPI processor aggregator device
(PAD) driver to a platform one.

While this is not expected to alter functionality, it changes sysfs
layout and so it will be visible to user space.

Link: https://lore.kernel.org/all/2396510.ElGaqSPkdT@rafael.j.wysocki/
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/8683270.T7Z3S40VBb@rafael.j.wysocki
2 weeks agofs/resctrl: Add missing return value descriptions
Reinette Chatre [Tue, 7 Apr 2026 16:01:59 +0000 (09:01 -0700)] 
fs/resctrl: Add missing return value descriptions

Using the stricter "./tools/docs/kernel-doc -Wall -v" to verify proper
formatting of documentation comments includes warnings related to return
markup on functions that are omitted during the default verification
checks. This stricter verification reports a couple of missing return
descriptions in resctrl:

    Warning: .../fs/resctrl/rdtgroup.c:1536 No description found for return value of 'rdtgroup_cbm_to_size'
    Warning: .../fs/resctrl/rdtgroup.c:3131 No description found for return value of 'mon_get_kn_priv'
    Warning: .../fs/resctrl/rdtgroup.c:3523 No description found for return value of 'cbm_ensure_valid'
    Warning: .../fs/resctrl/monitor.c:238 No description found for return value of 'resctrl_find_cleanest_closid'

Add the missing return descriptions.

Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://patch.msgid.link/1c50b9f7c73251c007133590986f127e1af57780.1775576382.git.reinette.chatre@intel.com
2 weeks agoMAINTAINERS: Update resctrl entry
Reinette Chatre [Tue, 7 Apr 2026 16:01:58 +0000 (09:01 -0700)] 
MAINTAINERS: Update resctrl entry

The x86 maintainers handle the resctrl filesystem and x86 architectural
resctrl code. Even so, the x86 maintainers are not part of the resctrl
section and not returned when scripts/get_maintainer.pl is run on resctrl
filesystem code. With patches flowing via x86 maintainers resctrl should
also ensure it follows the tip rules.

Add the x86 maintainer alias, x86@kernel.org, to the resctrl section to
ensure x86 maintainers are included in associated resctrl submissions.

Add a reference to the tip tree handbook to make it clear which rules
resctrl follows.

Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://patch.msgid.link/4c14dd82e81737c6413e10fe097475b1cc0886fc.1775576382.git.reinette.chatre@intel.com
2 weeks agosched_ext: Documentation: Fix scx_bpf_move_to_local kfunc name
fangqiurong [Tue, 7 Apr 2026 09:34:05 +0000 (17:34 +0800)] 
sched_ext: Documentation: Fix scx_bpf_move_to_local kfunc name

The correct kfunc name is scx_bpf_dsq_move_to_local(), not
scx_bpf_move_to_local(). Fix the two references in the
Scheduling Cycle section.

Signed-off-by: fangqiurong <fangqiurong@kylinos.cn>
Signed-off-by: Tejun Heo <tj@kernel.org>
2 weeks agoworkqueue: use NR_STD_WORKER_POOLS instead of hardcoded value
Maninder Singh [Tue, 7 Apr 2026 03:42:15 +0000 (09:12 +0530)] 
workqueue: use NR_STD_WORKER_POOLS instead of hardcoded value

use NR_STD_WORKER_POOLS for irq_work_fns[] array definition.
NR_STD_WORKER_POOLS is also 2, but better to use MACRO.
Initialization loop for_each_bh_worker_pool() also uses same MACRO.

Signed-off-by: Maninder Singh <maninder1.s@samsung.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
2 weeks agoof: property: Allow fw_devlink device-tree on x86
Herve Codina [Wed, 25 Mar 2026 14:35:44 +0000 (15:35 +0100)] 
of: property: Allow fw_devlink device-tree on x86

PCI drivers can use a device-tree overlay to describe the hardware
available on the PCI board. This is the case, for instance, of the
LAN966x PCI device driver.

Adding some more nodes in the device-tree overlay adds some more
consumer/supplier relationship between devices instantiated from this
overlay.

Those fw_node consumer/supplier relationships are handled by fw_devlink
and are created based on the device-tree parsing done by the
of_fwnode_add_links() function.

Those consumer/supplier links are needed in order to ensure a correct PM
runtime management and a correct removal order between devices.

For instance, without those links a supplier can be removed before its
consumers is removed leading to all kind of issue if this consumer still
want the use the already removed supplier.

The support for the usage of an overlay from a PCI driver has been added
on x86 systems in commit 1f340724419ed ("PCI: of: Create device tree PCI
host bridge node").

In the past, support for fw_devlink on x86 had been tried but this
support has been removed in commit 4a48b66b3f52 ("of: property: Disable
fw_devlink DT support for X86"). Indeed, this support was breaking some
x86 systems such as OLPC system and the regression was reported in [0].

Instead of disabling this support for all x86 system, use a finer grain
and disable this support only for the possible problematic subset of x86
systems (at least OLPC and CE4100).

Those systems use a device-tree to describe their hardware. Identify
those systems using key properties in the device-tree.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Link: https://lore.kernel.org/lkml/3c1f2473-92ad-bfc4-258e-a5a08ad73dd0@web.de/
Link: https://patch.msgid.link/20260325143555.451852-18-herve.codina@bootlin.com
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
2 weeks agobtrfs: btrfs_log_dev_io_error() on all bio errors
Boris Burkov [Mon, 6 Apr 2026 16:15:15 +0000 (09:15 -0700)] 
btrfs: btrfs_log_dev_io_error() on all bio errors

As far as I can tell, we never intentionally constrained ourselves to
these status codes, and it is misleading and surprising to lack the
bdev error logging when we get a different error code from the block
layer. This can lead to jumping to a wrong conclusion like "this
system didn't see any bio failures but aborted with EIO".

For example on nvme devices, I observe many failures coming back as
BLK_STS_MEDIUM. It is apparent that the nvme driver returns a variety of
BLK_STS_* status values in nvme_error_status().

So handle the known expected errors and make some noise on the rest
which we expect won't really happen.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Anand Jain <asj@kernel.org>
Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: fix silent IO error loss in encoded writes and zoned split
Michal Grzedzicki [Mon, 30 Mar 2026 16:06:44 +0000 (09:06 -0700)] 
btrfs: fix silent IO error loss in encoded writes and zoned split

can_finish_ordered_extent() and btrfs_finish_ordered_zoned() set
BTRFS_ORDERED_IOERR via bare set_bit(). Later,
btrfs_mark_ordered_extent_error() in btrfs_finish_one_ordered() uses
test_and_set_bit(), finds it already set, and skips
mapping_set_error(). The error is never recorded on the inode's
address_space, making it invisible to fsync. For encoded writes this
causes btrfs receive to silently produce files with zero-filled holes.

Fix: replace bare set_bit(BTRFS_ORDERED_IOERR) with
btrfs_mark_ordered_extent_error() which pairs test_and_set_bit() with
mapping_set_error(), guaranteeing the error is recorded exactly once.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Mark Harmstone <mark@harmstone.com>
Signed-off-by: Michal Grzedzicki <mge@meta.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: skip clearing EXTENT_DEFRAG for NOCOW ordered extents
Dave Chen [Mon, 30 Mar 2026 03:31:48 +0000 (11:31 +0800)] 
btrfs: skip clearing EXTENT_DEFRAG for NOCOW ordered extents

In btrfs_finish_one_ordered(), clear_bits is unconditionally initialized
with EXTENT_DEFRAG.  For NOCOW ordered extents this is always a no-op
because should_nocow() already forces the COW path when EXTENT_DEFRAG is
set, so a NOCOW ordered extent can never have EXTENT_DEFRAG on its range.

Although harmless, the unconditional btrfs_clear_extent_bit() call still
performs a cold rbtree lookup under the io tree spinlock on every NOCOW
write completion.  Avoid this by only adding EXTENT_DEFRAG to clear_bits
for non-NOCOW ordered extents, and skip the call entirely when there are
no bits to clear.

Signed-off-by: Dave Chen <davechen@synology.com>
Signed-off-by: Robbie Ko <robbieko@synology.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan check
Dave Chen [Tue, 7 Apr 2026 03:36:24 +0000 (11:36 +0800)] 
btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan check

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>
2 weeks agobtrfs: remove duplicate journal_info reset on failure to commit transaction
Filipe Manana [Wed, 1 Apr 2026 18:46:59 +0000 (19:46 +0100)] 
btrfs: remove duplicate journal_info reset on failure to commit transaction

If we get an error during the transaction commit path, we are resetting
current->journal_info to NULL twice - once in btrfs_commit_transaction()
right before calling cleanup_transaction() and then once again inside
cleanup_transaction(). Remove the instance in btrfs_commit_transaction().

Reviewed-by: Anand Jain <asj@kernel.org>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tag as unlikely if statements that check for fs in error state
Filipe Manana [Wed, 1 Apr 2026 17:51:35 +0000 (18:51 +0100)] 
btrfs: tag as unlikely if statements that check for fs in error state

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>
2 weeks agoMerge tag 'ata-7.0-final' of git://git.kernel.org/pub/scm/linux/kernel/git/libata...
Linus Torvalds [Tue, 7 Apr 2026 17:33:49 +0000 (10:33 -0700)] 
Merge tag 'ata-7.0-final' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux

Pull ata fix from Niklas Cassel:

 - Add a quirk for JMicron JMB582/JMB585 AHCI controllers such that
   they only use 32-bit DMA addresses.

   While these controllers do report that they support 64-bit DMA
   addresses, a user reports that using 64-bit DMA addresses cause
   silent corruption even on modern x86 systems (Arthur)

* tag 'ata-7.0-final' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux:
  ata: ahci: force 32-bit DMA for JMicron JMB582/JMB585

2 weeks agoMerge tag 'hyperv-fixes-signed-20260406' of git://git.kernel.org/pub/scm/linux/kernel...
Linus Torvalds [Tue, 7 Apr 2026 17:29:54 +0000 (10:29 -0700)] 
Merge tag 'hyperv-fixes-signed-20260406' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull Hyper-V fixes from Wei Liu:

 - Two fixes for Hyper-V PCI driver (Long Li, Sahil Chandna)

 - Fix an infinite loop issue in MSHV driver (Stanislav Kinsburskii)

* tag 'hyperv-fixes-signed-20260406' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  mshv: Fix infinite fault loop on permission-denied GPA intercepts
  PCI: hv: Fix double ida_free in hv_pci_probe error path
  PCI: hv: Set default NUMA node to 0 for devices without affinity info

2 weeks agoMerge tag 'mm-hotfixes-stable-2026-04-06-15-27' of git://git.kernel.org/pub/scm/linux...
Linus Torvalds [Tue, 7 Apr 2026 17:24:44 +0000 (10:24 -0700)] 
Merge tag 'mm-hotfixes-stable-2026-04-06-15-27' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "Eight hotfixes.  All are cc:stable and seven are for MM.

  All are singletons - please see the changelogs for details"

* tag 'mm-hotfixes-stable-2026-04-06-15-27' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  ocfs2: fix out-of-bounds write in ocfs2_write_end_inline
  mm/damon/stat: deallocate damon_call() failure leaking damon_ctx
  mm/vma: fix memory leak in __mmap_region()
  mm/memory_hotplug: maintain N_NORMAL_MEMORY during hotplug
  mm/damon/sysfs: dealloc repeat_call_control if damon_call() fails
  mm: reinstate unconditional writeback start in balance_dirty_pages()
  liveupdate: propagate file deserialization failures
  mm: filemap: fix nr_pages calculation overflow in filemap_map_pages()

2 weeks agoASoC: amd: ps: fix the pcm device numbering for acp pdm dmic
Syed Saba Kareem [Fri, 3 Apr 2026 10:06:17 +0000 (15:36 +0530)] 
ASoC: amd: ps: fix the pcm device numbering for acp pdm dmic

Fixed PCM device numbering is required for acp pdm dmic pcm device
to have a common UCM changes.
Set the 'use_dai_pcm_id' flag true in acp pdm dma driver for acp 6.3
platform. This will fix the pcm device numbering based on dai_link->id.

Fixes: 33cea6bbe488 ("ASoC: amd: add acp6.2 pdm platform driver")
Signed-off-by: Syed Saba Kareem <Syed.SabaKareem@amd.com>
Fixes: tag.
Link: https://patch.msgid.link/20260403100624.676953-1-syed.sabakareem@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2 weeks agoalarmtimer: Access timerqueue node under lock in suspend
Zhan Xusheng [Tue, 7 Apr 2026 14:36:27 +0000 (22:36 +0800)] 
alarmtimer: Access timerqueue node under lock in suspend

In alarmtimer_suspend(), timerqueue_getnext() is called under
base->lock, but next->expires is read after the lock is released.

This is safe because suspend freezes all relevant task contexts,
but reading the node while holding the lock makes the code easier
to reason about and not worry about a theoretical UAF.

Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260407143627.19405-1-zhanxusheng@xiaomi.com
2 weeks agodt-bindings: arm-smmu: qcom: Add compatible for Hawi SoC
Mukesh Ojha [Fri, 3 Apr 2026 08:09:56 +0000 (13:39 +0530)] 
dt-bindings: arm-smmu: qcom: Add compatible for Hawi SoC

Qualcomm Hawi SoC include apps smmu that implements arm,mmu-500, which
is used to translate device-visible virtual addresses to physical
addresses. Add compatible for these items.

Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Will Deacon <will@kernel.org>
2 weeks agobtrfs: fix double free in create_space_info() error path
Guangshuo Li [Wed, 1 Apr 2026 10:56:19 +0000 (18:56 +0800)] 
btrfs: fix double free in create_space_info() error path

When kobject_init_and_add() fails, the call chain is:

create_space_info()
-> btrfs_sysfs_add_space_info_type()
-> kobject_init_and_add()
-> failure
-> kobject_put(&space_info->kobj)
-> space_info_release()
-> kfree(space_info)

Then control returns to create_space_info():

btrfs_sysfs_add_space_info_type() returns error
-> goto out_free
-> kfree(space_info)

This causes a double free.

Keep the direct kfree(space_info) for the earlier failure path, but
after btrfs_sysfs_add_space_info_type() has called kobject_put(), let
the kobject release callback handle the cleanup.

Fixes: a11224a016d6d ("btrfs: fix memory leaks in create_space_info() error paths")
CC: stable@vger.kernel.org # 6.19+
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: fix double free in create_space_info_sub_group() error path
Guangshuo Li [Wed, 1 Apr 2026 11:02:19 +0000 (19:02 +0800)] 
btrfs: fix double free in create_space_info_sub_group() error path

When kobject_init_and_add() fails, the call chain is:

create_space_info_sub_group()
-> btrfs_sysfs_add_space_info_type()
-> kobject_init_and_add()
-> failure
-> kobject_put(&sub_group->kobj)
-> space_info_release()
-> kfree(sub_group)

Then control returns to create_space_info_sub_group(), where:

btrfs_sysfs_add_space_info_type() returns error
-> kfree(sub_group)

Thus, sub_group is freed twice.

Keep parent->sub_group[index] = NULL for the failure path, but after
btrfs_sysfs_add_space_info_type() has called kobject_put(), let the
kobject release callback handle the cleanup.

Fixes: f92ee31e031c ("btrfs: introduce btrfs_space_info sub-group")
CC: stable@vger.kernel.org # 6.18+
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: do not reject a valid running dev-replace
Qu Wenruo [Tue, 31 Mar 2026 23:02:57 +0000 (09:32 +1030)] 
btrfs: do not reject a valid running dev-replace

[BUG]
There is a bug report that a btrfs with running dev-replace got rejected
with the following messages:

  BTRFS error (device sdk1): devid 0 path /dev/sdk1 is registered but not found in chunk tree
  BTRFS error (device sdk1): remove the above devices or use 'btrfs device scan --forget <dev>' to unregister them before mount
  BTRFS error (device sdk1): open_ctree failed: -117

[CAUSE]
The tree and super block dumps show the fs is completely sane, except
one thing, there is no dev item for devid 0 in chunk tree.

However this is not a bug, as we do not insert dev item for devid 0 in
the first place.
Since the devid 0 is only there temporarily we do not really need to
insert a dev item for it and then later remove it again.

It is the commit 34308187395f ("btrfs: add extra device item checks at
mount") adding a overly strict check that triggers a false alert and
rejected the valid filesystem.

[FIX]
Add a special handling for devid 0, and doesn't require devid 0 to
have a device item in chunk tree.

Reported-by: Jaron Viëtor <jaron@vietors.com>
Link: https://lore.kernel.org/linux-btrfs/CAF1bhLVYLZvD=j2XyuxXDKD-NWNJAwDnpVN+UYeQW-HbzNRn1A@mail.gmail.com/
Fixes: 34308187395f ("btrfs: add extra device item checks at mount")
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: only invalidate btree inode pages after all ebs are released
Qu Wenruo [Mon, 30 Mar 2026 22:21:56 +0000 (08:51 +1030)] 
btrfs: only invalidate btree inode pages after all ebs are released

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>
2 weeks agobtrfs: prevent direct reclaim during compressed readahead
JP Kobryn (Meta) [Sat, 28 Mar 2026 21:46:19 +0000 (14:46 -0700)] 
btrfs: prevent direct reclaim during compressed readahead

Under memory pressure, direct reclaim can kick in during compressed
readahead. This puts the associated task into D-state. Then shrink_lruvec()
disables interrupts when acquiring the LRU lock. Under heavy pressure,
we've observed reclaim can run long enough that the CPU becomes prone to
CSD lock stalls since it cannot service incoming IPIs. Although the CSD
lock stalls are the worst case scenario, we have found many more subtle
occurrences of this latency on the order of seconds, over a minute in some
cases.

Prevent direct reclaim during compressed readahead. This is achieved by
using different GFP flags at key points when the bio is marked for
readahead.

There are two functions that allocate during compressed readahead:
btrfs_alloc_compr_folio() and add_ra_bio_pages(). Both currently use
GFP_NOFS which includes __GFP_DIRECT_RECLAIM.

For the internal API call btrfs_alloc_compr_folio(), the signature changes
to accept an additional gfp_t parameter. At the readahead call site, it
gets flags similar to GFP_NOFS but stripped of __GFP_DIRECT_RECLAIM.
__GFP_NOWARN is added since these allocations are allowed to fail. Demand
reads still use full GFP_NOFS and will enter reclaim if needed. All other
existing call sites of btrfs_alloc_compr_folio() now explicitly pass
GFP_NOFS to retain their current behavior.

add_ra_bio_pages() gains a bool parameter which allows callers to specify
if they want to allow direct reclaim or not. In either case, the
__GFP_NOWARN flag was added unconditionally since the allocations are
speculative.

There has been some previous work done on calling add_ra_bio_pages() [0].
This patch is complementary: where that patch reduces call frequency, this
patch reduces the latency associated with those calls.

[0] https://lore.kernel.org/linux-btrfs/656838ec1232314a2657716e59f4f15a8eadba64.1751492111.git.boris@bur.io/

Reviewed-by: Mark Harmstone <mark@harmstone.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: JP Kobryn (Meta) <jp.kobryn@linux.dev>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: replace BUG_ON() with error return in cache_save_setup()
Teng Liu [Sat, 28 Mar 2026 06:40:59 +0000 (07:40 +0100)] 
btrfs: replace BUG_ON() with error return in cache_save_setup()

In cache_save_setup(), if create_free_space_inode() succeeds but the
subsequent lookup_free_space_inode() still fails on retry, the
BUG_ON(retries) will crash the kernel. This can happen due to I/O
errors or transient failures, not just programming bugs.

Replace the BUG_ON with proper error handling that returns the original
error code through the existing cleanup path. The callers already handle
this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the
space cache simply won't be written for that block group.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Teng Liu <27rabbitlt@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: zstd: don't cache sectorsize in a local variable
David Sterba [Tue, 6 Jan 2026 16:20:34 +0000 (17:20 +0100)] 
btrfs: zstd: don't cache sectorsize in a local variable

The sectorsize is used once or at most twice in the callbacks, no need
to cache it on stack. Minor effect on zstd_compress_folios() where it
saves 8 bytes of stack.

Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: zlib: don't cache sectorsize in a local variable
David Sterba [Tue, 6 Jan 2026 16:20:31 +0000 (17:20 +0100)] 
btrfs: zlib: don't cache sectorsize in a local variable

The sectorsize is used once or at most twice in the callbacks, no need
to cache it on stack.

Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: zlib: drop redundant folio address variable
David Sterba [Tue, 6 Jan 2026 16:20:30 +0000 (17:20 +0100)] 
btrfs: zlib: drop redundant folio address variable

We're caching the current output folio address but it's not really
necessary as we store it in the variable and then pass it to the stream
context. We can read the folio address directly.

Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: lzo: inline read/write length helpers
David Sterba [Tue, 6 Jan 2026 16:20:29 +0000 (17:20 +0100)] 
btrfs: lzo: inline read/write length helpers

The LZO_LEN read/write helpers are supposed to be trivial and we're
duplicating the put/get unaligned helpers so use them directly.

Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: use common eb range validation in read_extent_buffer_to_user_nofault()
David Sterba [Tue, 6 Jan 2026 16:20:28 +0000 (17:20 +0100)] 
btrfs: use common eb range validation in read_extent_buffer_to_user_nofault()

The extent buffer access is checked in other helpers by
check_eb_range(), which validates the requested start, length against
the extent buffer. While this almost never fails we should still handle
it as an error and not just warn.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: read eb folio index right before loops
David Sterba [Tue, 6 Jan 2026 16:20:27 +0000 (17:20 +0100)] 
btrfs: read eb folio index right before loops

There are generic helpers to access extent buffer folio data of any
length, potentially iterating over a few of them. This is a slow path,
either we use the type based accessors or the eb folio allocation is
contiguous and we can use the memcpy/memcmp helpers.

The initialization of 'i' is done at the beginning though it may not be
needed. Move it right before the folio loop, this has minor effect on
generated code in __write_extent_buffer().

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: rename local variable for offset in folio
David Sterba [Tue, 6 Jan 2026 16:20:26 +0000 (17:20 +0100)] 
btrfs: rename local variable for offset in folio

Use proper abbreviation of the 'offset in folio' in the variable name,
same as we have in accessors.c.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: unify types for binary search variables
David Sterba [Tue, 6 Jan 2026 16:20:25 +0000 (17:20 +0100)] 
btrfs: unify types for binary search variables

The variables calculating where to jump next are using mixed in types
which requires some conversions on the instruction level. Using 'u32'
removes one call to 'movslq', making the main loop shorter.

This complements type conversion done in a724f313f84beb ("btrfs: do
unsigned integer division in the extent buffer binary search loop")

Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove duplicate calculation of eb offset in btrfs_bin_search()
David Sterba [Tue, 6 Jan 2026 16:20:24 +0000 (17:20 +0100)] 
btrfs: remove duplicate calculation of eb offset in btrfs_bin_search()

In the main search loop the variable 'oil' (offset in folio) is set
twice, one duplicated when the key fits completely to the contiguous
range. We can remove it and while it's just a simple calculation, the
binary search loop is executed many times so micro optimizations add up.

The code size is reduced by 64 bytes on release config, the loop is
reorganized a bit and a few instructions shorter.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tree-checker: add remap-tree checks to check_block_group_item()
Mark Harmstone [Wed, 25 Mar 2026 12:53:43 +0000 (12:53 +0000)] 
btrfs: tree-checker: add remap-tree checks to check_block_group_item()

Add some write-time checks for block group items relating to the remap
tree.

Here we're checking:

* That the REMAPPED or METADATA_REMAP flags aren't set unless the
  REMAP_TREE incompat flag is also set
* That `remap_bytes` isn't more than the size of the block group
* That `identity_remap_count` isn't more than the number of sectors in
  the block group

Signed-off-by: Mark Harmstone <mark@harmstone.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: make btrfs_free_log() and btrfs_free_log_root_tree() return void
Filipe Manana [Tue, 24 Mar 2026 15:01:34 +0000 (15:01 +0000)] 
btrfs: make btrfs_free_log() and btrfs_free_log_root_tree() return void

These functions never fail, always return success (0) and none of the
callers care about their return values. Change their return type from int
to void.

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>
2 weeks agobtrfs: fix deadlock between reflink and transaction commit when using flushoncommit
Filipe Manana [Mon, 23 Mar 2026 15:50:13 +0000 (15:50 +0000)] 
btrfs: fix deadlock between reflink and transaction commit when using flushoncommit

When using the flushoncommit mount option, we can have a deadlock between
a transaction commit and a reflink operation that copied an inline extent
to an offset beyond the current i_size of the destination node.

The deadlock happens like this:

1) Task A clones an inline extent from inode X to an offset of inode Y
   that is beyond Y's current i_size. This means we copied the inline
   extent's data to a folio of inode Y that is beyond its EOF, using a
   call to copy_inline_to_page();

2) Task B starts a transaction commit and calls
   btrfs_start_delalloc_flush() to flush delalloc;

3) The delalloc flushing sees the new dirty folio of inode Y and when it
   attempts to flush it, it ends up at extent_writepage() and sees that
   the offset of the folio is beyond the i_size of inode Y, so it attempts
   to invalidate the folio by calling folio_invalidate(), which ends up at
   btrfs' folio invalidate callback - btrfs_invalidate_folio(). There it
   tries to lock the folio's range in inode Y's extent io tree, but it
   blocks since it's currently locked by task A - during a reflink we lock
   the inodes and the source and destination ranges after flushing all
   delalloc and waiting for ordered extent completion - after that we
   don't expect to have dirty folios in the ranges, the exception is if
   we have to copy an inline extent's data (because the destination offset
   is not zero);

4) Task A then attempts to start a transaction to update the inode item,
   and then it's blocked since the current transaction is in the
   TRANS_STATE_COMMIT_START state. Therefore task A has to wait for the
   current transaction to become unblocked (its state >=
   TRANS_STATE_UNBLOCKED).

   So task A is waiting for the transaction commit done by task B, and
   the later waiting on the extent lock of inode Y that is currently
   held by task A.

Syzbot recently reported this with the following stack traces:

  INFO: task kworker/u8:7:1053 blocked for more than 143 seconds.
        Not tainted syzkaller #0
  "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
  task:kworker/u8:7    state:D stack:23520 pid:1053  tgid:1053  ppid:2      task_flags:0x4208060 flags:0x00080000
  Workqueue: writeback wb_workfn (flush-btrfs-46)
  Call Trace:
   <TASK>
   context_switch kernel/sched/core.c:5298 [inline]
   __schedule+0x1553/0x5240 kernel/sched/core.c:6911
   __schedule_loop kernel/sched/core.c:6993 [inline]
   schedule+0x164/0x360 kernel/sched/core.c:7008
   wait_extent_bit fs/btrfs/extent-io-tree.c:811 [inline]
   btrfs_lock_extent_bits+0x59c/0x700 fs/btrfs/extent-io-tree.c:1914
   btrfs_lock_extent fs/btrfs/extent-io-tree.h:152 [inline]
   btrfs_invalidate_folio+0x43d/0xc40 fs/btrfs/inode.c:7704
   extent_writepage fs/btrfs/extent_io.c:1852 [inline]
   extent_write_cache_pages fs/btrfs/extent_io.c:2580 [inline]
   btrfs_writepages+0x12ff/0x2440 fs/btrfs/extent_io.c:2713
   do_writepages+0x32e/0x550 mm/page-writeback.c:2554
   __writeback_single_inode+0x133/0x11a0 fs/fs-writeback.c:1750
   writeback_sb_inodes+0x995/0x19d0 fs/fs-writeback.c:2042
   wb_writeback+0x456/0xb70 fs/fs-writeback.c:2227
   wb_do_writeback fs/fs-writeback.c:2374 [inline]
   wb_workfn+0x41a/0xf60 fs/fs-writeback.c:2414
   process_one_work kernel/workqueue.c:3276 [inline]
   process_scheduled_works+0xb6e/0x18c0 kernel/workqueue.c:3359
   worker_thread+0xa53/0xfc0 kernel/workqueue.c:3440
   kthread+0x388/0x470 kernel/kthread.c:436
   ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
   ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
   </TASK>
  INFO: task syz.4.64:6910 blocked for more than 143 seconds.
        Not tainted syzkaller #0
  "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
  task:syz.4.64        state:D stack:22752 pid:6910  tgid:6905  ppid:5944   task_flags:0x400140 flags:0x00080002
  Call Trace:
   <TASK>
   context_switch kernel/sched/core.c:5298 [inline]
   __schedule+0x1553/0x5240 kernel/sched/core.c:6911
   __schedule_loop kernel/sched/core.c:6993 [inline]
   schedule+0x164/0x360 kernel/sched/core.c:7008
   wait_current_trans+0x39f/0x590 fs/btrfs/transaction.c:535
   start_transaction+0x6a7/0x1650 fs/btrfs/transaction.c:705
   clone_copy_inline_extent fs/btrfs/reflink.c:299 [inline]
   btrfs_clone+0x128a/0x24d0 fs/btrfs/reflink.c:529
   btrfs_clone_files+0x271/0x3f0 fs/btrfs/reflink.c:750
   btrfs_remap_file_range+0x76b/0x1320 fs/btrfs/reflink.c:903
   vfs_copy_file_range+0xda7/0x1390 fs/read_write.c:1600
   __do_sys_copy_file_range fs/read_write.c:1683 [inline]
   __se_sys_copy_file_range+0x2fb/0x480 fs/read_write.c:1650
   do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
   do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
   entry_SYSCALL_64_after_hwframe+0x77/0x7f
  RIP: 0033:0x7f5f73afc799
  RSP: 002b:00007f5f7315e028 EFLAGS: 00000246 ORIG_RAX: 0000000000000146
  RAX: ffffffffffffffda RBX: 00007f5f73d75fa0 RCX: 00007f5f73afc799
  RDX: 0000000000000005 RSI: 0000000000000000 RDI: 0000000000000005
  RBP: 00007f5f73b92c99 R08: 0000000000000863 R09: 0000000000000000
  R10: 00002000000000c0 R11: 0000000000000246 R12: 0000000000000000
  R13: 00007f5f73d76038 R14: 00007f5f73d75fa0 R15: 00007fff138a5068
   </TASK>
  INFO: task syz.4.64:6975 blocked for more than 143 seconds.
        Not tainted syzkaller #0
  "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
  task:syz.4.64        state:D stack:24736 pid:6975  tgid:6905  ppid:5944   task_flags:0x400040 flags:0x00080002
  Call Trace:
   <TASK>
   context_switch kernel/sched/core.c:5298 [inline]
   __schedule+0x1553/0x5240 kernel/sched/core.c:6911
   __schedule_loop kernel/sched/core.c:6993 [inline]
   schedule+0x164/0x360 kernel/sched/core.c:7008
   wb_wait_for_completion+0x3e8/0x790 fs/fs-writeback.c:227
   __writeback_inodes_sb_nr+0x24c/0x2d0 fs/fs-writeback.c:2838
   try_to_writeback_inodes_sb+0x9a/0xc0 fs/fs-writeback.c:2886
   btrfs_start_delalloc_flush fs/btrfs/transaction.c:2175 [inline]
   btrfs_commit_transaction+0x82e/0x31a0 fs/btrfs/transaction.c:2364
   btrfs_ioctl+0xca7/0xd00 fs/btrfs/ioctl.c:5206
   vfs_ioctl fs/ioctl.c:51 [inline]
   __do_sys_ioctl fs/ioctl.c:597 [inline]
   __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
   do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
   do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
   entry_SYSCALL_64_after_hwframe+0x77/0x7f
  RIP: 0033:0x7f5f73afc799
  RSP: 002b:00007f5f7313d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
  RAX: ffffffffffffffda RBX: 00007f5f73d76090 RCX: 00007f5f73afc799
  RDX: 0000000000000000 RSI: 0000000000009408 RDI: 0000000000000004
  RBP: 00007f5f73b92c99 R08: 0000000000000000 R09: 0000000000000000
  R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
  R13: 00007f5f73d76128 R14: 00007f5f73d76090 R15: 00007fff138a5068
   </TASK>

Fix this by updating the i_size of the destination inode of a reflink
operation after we copy an inline extent's data to an offset beyond the
i_size and before attempting to start a transaction to update the inode's
item.

Reported-by: syzbot+63056bf627663701bbbf@syzkaller.appspotmail.com
Link: https://lore.kernel.org/linux-btrfs/69bba3fe.050a0220.227207.002f.GAE@google.com/
Fixes: 05a5a7621ce6 ("Btrfs: implement full reflink support for inline extents")
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tree-checker: check remap-tree flags in btrfs_check_chunk_valid()
Mark Harmstone [Wed, 4 Mar 2026 12:02:10 +0000 (12:02 +0000)] 
btrfs: tree-checker: check remap-tree flags in btrfs_check_chunk_valid()

Add a check to btrfs_check_chunk_valid() that the METADATA_REMAP and
REMAPPED flags are only set if the REMAP_TREE incompat flag is also set.

Signed-off-by: Mark Harmstone <mark@harmstone.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tree-checker: add checker for items in remap tree
Mark Harmstone [Tue, 3 Mar 2026 15:59:12 +0000 (15:59 +0000)] 
btrfs: tree-checker: add checker for items in remap tree

Add write-time checking of items in the remap tree, to catch errors
before they are written to disk.

We're checking:

* That remap items, remap backrefs, and identity remaps aren't written
  unless the REMAP_TREE incompat flag is set
* That identity remaps have a size of 0
* That remap items and remap backrefs have a size of sizeof(struct
  btrfs_remap_item)
* That the objectid for these items is aligned to the sector size
* That the offset for these items (i.e. the size of the remapping) isn't
  0 and is aligned to the sector size
* That objectid + offset doesn't overflow

Signed-off-by: Mark Harmstone <mark@harmstone.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: fix unnecessary flush on close when truncating zero-sized files
Dave Chen [Mon, 23 Mar 2026 03:43:22 +0000 (11:43 +0800)] 
btrfs: fix unnecessary flush on close when truncating zero-sized files

In btrfs_setsize(), when a file is truncated to size 0, the
BTRFS_INODE_FLUSH_ON_CLOSE flag is unconditionally set to ensure
pending writes get flushed on close. This flag was designed to protect
the "truncate-then-rewrite" pattern, where an application truncates a
file with existing data down to zero and writes new content, ensuring
the new data reach disk on close.

However, when a file already has a size of 0 (e.g. a newly created
file opened with O_CREAT | O_TRUNC), oldsize and newsize are both 0.
In this case, setting BTRFS_INODE_FLUSH_ON_CLOSE is unnecessary because
no "good data" was truncated away. The subsequent filemap_flush() in
btrfs_release_file() then triggers avoidable writeback that disrupts
the normal delayed writeback batching, adding I/O overhead.

This comes from a real workload. A backup service creates temporary
files via mkstemp(), closes them, and later reopens them with O_TRUNC
for writing. The O_TRUNC is defensive.  The file creation and usage is
done by a different component, so removing the unneeded truncation is
not straightforward.  This pattern repeats for a large number of files
each close() triggers an unnecessary filemap_flush().

Signed-off-by: Dave Chen <davechen@synology.com>
Signed-off-by: Robbie Ko <robbieko@synology.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: move shutdown and remove_bdev callbacks out of experimental features
Qu Wenruo [Fri, 27 Feb 2026 03:33:44 +0000 (14:03 +1030)] 
btrfs: move shutdown and remove_bdev callbacks out of experimental features

These two new callbacks have been introduced in v6.19, and it has been
two releases in v7.1.

During that time we have not yet exposed bugs related that two features,
thus it's time to expose them for end users.

It's especially important to expose remove_bdev callback to end users.

That new callback makes btrfs automatically shutdown or go degraded
when a device is missing (depending on if the fs can maintain RW), which
is affecting end users.

We want some feedback from early adopters.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
Yochai Eisenrich [Sun, 22 Mar 2026 06:39:35 +0000 (08:39 +0200)] 
btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
block group RAID type lists. The first pass counts entries to determine
the allocation size, then the second pass fills the buffer. The
groups_sem rwlock is released between passes, allowing concurrent block
group removal to reduce the entry count.

When the second pass fills fewer entries than the first pass counted,
copy_to_user() copies the full alloc_size bytes including trailing
uninitialized kmalloc bytes to userspace.

Fix by copying only total_spaces entries (the actually-filled count from
the second pass) instead of alloc_size bytes, and switch to kzalloc so
any future copy size mismatch cannot leak heap data.

Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl")
CC: stable@vger.kernel.org # 3.0
Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: avoid taking the device_list_mutex in btrfs_run_dev_stats()
Filipe Manana [Wed, 18 Mar 2026 13:39:51 +0000 (13:39 +0000)] 
btrfs: avoid taking the device_list_mutex in btrfs_run_dev_stats()

btrfs_run_dev_stats() is called during the critical section of a
transaction commit and it takes the device_list_mutex, which is also
acquired by fitrim, which does discard operations while holding that
mutex. Most of the time, if we are on a healthy filesystem, we don't have
new stat updates to persist in the device tree, so blocking on the
device_list_mutex is just wasting time and making any tasks that need to
start a new transaction wait longer that necessary.

Since the device list is RCU safe/protected, make btrfs_run_dev_stats()
do an initial check for device stat updates using RCU and quit without
taking the device_list_mutex in case there are no new device stats that
need to be persisted in the device tree.

Also note that adding/removing devices also requires starting a
transaction, and since btrfs_run_dev_stats() is called from the critical
section of a transaction commit, no one can be concurrently adding or
removing a device while btrfs_run_dev_stats() is called.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: avoid GFP_ATOMIC allocations in qgroup free paths
Leo Martins [Thu, 19 Mar 2026 23:49:08 +0000 (16:49 -0700)] 
btrfs: avoid GFP_ATOMIC allocations in qgroup free paths

When qgroups are enabled, __btrfs_qgroup_release_data() and
qgroup_free_reserved_data() pass an extent_changeset to
btrfs_clear_record_extent_bits() to track how many bytes had their
EXTENT_QGROUP_RESERVED bits cleared. Inside the extent IO tree spinlock,
add_extent_changeset() calls ulist_add() with GFP_ATOMIC to record each
changed range. If this allocation fails, it hits a BUG_ON and panics the
kernel.

However, both of these callers only read changeset.bytes_changed
afterwards — the range_changed ulist is populated and immediately freed
without ever being iterated. The GFP_ATOMIC allocation is entirely
unnecessary for these paths.

Introduce extent_changeset_init_bytes_only() which uses a sentinel value
(EXTENT_CHANGESET_BYTES_ONLY) on the ulist's prealloc field to signal
that only bytes_changed should be tracked. add_extent_changeset() checks
for this sentinel and returns early after updating bytes_changed,
skipping the ulist_add() call entirely. This eliminates the GFP_ATOMIC
allocation and makes the BUG_ON unreachable for these paths.

Callers that need range tracking (qgroup_reserve_data,
qgroup_unreserve_range, btrfs_qgroup_check_reserved_leak) continue to
use extent_changeset_init() and are unaffected.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Leo Martins <loemra.dev@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: decrease indentation of find_free_extent_update_loop
Johannes Thumshirn [Wed, 18 Mar 2026 07:17:00 +0000 (08:17 +0100)] 
btrfs: decrease indentation of find_free_extent_update_loop

Decrease the indentation of find_free_extent_update_loop(), by inverting
the check if the loop state is smaller than LOOP_NO_EMPTY_SIZE.

This also allows for an early return from find_free_extent_update_loop(),
in case LOOP_NO_EMPTY_SIZE is already set at this point.

While at it change a

    if () {
    }
    else if
    else

pattern to all using curly braces and be consistent with the rest of btrfs
code.

Also change 'int exists' to 'bool have_trans' giving it a more meaningful
name and type.

No functional changes intended.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: unexport btrfs_qgroup_reserve_meta()
Filipe Manana [Tue, 17 Mar 2026 19:35:58 +0000 (19:35 +0000)] 
btrfs: unexport btrfs_qgroup_reserve_meta()

There's only one caller outside qgroup.c of btrfs_qgroup_reserve_meta()
and we have btrfs_qgroup_reserve_meta_prealloc() is a wrapper around
that function. Make that caller use btrfs_qgroup_reserve_meta_prealloc()
and unexport btrfs_qgroup_reserve_meta(), simplifying the external API.

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>
2 weeks agobtrfs: collapse __btrfs_qgroup_reserve_meta() into btrfs_qgroup_reserve_meta_prealloc()
Filipe Manana [Tue, 17 Mar 2026 19:19:43 +0000 (19:19 +0000)] 
btrfs: collapse __btrfs_qgroup_reserve_meta() into btrfs_qgroup_reserve_meta_prealloc()

Since __btrfs_qgroup_reserve_meta() is only called by
btrfs_qgroup_reserve_meta_prealloc(), which is a simple inline wrapper,
get rid of the later and rename __btrfs_qgroup_reserve_meta() to the
later.

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>
2 weeks agobtrfs: collapse __btrfs_qgroup_free_meta() into btrfs_qgroup_free_meta_prealloc()
Filipe Manana [Tue, 17 Mar 2026 19:09:15 +0000 (19:09 +0000)] 
btrfs: collapse __btrfs_qgroup_free_meta() into btrfs_qgroup_free_meta_prealloc()

Since __btrfs_qgroup_free_meta() is only called by
btrfs_qgroup_free_meta_prealloc(), which is a simple inline wrapper, get
rid of the later and rename __btrfs_qgroup_free_meta() to the later.

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>
2 weeks agobtrfs: remove unused qgroup functions for pertrans reservation and freeing
Filipe Manana [Tue, 17 Mar 2026 18:54:04 +0000 (18:54 +0000)] 
btrfs: remove unused qgroup functions for pertrans reservation and freeing

They have no more users since commit a6496849671a ("btrfs: fix start
transaction qgroup rsv double free"), so remove them.

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>
2 weeks agobtrfs: optimize clearing all bits from first extent record in an io tree
Filipe Manana [Wed, 11 Mar 2026 18:36:36 +0000 (18:36 +0000)] 
btrfs: optimize clearing all bits from first extent record in an io tree

When we are clearing all the bits from the first record that contains the
target range and that record ends at or before our target range but starts
before our target range, we are doing a lot of unnecessary work:

1) Allocating a prealloc state if we don't have one already;

2) Adjust that record's start offset to the start of our range and
   make the prealloc state have a range going from the original start
   offset of that first record to the start offset of our target range,
   and with the same bits as that first record. Then we insert the
   prealloc extent in the rbtree - this is done in split_state();

3) Remove our adjusted first state from the rbtree since all the bits
   were cleared - this is done in clear_state_bit().

This is only wasting time when we can simply trim that first record, so
that it represents the range from its start offset to the start offset of
our target range. So optimize for that case and avoid the prealloc state
allocation, insertion and deletion from the rbtree.

This patch is the last patch of a patchset comprised of the following
patches (in descending order):

  btrfs: optimize clearing all bits from first extent record in an io tree
  btrfs: panic instead of warn when splitting extent state not in the tree
  btrfs: free cached state outside critical section in wait_extent_bit()
  btrfs: avoid unnecessary wake ups on io trees when there are no waiters
  btrfs: remove wake parameter from clear_state_bit()
  btrfs: change last argument of add_extent_changeset() to boolean
  btrfs: use extent_io_tree_panic() instead of BUG_ON()
  btrfs: make add_extent_changeset() only return errors or success
  btrfs: tag as unlikely branches that call extent_io_tree_panic()
  btrfs: turn extent_io_tree_panic() into a macro for better error reporting
  btrfs: optimize clearing all bits from the last extent record in an io tree

The following fio script was used to measure performance before and after
applying all the patches:

  $ cat ./fio-io-uring-2.sh
  #!/bin/bash

  DEV=/dev/nullb0
  MNT=/mnt/nullb0
  MOUNT_OPTIONS="-o ssd"
  MKFS_OPTIONS=""

  if [ $# -ne 3 ]; then
      echo "Use $0 NUM_JOBS FILE_SIZE RUN_TIME"
      exit 1
  fi

  NUM_JOBS=$1
  FILE_SIZE=$2
  RUN_TIME=$3

  cat <<EOF > /tmp/fio-job.ini
  [io_uring_rw]
  rw=randwrite
  fsync=0
  fallocate=none
  group_reporting=1
  direct=1
  ioengine=io_uring
  fixedbufs=1
  iodepth=64
  bs=4K
  filesize=$FILE_SIZE
  runtime=$RUN_TIME
  time_based
  filename=foobar
  directory=$MNT
  numjobs=$NUM_JOBS
  thread
  EOF

  echo performance | \
      tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

  echo
  echo "Using config:"
  echo
  cat /tmp/fio-job.ini
  echo

  umount $MNT &> /dev/null
  mkfs.btrfs -f $MKFS_OPTIONS $DEV &> /dev/null
  mount $MOUNT_OPTIONS $DEV $MNT

  fio /tmp/fio-job.ini

  umount $MNT

When running this script on a 12 cores machine using a 16G null block
device the results were the following:

Before patchset:

  $ ./fio-io-uring-2.sh 12 8G 60
  (...)
  WRITE: bw=74.8MiB/s (78.5MB/s), 74.8MiB/s-74.8MiB/s (78.5MB/s-78.5MB/s), io=4504MiB (4723MB), run=60197-60197msec

After patchset:

  $ ./fio-io-uring-2.sh 12 8G 60
  (...)
  WRITE: bw=82.2MiB/s (86.2MB/s), 82.2MiB/s-82.2MiB/s (86.2MB/s-86.2MB/s), io=4937MiB (5176MB), run=60027-60027msec

Also, using bpftrace to collect the duration (in nanoseconds) of all the
btrfs_clear_extent_bit_changeset() calls done during that fio test and
then making an histogram from that data, held the following results:

Before patchset:

  Count: 6304804
  Range:  0.000 - 7587172.000; Mean: 2011.308; Median: 1219.000; Stddev: 17117.533
  Percentiles:  90th: 1888.000; 95th: 2189.000; 99th: 16104.000
        0.000 -    8.098:        7 |
        8.098 -   40.385:       20 |
       40.385 -  187.254:      146 |
      187.254 -  855.347:   742048 #######
      855.347 - 3894.426:  5462542 #####################################################
     3894.426 - 17718.848:   41489 |
    17718.848 - 80604.558:   46085 |
    80604.558 - 366664.449:  11285 |
   366664.449 - 1667918.122:   961 |
  1667918.122 - 7587172.000:   113 |

After patchset:

  Count: 6282879
  Range:  0.000 - 6029290.000; Mean: 1896.482; Median: 1126.000; Stddev: 15276.691
  Percentiles:  90th: 1741.000; 95th: 2026.000; 99th: 15713.000
        0.000 - 60.014:         12 |
       60.014 - 217.984:        63 |
      217.984 - 784.949:    517515 #####
      784.949 - 2819.823:  5632335 #####################################################
     2819.823 - 10123.127:   55716 #
    10123.127 - 36335.184:   46034 |
    36335.184 - 130412.049:  25708 |
   130412.049 - 468060.350:   4824 |
   468060.350 - 1679903.189:   549 |
  1679903.189 - 6029290.000:    84 |

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: panic instead of warn when splitting extent state not in the tree
Filipe Manana [Wed, 11 Mar 2026 16:15:59 +0000 (16:15 +0000)] 
btrfs: panic instead of warn when splitting extent state not in the tree

We are not expected ever to split an extent state record that is not in
the rbtree, as every record we pass to split_state() was found by
iterating the rbtree, so if that ever happens it means we are not holding
the extent io tree's spinlock or we have some memory corruption.

Instead of simply warning in case the extent state record passed to
split_state() is not in the rbtree, panic as this is a serious problem.
Also tag as unlikely the case where the record is not in the rbtree.

This also makes a tiny reduction the btrfs module's text size.

Before:

  $ size fs/btrfs/btrfs.ko
     text    data     bss     dec     hex filename
  2000080  174328   15592 2190000  216ab0 fs/btrfs/btrfs.ko

After:

  $ size fs/btrfs/btrfs.ko
     text    data     bss     dec     hex filename
  2000064  174328   15592 2189984  216aa0 fs/btrfs/btrfs.ko

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: free cached state outside critical section in wait_extent_bit()
Filipe Manana [Mon, 16 Mar 2026 11:38:36 +0000 (11:38 +0000)] 
btrfs: free cached state outside critical section in wait_extent_bit()

There's no need to free the cached extent state record while holding the
io tree's spinlock, it's just making the critical section longer than it
needs to be. So just do it after unlocking the io tree.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: avoid unnecessary wake ups on io trees when there are no waiters
Filipe Manana [Wed, 11 Mar 2026 15:07:11 +0000 (15:07 +0000)] 
btrfs: avoid unnecessary wake ups on io trees when there are no waiters

Whenever clearing the extent lock bits of an extent state record, we
unconditionally call wake_up() on the state's waitqueue. Most of the
time there are no waiters on the queue so we are just wasting time calling
wake_up(), since that requires locking and unlocking the queue's spinlock,
disable and re-enable interrupts, function calls, and other minor overhead
while we are holding a critical section delimited by the extent io tree's
spinlock.

So call wake_up() only if there are waiters on an extent state's wait
queue.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove wake parameter from clear_state_bit()
Filipe Manana [Wed, 11 Mar 2026 12:50:03 +0000 (12:50 +0000)] 
btrfs: remove wake parameter from clear_state_bit()

There's no need to pass the 'wake' parameter, we can determine if we have
to wake up waiters by checking if EXTENT_LOCK_BITS is set in the bits to
clear. So simplify things and remove the parameter.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: change last argument of add_extent_changeset() to boolean
Filipe Manana [Wed, 11 Mar 2026 12:43:57 +0000 (12:43 +0000)] 
btrfs: change last argument of add_extent_changeset() to boolean

The argument is used as a boolean but it's defined as an integer.
Switch it to a boolean for better readability.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: use extent_io_tree_panic() instead of BUG_ON()
Filipe Manana [Wed, 11 Mar 2026 12:35:33 +0000 (12:35 +0000)] 
btrfs: use extent_io_tree_panic() instead of BUG_ON()

There's no need to call BUG_ON(), instead call extent_io_tree_panic(),
which also calls BUG(), but it prints an additional error message with
some useful information before hitting BUG().

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: make add_extent_changeset() only return errors or success
Filipe Manana [Wed, 11 Mar 2026 12:17:03 +0000 (12:17 +0000)] 
btrfs: make add_extent_changeset() only return errors or success

Currently add_extent_changeset() always returns the return value from its
call to ulist_add(), which can return an error, 0 or 1. There are no
callers that care about the difference between 0 and 1 and all except one
of them, check for negative values and ignore other values, but there is
another caller (btrfs_clear_extent_bit_changeset()) that must set its
'ret' variable to 0 after calling add_extent_changeset(), so that it
does not return an unexpected value of 1 to its caller.

So change add_extent_changeset() to only return errors or 0, avoiding
that caller (and any future callers) from having to deal with a return
value of 1.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tag as unlikely branches that call extent_io_tree_panic()
Filipe Manana [Wed, 11 Mar 2026 12:07:03 +0000 (12:07 +0000)] 
btrfs: tag as unlikely branches that call extent_io_tree_panic()

It's unexpected to ever call extent_io_tree_panic() so surround with
'unlikely' every if statement condition that leads to it, making it
explicit to a reader and to hint the compiler to potentially generate
better code.

On x86_64, using gcc 14.2.0-19 from Debian, this resulted in a slightly
decrease of the btrfs module's text size.

Before:

  $ size fs/btrfs/btrfs.ko
     text    data     bss     dec     hex filename
  1999832  174320   15592 2189744  2169b0 fs/btrfs/btrfs.ko

After:

  $ size fs/btrfs/btrfs.ko
     text    data     bss     dec     hex filename
  1999768  174320   15592 2189680  216970 fs/btrfs/btrfs.ko

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: turn extent_io_tree_panic() into a macro for better error reporting
Filipe Manana [Wed, 11 Mar 2026 12:00:31 +0000 (12:00 +0000)] 
btrfs: turn extent_io_tree_panic() into a macro for better error reporting

When extent_io_tree_panic() is called we get a stace trace that is not
very useful since the error message reports the location inside the
extent_io_tree_panic() function and not in the caller of the function.

Example:

  [ 7830.424291] BTRFS critical (device sdb): panic in extent_io_tree_panic:334: extent io tree error on add_extent_changeset state start 4083712 end 4112383 (errno=1 unknown)
  [ 7830.426816] ------------[ cut here ]------------
  [ 7830.427581] kernel BUG at fs/btrfs/extent-io-tree.c:334!
  [ 7830.428495] Oops: invalid opcode: 0000 [#1] SMP PTI
  [ 7830.429318] CPU: 5 UID: 0 PID: 1451600 Comm: fsstress Not tainted 7.0.0-rc2-btrfs-next-227+ #1 PREEMPT(full)
  [ 7830.430899] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
  [ 7830.432771] RIP: 0010:extent_io_tree_panic+0x41/0x43 [btrfs]
  [ 7830.433815] Code: 75 0a 48 8b (...)
  [ 7830.436849] RSP: 0018:ffffd2334f4a3b68 EFLAGS: 00010246
  [ 7830.437668] RAX: 0000000000000000 RBX: 00000000003ebfff RCX: 0000000000000000
  [ 7830.438801] RDX: ffffffffc08d4368 RSI: ffffffffbb6ce475 RDI: ffff896501d6b780
  [ 7830.439671] RBP: 0000000000001000 R08: 0000000000000000 R09: 00000000ffefffff
  [ 7830.440575] R10: 0000000000000000 R11: 0000000000000003 R12: 0000000000000000
  [ 7830.441458] R13: ffff896547374c08 R14: 00000000003effff R15: ffff896547374c08
  [ 7830.442333] FS:  00007f3e252af0c0(0000) GS:ffff896c6185d000(0000) knlGS:0000000000000000
  [ 7830.443326] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  [ 7830.444047] CR2: 00007f3e252ad000 CR3: 0000000113b0a004 CR4: 0000000000370ef0
  [ 7830.444905] Call Trace:
  [ 7830.445229]  <TASK>
  [ 7830.445557]  btrfs_clear_extent_bit_changeset.cold+0x43/0x80 [btrfs]
  [ 7830.446543]  btrfs_clear_record_extent_bits+0x19/0x20 [btrfs]
  [ 7830.447308]  qgroup_free_reserved_data+0xf9/0x170 [btrfs]
  [ 7830.448040]  btrfs_buffered_write+0x368/0x8e0 [btrfs]
  [ 7830.448707]  btrfs_direct_write+0x1a5/0x480 [btrfs]
  [ 7830.449396]  btrfs_do_write_iter+0x18c/0x210 [btrfs]
  [ 7830.450167]  vfs_write+0x21f/0x450
  [ 7830.450662]  ksys_write+0x5f/0xd0
  [ 7830.451092]  do_syscall_64+0xe9/0xf20
  [ 7830.451610]  entry_SYSCALL_64_after_hwframe+0x76/0x7e

Change extent_io_tree_panic() to a macro so that we get a report that
gives the exact place where the error happens.

Example after this change:

  [63677.406061] BTRFS critical (device sdc): panic in btrfs_clear_extent_bit_changeset:744: extent io tree error on add_extent_changeset state start 1818624 end 1830911 (errno=1 unknown)
  [63677.410055] ------------[ cut here ]------------
  [63677.410910] kernel BUG at fs/btrfs/extent-io-tree.c:744!
  [63677.411918] Oops: invalid opcode: 0000 [#1] SMP PTI
  [63677.413032] CPU: 0 UID: 0 PID: 13028 Comm: fsstress Not tainted 7.0.0-rc2-btrfs-next-227+ #1 PREEMPT(full)
  [63677.415139] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
  [63677.417283] RIP: 0010:btrfs_clear_extent_bit_changeset.cold+0xcd/0x10c [btrfs]
  [63677.418676] Code: 8b 37 48 8b (...)
  [63677.421917] RSP: 0018:ffffd2290a417b30 EFLAGS: 00010246
  [63677.422824] RAX: 0000000000000000 RBX: 00000000001befff RCX: 0000000000000000
  [63677.424320] RDX: ffffffffc0970348 RSI: ffffffffa92ce475 RDI: ffff8897ded9dc80
  [63677.429772] RBP: 0000000000001000 R08: 0000000000000000 R09: 00000000ffefffff
  [63677.430787] R10: 0000000000000000 R11: 0000000000000003 R12: 0000000000000000
  [63677.431818] R13: ffff8897966655d8 R14: 00000000001bffff R15: ffff8897966655d8
  [63677.432764] FS:  00007f5c074c50c0(0000) GS:ffff889ef3b1d000(0000) knlGS:0000000000000000
  [63677.433940] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  [63677.434787] CR2: 00007f5c074c3000 CR3: 000000014b9de002 CR4: 0000000000370ef0
  [63677.435960] Call Trace:
  [63677.436432]  <TASK>
  [63677.436838]  btrfs_clear_record_extent_bits+0x19/0x20 [btrfs]
  [63677.437980]  qgroup_free_reserved_data+0xf9/0x170 [btrfs]
  [63677.439070]  btrfs_buffered_write+0x368/0x8e0 [btrfs]
  [63677.439889]  btrfs_do_write_iter+0x1a8/0x210 [btrfs]
  [63677.441460]  do_iter_readv_writev+0x145/0x240
  [63677.446309]  vfs_writev+0x120/0x3b0
  [63677.446878]  ? __do_sys_newfstat+0x33/0x60
  [63677.447759]  ? do_pwritev+0x8a/0xd0
  [63677.449119]  do_pwritev+0x8a/0xd0
  [63677.452342]  do_syscall_64+0xe9/0xf20
  [63677.452961]  entry_SYSCALL_64_after_hwframe+0x76/0x7e

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: optimize clearing all bits from the last extent record in an io tree
Filipe Manana [Tue, 10 Mar 2026 15:29:33 +0000 (15:29 +0000)] 
btrfs: optimize clearing all bits from the last extent record in an io tree

When we are clearing all the bits from the last record that contains the
target range (i.e. the record starts before our target range and ends
beyond it), we are doing a lot of unnecessary work:

1) Allocating a prealloc state if we don't have one already;

2) Adjust that last record's start offset to the end of our range and
   make the prealloc state have a range going from the original start
   offset of that last record to the end offset of our target range and
   the same bits as the last record. Then we insert the prealloc extent
   in the rbtree - this is done in split_state();

3) Remove our prealloc state from the rbtree since all the bits were
   cleared - this is done in clear_state_bit().

This is only wasting time when we can simply trim the last record so
that it's start offset is adjust to the end of the target range. So
optimize for that case and avoid the prealloc state allocation, insertion
and deletion from the rbtree.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove atomic parameter from btrfs_buffer_uptodate()
Qu Wenruo [Sun, 15 Mar 2026 21:38:24 +0000 (08:08 +1030)] 
btrfs: remove atomic parameter from btrfs_buffer_uptodate()

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>
2 weeks agobtrfs: output more info when duplicated ordered extent is found
Qu Wenruo [Sat, 14 Mar 2026 00:00:39 +0000 (10:30 +1030)] 
btrfs: output more info when duplicated ordered extent is found

During development of a new feature, I triggered that btrfs_panic()
inside insert_ordered_extent() and spent quite some unnecessary before
noticing I'm passing incorrect flags when creating a new ordered extent.

Unfortunately the existing error message is not providing much help.

Enhance the output to provide file offset, num bytes and flags of both
existing and new ordered extents.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: check type flags in alloc_ordered_extent()
Qu Wenruo [Sat, 14 Mar 2026 00:00:38 +0000 (10:30 +1030)] 
btrfs: check type flags in alloc_ordered_extent()

Unlike other flags used in btrfs, BTRFS_ORDERED_* macros are different as
they cannot be directly used as flags.

They are defined as bit values, thus they should be utilized with
bit operations, not directly with logical operations.

Unfortunately sometimes I forgot this and passed the incorrect flags
to alloc_ordered_extent() and hit weird bugs.

Enhance the type checks in alloc_ordered_extent():

- Make sure there is one and only one bit set for exclusive type flags
  There are four exclusive type flags, REGULAR, NOCOW, PREALLOC and
  COMPRESSED.
  So introduce a new macro, BTRFS_ORDERED_EXCLUSIVE_FLAGS, to cover
  above flags.

  Add an ASSERT() to check one and only one of those exclusive flags can
  be set for alloc_ordered_extent().

- Re-order the type bit numbers to the end of the enum
  This is make it much harder to get a valid false negative.

  E.g., with the old code BTRFS_ORDERED_REGULAR starts at zero, we can
  have the following flags passing the bit uniqueness check:

  * BTRFS_ORDERED_NOCOW
    Be treated as BTRFS_ORDERED_REGULAR (1 == 1UL << 0).

  * BTRFS_ORDERED_PREALLOC
    Be treated as BTRFS_ORDERED_NOCOW (2 == 1UL << 1).

  * BTRFS_ORDERED_DIRECT
    Be treated as BTRFS_ORDERED_PREALLOC (4 == 1UL << 2).

  Now all those types start at 8, passing any of those bit numbers as
  flags directly will not pass the ASSERT().

- Add a static assert to avoid overflow
  To make sure all BTRFS_ORDERED_* flags can fit into an unsigned long.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: revalidate cached tree blocks on the uptodate path
ZhengYuan Huang [Fri, 13 Mar 2026 09:19:23 +0000 (17:19 +0800)] 
btrfs: revalidate cached tree blocks on the uptodate path

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>
2 weeks agobtrfs: prefer IS_ERR_OR_NULL() over manual NULL check
Philipp Hahn [Tue, 10 Mar 2026 11:48:28 +0000 (12:48 +0100)] 
btrfs: prefer IS_ERR_OR_NULL() over manual NULL check

Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
check.

IS_ERR_OR_NULL() already uses likely(!ptr) internally. checkpatch does
not like nesting it:
> WARNING: nested (un)?likely() calls, IS_ERR_OR_NULL already uses
> unlikely() internally
Remove the explicit use of likely().

Change generated with coccinelle.

Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tree-checker: introduce checks for FREE_SPACE_BITMAP
ZhengYuan Huang [Tue, 10 Mar 2026 21:56:10 +0000 (08:26 +1030)] 
btrfs: tree-checker: introduce checks for FREE_SPACE_BITMAP

Introduce checks for FREE_SPACE_BITMAP item, which include:

- Key alignment check
  Same as FREE_SPACE_EXTENT, the objectid is the logical bytenr of the
  free space, and offset is the length of the free space, so both
  should be aligned to the fs block size.

- Non-zero range check
  A zero key->offset would describe an empty bitmap, which is invalid.

- Item size check
  The item must hold exactly DIV_ROUND_UP(key->offset >> sectorsize_bits,
  BITS_PER_BYTE) bytes.  A mismatch indicates a truncated or otherwise
  corrupt bitmap item; without this check, the bitmap loading path would
  walk past the end of the leaf and trigger a NULL dereference in
  assert_eb_folio_uptodate().

Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Reviewed-by: Qu Wenruo <wqu@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>
2 weeks agobtrfs: tree-checker: introduce checks for FREE_SPACE_EXTENT
Qu Wenruo [Mon, 9 Mar 2026 22:19:26 +0000 (08:49 +1030)] 
btrfs: tree-checker: introduce checks for FREE_SPACE_EXTENT

Introduce FREE_SPACE_EXTENT checks, which include:

- The key alignment check
  The objectid is the logical bytenr of the free space, and offset is the
  length of the free space, thus they should all be aligned to the fs
  block size.

- The item size check
  The FREE_SPACE_EXTENT item should have a size of zero.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: tree-checker: introduce checks for FREE_SPACE_INFO
Qu Wenruo [Mon, 9 Mar 2026 22:19:25 +0000 (08:49 +1030)] 
btrfs: tree-checker: introduce checks for FREE_SPACE_INFO

Introduce checks for FREE_SPACE_INFO item, which include:

- Key alignment check
  The objectid is the logical bytenr of the chunk/bg, and offset is the
  length of the chunk/bg, thus they should all be aligned to the fs
  block size.

- Item size check
  The FREE_SPACE_INFO should a fix size.

- Flags check
  The flags member should have no other flags than
  BTRFS_FREE_SPACE_USING_BITMAPS.

  For future expansion, introduce a new macro
  BTRFS_FREE_SPACE_FLAGS_MASK for such checks.

  And since we're here, the BTRFS_FREE_SPACE_USING_BITMAPS should not
  use unsigned long long, as the flags is only 32 bits wide.
  So fix that to use unsigned long.

- Extent count check
  That member shows how many free space bitmap/extent items there are
  inside the chunk/bg.

  We know the chunk size (from key->offset), thus there should be at
  most (key->offset >> sectorsize_bits) blocks inside the chunk.
  Use that value as the upper limit and if that counter is larger than
  that, there is a high chance it's a bitflip in high bits.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: zoned: limit number of zones reclaimed in flush_space()
Johannes Thumshirn [Thu, 5 Mar 2026 10:06:44 +0000 (11:06 +0100)] 
btrfs: zoned: limit number of zones reclaimed in flush_space()

Limit the number of zones reclaimed in flush_space()'s RECLAIM_ZONES
state.

This prevents possibly long running reclaim sweeps to block other tasks in
the system, while the system is under pressure anyways, causing the
tasks to hang.

An example of this can be seen here, triggered by fstests generic/551:

generic/551        [   27.042349] run fstests generic/551 at 2026-02-27 11:05:30
 BTRFS: device fsid 78c16e29-20d9-4c8e-bc04-7ba431be38ff devid 1 transid 8 /dev/vdb (254:16) scanned by mount (806)
 BTRFS info (device vdb): first mount of filesystem 78c16e29-20d9-4c8e-bc04-7ba431be38ff
 BTRFS info (device vdb): using crc32c checksum algorithm
 BTRFS info (device vdb): host-managed zoned block device /dev/vdb, 64 zones of 268435456 bytes
 BTRFS info (device vdb): zoned mode enabled with zone size 268435456
 BTRFS info (device vdb): checking UUID tree
 BTRFS info (device vdb): enabling free space tree
 INFO: task kworker/u38:1:90 blocked for more than 120 seconds.
       Not tainted 7.0.0-rc1+ #345
 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
 task:kworker/u38:1   state:D stack:0     pid:90    tgid:90    ppid:2      task_flags:0x4208060 flags:0x00080000
 Workqueue: events_unbound btrfs_async_reclaim_data_space
 Call Trace:
  <TASK>
  __schedule+0x34f/0xe70
  schedule+0x41/0x140
  schedule_timeout+0xa3/0x110
  ? mark_held_locks+0x40/0x70
  ? lockdep_hardirqs_on_prepare+0xd8/0x1c0
  ? trace_hardirqs_on+0x18/0x100
  ? lockdep_hardirqs_on+0x84/0x130
  ? _raw_spin_unlock_irq+0x33/0x50
  wait_for_completion+0xa4/0x150
  ? __flush_work+0x24c/0x550
  __flush_work+0x339/0x550
  ? __pfx_wq_barrier_func+0x10/0x10
  ? wait_for_completion+0x39/0x150
  flush_space+0x243/0x660
  ? find_held_lock+0x2b/0x80
  ? kvm_sched_clock_read+0x11/0x20
  ? local_clock_noinstr+0x17/0x110
  ? local_clock+0x15/0x30
  ? lock_release+0x1b7/0x4b0
  do_async_reclaim_data_space+0xe8/0x160
  btrfs_async_reclaim_data_space+0x19/0x30
  process_one_work+0x20a/0x5f0
  ? lock_is_held_type+0xcd/0x130
  worker_thread+0x1e2/0x3c0
  ? __pfx_worker_thread+0x10/0x10
  kthread+0x103/0x150
  ? __pfx_kthread+0x10/0x10
  ret_from_fork+0x20d/0x320
  ? __pfx_kthread+0x10/0x10
  ret_from_fork_asm+0x1a/0x30
  </TASK>

 Showing all locks held in the system:
 1 lock held by khungtaskd/67:
  #0: ffffffff824d58e0 (rcu_read_lock){....}-{1:3}, at: debug_show_all_locks+0x3d/0x194
 2 locks held by kworker/u38:1/90:
  #0: ffff8881000aa158 ((wq_completion)events_unbound){+.+.}-{0:0}, at: process_one_work+0x3c4/0x5f0
  #1: ffffc90000c17e58 ((work_completion)(&fs_info->async_data_reclaim_work)){+.+.}-{0:0}, at: process_one_work+0x1c0/0x5f0
 5 locks held by kworker/u39:1/191:
  #0: ffff8881000aa158 ((wq_completion)events_unbound){+.+.}-{0:0}, at: process_one_work+0x3c4/0x5f0
  #1: ffffc90000dfbe58 ((work_completion)(&fs_info->reclaim_bgs_work)){+.+.}-{0:0}, at: process_one_work+0x1c0/0x5f0
  #2: ffff888101da0420 (sb_writers#9){.+.+}-{0:0}, at: process_one_work+0x20a/0x5f0
  #3: ffff88811040a648 (&fs_info->reclaim_bgs_lock){+.+.}-{4:4}, at: btrfs_reclaim_bgs_work+0x1de/0x770
  #4: ffff888110408a18 (&fs_info->cleaner_mutex){+.+.}-{4:4}, at: btrfs_relocate_block_group+0x95a/0x20f0
 1 lock held by aio-dio-write-v/980:
  #0: ffff888110093008 (&sb->s_type->i_mutex_key#15){++++}-{4:4}, at: btrfs_inode_lock+0x51/0xb0

 =============================================

To prevent these long running reclaims from blocking the system, only
reclaim 5 block_groups in the RECLAIM_ZONES state of flush_space(). Also
as these reclaims are now constrained, it opens up the use for a
synchronous call to brtfs_reclaim_block_groups(), eliminating the need
to place the reclaim task on a workqueue and then flushing the workqueue
again.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: create btrfs_reclaim_block_groups()
Johannes Thumshirn [Thu, 5 Mar 2026 10:06:43 +0000 (11:06 +0100)] 
btrfs: create btrfs_reclaim_block_groups()

Create a function btrfs_reclaim_block_groups() that gets called from the
block-group reclaim worker.

This allows creating synchronous block_group reclaim later on.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: move reclaiming of a single block group into its own function
Johannes Thumshirn [Thu, 5 Mar 2026 10:06:42 +0000 (11:06 +0100)] 
btrfs: move reclaiming of a single block group into its own function

The main work of reclaiming a single block-group in
btrfs_reclaim_bgs_work() is done inside the loop iterating over all the
block_groups in the fs_info->reclaim_bgs list.

Factor out reclaim of a single block group from the loop to improve
readability.

No functional change intended.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: extract inlined creation into a dedicated delalloc helper
Qu Wenruo [Wed, 4 Mar 2026 05:18:44 +0000 (15:48 +1030)] 
btrfs: extract inlined creation into a dedicated delalloc helper

Currently we call cow_file_range_inline() in different situations, from
regular cow_file_range() to compress_file_range().

This is because inline extent creation has different conditions based on
whether it's a compressed one or not.

But on the other hand, inline extent creation shouldn't be so
distributed, we can just have a dedicated branch in
btrfs_run_delalloc_range().

It will become more obvious for compressed inline cases, it makes no
sense to go through all the complex async extent mechanism just to
inline a single block.

So here we introduce a dedicated run_delalloc_inline() helper, and
remove all inline related handling from cow_file_range() and
compress_file_range().

There is a special update to inode_need_compress(), that a new
@check_inline parameter is introduced.
This is to allow inline specific checks to be done inside
run_delalloc_inline(), which allows single block compression, but
other call sites should always reject single block compression.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: move the mapping_set_error() out of the loop in end_bbio_data_write()
Qu Wenruo [Tue, 3 Mar 2026 08:15:10 +0000 (18:45 +1030)] 
btrfs: move the mapping_set_error() out of the loop in end_bbio_data_write()

Previously we have to call mapping_set_error() inside the
for_each_folio_all() loop, because we do not have a better way to grab
an inode, other than through folio->mapping.

But nowadays every btrfs_bio has its inode member populated, thus we can
easily grab the inode and its i_mapping easily, without the help from a
folio.

Now we can move that mapping_set_error() out of the loop, and use
bbio->inode to grab the i_mapping.

Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove the alignment check in end_bbio_data_write()
Qu Wenruo [Tue, 3 Mar 2026 08:15:09 +0000 (18:45 +1030)] 
btrfs: remove the alignment check in end_bbio_data_write()

The check is not necessary because:

- There is already assert_bbio_alignment() at btrfs_submit_bbio()

- There is also btrfs_subpage_assert() for all btrfs_folio_*() helpers

- The original commit mentions the check may go away in the future
  Commit 17a5adccf3fd01 ("btrfs: do away with non-whole_page extent
  I/O") introduced the check first, and in the commit message:

    I've replaced the whole_page computations with warnings, just to be
    sure that we're not issuing partial page reads or writes.  The
    warnings should probably just go away some time.

- No similar check in all other endio functions
  No matter if it's data read, compressed read or write.

- There is no such report for very long
  I do not even remember if there is any such report.

Thus the need to do such check in end_bbio_data_write() is very weak,
and we can just get rid of it.

Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: add tracepoint for search slot restart tracking
Leo Martins [Thu, 26 Feb 2026 09:51:08 +0000 (01:51 -0800)] 
btrfs: add tracepoint for search slot restart tracking

Add a btrfs_search_slot_restart tracepoint that fires at each restart
site in btrfs_search_slot(), recording the root, tree level, and
reason for the restart. This enables tracking search slot restarts
which contribute to COW amplification under memory pressure.

The four restart reasons are:
 - write_lock: insufficient write lock level, need to restart with
   higher lock
 - setup_nodes: node setup returned -EAGAIN
 - slot_zero: insertion at slot 0 requires higher write lock level
 - read_block: read_block_for_search returned -EAGAIN (block not
   cached or lock contention)

COW counts are already tracked by the existing trace_btrfs_cow_block()
tracepoint. The per-restart-site tracepoint avoids counter overhead
in the critical path when tracepoints are disabled, and provides
richer per-event information that bpftrace scripts can aggregate into
counts, histograms, and per-root breakdowns.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Leo Martins <loemra.dev@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: inhibit extent buffer writeback to prevent COW amplification
Leo Martins [Thu, 26 Feb 2026 09:51:07 +0000 (01:51 -0800)] 
btrfs: inhibit extent buffer writeback to prevent COW amplification

Inhibit writeback on COW'd extent buffers for the lifetime of the
transaction handle, preventing background writeback from setting
BTRFS_HEADER_FLAG_WRITTEN and causing unnecessary re-COW.

COW amplification occurs when background writeback flushes an extent
buffer that a transaction handle is still actively modifying. When
lock_extent_buffer_for_io() transitions a buffer from dirty to
writeback, it sets BTRFS_HEADER_FLAG_WRITTEN, marking the block as
having been persisted to disk at its current bytenr. Once WRITTEN is
set, should_cow_block() must either COW the block again or overwrite
it in place, both of which are unnecessary overhead when the buffer
is still being modified by the same handle that allocated it. By
inhibiting background writeback on actively-used buffers, WRITTEN is
never set while a transaction handle holds a reference to the buffer,
avoiding this overhead entirely.

Add an atomic_t writeback_inhibitors counter to struct extent_buffer,
which fits in an existing 6-byte hole without increasing struct size.
When a buffer is COW'd in btrfs_force_cow_block(), call
btrfs_inhibit_eb_writeback() to store the eb in the transaction
handle's writeback_inhibited_ebs xarray (keyed by eb->start), take a
reference, and increment writeback_inhibitors. The function handles
dedup (same eb inhibited twice by the same handle) and replacement
(different eb at the same logical address). Allocation failure is
graceful: the buffer simply falls back to the pre-existing behavior
where it may be written back and re-COW'd.

Also inhibit writeback in should_cow_block() when COW is skipped,
so that every transaction handle that reuses an already-COW'd buffer
also inhibits its writeback. Without this, if handle A COWs a block
and inhibits it, and handle B later reuses the same block without
inhibiting, handle A's uninhibit on end_transaction leaves the buffer
unprotected while handle B is still using it. This ensures all handles
that access a COW'd buffer contribute to the inhibitor count, and the
buffer remains protected until the last handle releases it.

In lock_extent_buffer_for_io(), when writeback_inhibitors is non-zero
and the writeback mode is WB_SYNC_NONE, skip the buffer. WB_SYNC_NONE
is used by the VM flusher threads for background and periodic
writeback, which are the only paths that cause COW amplification by
opportunistically writing out dirty extent buffers mid-transaction.
Skipping these is safe because the buffers remain dirty in the page
cache and will be written out at transaction commit time.

WB_SYNC_ALL must always proceed regardless of writeback_inhibitors.
This is required for correctness in the fsync path: btrfs_sync_log()
writes log tree blocks via filemap_fdatawrite_range() (WB_SYNC_ALL)
while the transaction handle that inhibited those same blocks is still
active. Without the WB_SYNC_ALL bypass, those inhibited log tree
blocks would be silently skipped, resulting in an incomplete log on
disk and corruption on replay. btrfs_write_and_wait_transaction()
also uses WB_SYNC_ALL via filemap_fdatawrite_range(); for that path,
inhibitors are already cleared beforehand, but the bypass ensures
correctness regardless.

Uninhibit in __btrfs_end_transaction() before atomic_dec(num_writers)
to prevent a race where the committer proceeds while buffers are still
inhibited. Also uninhibit in btrfs_commit_transaction() before writing
and in cleanup_transaction() for the error path.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Sun YangKai <sunk67188@gmail.com>
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Leo Martins <loemra.dev@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: extract the max compression chunk size into a macro
Qu Wenruo [Fri, 27 Feb 2026 02:45:53 +0000 (13:15 +1030)] 
btrfs: extract the max compression chunk size into a macro

We have two locations using open-coded 512K size, as the async chunk
size.

For compression we have not only the max size a compressed extent can
represent (128K), but also how large an async chunk can be (512K).

Although we have a macro for the maximum compressed extent size, we do
not have any macro for the async chunk size.

Add such a macro and replace the two open-coded SZ_512K.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove pointless error check in btrfs_check_dir_item_collision()
Filipe Manana [Wed, 25 Feb 2026 19:22:41 +0000 (19:22 +0000)] 
btrfs: remove pointless error check in btrfs_check_dir_item_collision()

We're under the IS_ERR() branch so we know that 'ret', which got assigned
the value of PTR_ERR(di) is always negative, so there's no point in
checking if it's negative.

Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove duplicated uuid tree existence check in btrfs_uuid_tree_add()
Filipe Manana [Thu, 19 Feb 2026 16:05:39 +0000 (16:05 +0000)] 
btrfs: remove duplicated uuid tree existence check in btrfs_uuid_tree_add()

There's no point in checking if the uuid root exists in
btrfs_uuid_tree_add(), since we already do it in btrfs_uuid_tree_lookup().
We can just remove the check from btrfs_uuid_tree_add() and make
btrfs_uuid_tree_lookup() return -EINVAL instead of -ENOENT in case the
uuid tree does not exists.

Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: stop checking for -EEXIST return value from btrfs_uuid_tree_add()
Filipe Manana [Tue, 24 Feb 2026 15:13:32 +0000 (15:13 +0000)] 
btrfs: stop checking for -EEXIST return value from btrfs_uuid_tree_add()

We never return -EEXIST from btrfs_uuid_tree_add(), if the item already
exists we extend it, so it's pointless to check for such return value.

Furthermore, in create_pending_snapshot(), the logic is completely broken.
The goal was to not error out and abort the transaction in case of -EEXIST
but we left 'ret' with the -EEXIST value, so we end up setting
pending->error to -EEXIST and return that error up the call chain up to
btrfs_commit_transaction(), which will abort the transaction.

Reviewed-by: Boris Burkov <boris@bur.io>
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>
2 weeks agobtrfs: report filesystem shutdown via fserror
Miquel Sabaté Solà [Mon, 16 Feb 2026 00:28:06 +0000 (01:28 +0100)] 
btrfs: report filesystem shutdown via fserror

Commit 347b7042fb26 ("Merge patch series "fs: generic file IO error
reporting"") has introduced a common framework for reporting errors to
fsnotify in a standard way.

One of the functions being introduced is fserror_report_shutdown() that,
when combined with the experimental support for shutdown in btrfs, it
means that user-space can also easily detect whenever a btrfs filesystem
has been marked as shutdown.

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>
2 weeks agobtrfs: replace kcalloc() calls to kzalloc_objs()
Miquel Sabaté Solà [Tue, 24 Feb 2026 21:45:44 +0000 (22:45 +0100)] 
btrfs: replace kcalloc() calls to kzalloc_objs()

Commit 2932ba8d9c99 ("slab: Introduce kmalloc_obj() and family")
introduced, among many others, the kzalloc_objs() helper, which has some
benefits over kcalloc(). Namely, internal introspection of the allocated
type now becomes possible, allowing for future alignment-aware choices
to be made by the allocator and future hardening work that can be type
sensitive. Dropping 'sizeof' comes also as a nice side-effect.

Moreover, this also allows us to be in line with the recent tree-wide
migration to the kmalloc_obj() and family of helpers. See
commit 69050f8d6d07 ("treewide: Replace kmalloc with kmalloc_obj for
non-scalar types").

Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: do compressed bio size roundup and zeroing in one go
Qu Wenruo [Thu, 19 Feb 2026 23:43:38 +0000 (10:13 +1030)] 
btrfs: do compressed bio size roundup and zeroing in one go

Currently we zero out all the remaining bytes of the last folio of
the compressed bio, then round the bio size to fs block boundary.

But that is done in two different functions, zero_last_folio() to zero
the remaining bytes of the last folio, and round_up_last_block() to
round up the bio to fs block boundary.

There are some minor problems:

- zero_last_folio() is zeroing ranges we won't submit
  This is mostly affecting block size < page size cases, where we can
  have a large folio (e.g. 64K), but the fs block size is only 4K.

  In that case, we may only want to submit the first 4K of the folio,
  the remaining range won't matter, but we still zero them all.

  This causes unnecessary CPU usage just to zero out some bytes we won't
  utilized.

- compressed_bio_last_folio() is called twice in two different functions
  Which in theory we only need to call it once.

Enhance the situation by:

- Only zero out bytes up to the fs block boundary
  Thus this will reduce some overhead for bs < ps cases.

- Move the folio_zero_range() call into round_up_last_block()
  So that we can reuse the same folio returned by
  compressed_bio_last_folio().

Reviewed-by: Anand Jain <asj@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>
2 weeks agobtrfs: reduce the size of compressed_bio
Qu Wenruo [Fri, 20 Feb 2026 03:41:51 +0000 (14:11 +1030)] 
btrfs: reduce the size of compressed_bio

The member compressed_bio::compressed_len can be replaced by the bio
size, as we always submit the full compressed data without any partial
read/write.

Furthermore we already have enough ASSERT()s making sure the bio size
matches the ordered extent or the extent map.

This saves 8 bytes from compressed_bio:

Before:

struct compressed_bio {
        u64                        start;                /*     0     8 */
        unsigned int               len;                  /*     8     4 */
        unsigned int               compressed_len;       /*    12     4 */
        u8                         compress_type;        /*    16     1 */
        bool                       writeback;            /*    17     1 */

        /* XXX 6 bytes hole, try to pack */

        struct btrfs_bio *         orig_bbio;            /*    24     8 */
        struct btrfs_bio           bbio __attribute__((__aligned__(8))); /*    32   304 */

        /* XXX last struct has 1 bit hole */

        /* size: 336, cachelines: 6, members: 7 */
        /* sum members: 330, holes: 1, sum holes: 6 */
        /* member types with bit holes: 1, total: 1 */
        /* forced alignments: 1 */
        /* last cacheline: 16 bytes */
} __attribute__((__aligned__(8)));

After:

 struct compressed_bio {
        u64                        start;                /*     0     8 */
        unsigned int               len;                  /*     8     4 */
        u8                         compress_type;        /*    12     1 */
        bool                       writeback;            /*    13     1 */

        /* XXX 2 bytes hole, try to pack */

        struct btrfs_bio *         orig_bbio;            /*    16     8 */
        struct btrfs_bio           bbio __attribute__((__aligned__(8))); /*    24   304 */

        /* XXX last struct has 1 bit hole */

        /* size: 328, cachelines: 6, members: 6 */
        /* sum members: 326, holes: 1, sum holes: 2 */
        /* member types with bit holes: 1, total: 1 */
        /* forced alignments: 1 */
        /* last cacheline: 8 bytes */
} __attribute__((__aligned__(8)));

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: introduce a common helper to calculate the size of a bio
Qu Wenruo [Fri, 20 Feb 2026 03:41:50 +0000 (14:11 +1030)] 
btrfs: introduce a common helper to calculate the size of a bio

We have several call sites doing the same work to calculate the size of
a bio:

struct bio_vec *bvec;
u32 bio_size = 0;
int i;

bio_for_each_bvec_all(bvec, bio, i)
bio_size += bvec->bv_len;

We can use a common helper instead of open-coding it everywhere.

This also allows us to constify the @bio_size variables used in all the
call sites.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove redundant nowait check in lock_extent_direct()
Alexey Velichayshiy [Sun, 22 Feb 2026 12:47:23 +0000 (15:47 +0300)] 
btrfs: remove redundant nowait check in lock_extent_direct()

The nowait flag is always false in this context, making the conditional
check unnecessary. Simplify the code by directly assigning -ENOTBLK.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Alexey Velichayshiy <a.velichayshiy@ispras.ru>
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>
2 weeks agobtrfs: fix placement of unlikely() in btrfs_insert_one_raid_extent()
Mark Harmstone [Wed, 18 Feb 2026 12:41:00 +0000 (12:41 +0000)] 
btrfs: fix placement of unlikely() in btrfs_insert_one_raid_extent()

Fix the unlikely added to btrfs_insert_one_raid_extent() by commit
a929904cf73b65 ("btrfs: add unlikely annotations to branches leading to
transaction abort"): the exclamation point is in the wrong place, so we
are telling the compiler that allocation failure is actually expected.

Reviewed-by: Filipe Manana <fdmanana@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>
2 weeks agobtrfs: pass a btrfs inode to tree-log.c:fill_inode_item()
Filipe Manana [Tue, 17 Feb 2026 17:48:17 +0000 (17:48 +0000)] 
btrfs: pass a btrfs inode to tree-log.c:fill_inode_item()

All internal functions should be given a btrfs_inode for consistency and
not a VFS inode. So pass a btrfs_inode instead of a VFS inode.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: stop printing condition result in assertion failure messages
Filipe Manana [Thu, 19 Feb 2026 15:37:59 +0000 (15:37 +0000)] 
btrfs: stop printing condition result in assertion failure messages

It's useless to print the result of the condition, it's always 0 if the
assertion is triggered, so it doesn't provide any useful information.

Examples:

   assertion failed: cb->bbio.bio.bi_iter.bi_size == disk_num_bytes :: 0, in inode.c:9991
   assertion failed: folio_test_writeback(folio) :: 0, in subpage.c:476

So stop printing that, it's always ":: 0" for any assertion triggered
(except for conditions that are just an identifier).

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>
2 weeks agobtrfs: constify arguments of some functions
Filipe Manana [Thu, 19 Feb 2026 15:34:12 +0000 (15:34 +0000)] 
btrfs: constify arguments of some functions

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>
2 weeks agobtrfs: avoid unnecessary root node COW during snapshotting
Filipe Manana [Wed, 18 Feb 2026 15:07:09 +0000 (15:07 +0000)] 
btrfs: avoid unnecessary root node COW during snapshotting

There's no need to COW the root node of the subvolume we are snapshotting
because we then call btrfs_copy_root(), which creates a copy of the root
node and sets its generation to the current transaction. So remove this
redundant COW right before calling btrfs_copy_root(), saving one extent
allocation, memory allocation, copying things, etc, and making the code
less confusing. Also rename the extent buffer variable from "old" to
"root_eb" since that name no longer makes any sense after removing the
unnecessary COW operation.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: check snapshot_force_cow earlier in can_nocow_file_extent()
Chen Guan Jie [Mon, 16 Feb 2026 22:16:32 +0000 (06:16 +0800)] 
btrfs: check snapshot_force_cow earlier in can_nocow_file_extent()

When a snapshot is being created, the atomic counter snapshot_force_cow
is incremented to force incoming writes to fallback to COW. This is a
critical mechanism to protect the consistency of the snapshot being taken.

Currently, can_nocow_file_extent() checks this counter only after
performing several checks, most notably the expensive cross-reference
check via btrfs_cross_ref_exist(). btrfs_cross_ref_exist() releases the
path and performs a search in the extent tree or backref cache, which
involves btree traversals and locking overhead.

Moves the snapshot_force_cow check to the very beginning of
can_nocow_file_extent().

This reordering is safe and beneficial because:

1. args->writeback_path is invariant for the duration of the call (set
   by caller run_delalloc_nocow).

2. is_freespace_inode is a static property of the inode.

3. The state of snapshot_force_cow is driven by the btrfs_mksnapshot()
   process. Checking it earlier does not change the outcome of the NOCOW
   decision, but effectively prunes the expensive code path when a
   fallback to COW is inevitable.

By failing fast when a snapshot is pending, we avoid the unnecessary
overhead of btrfs_cross_ref_exist() and other extent item checks in the
scenario where NOCOW is already known to be impossible.

Signed-off-by: Chen Guan Jie <jk.chen1095@gmail.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: do not mark inode incompressible after inline attempt fails
Qu Wenruo [Mon, 16 Feb 2026 02:49:38 +0000 (13:19 +1030)] 
btrfs: do not mark inode incompressible after inline attempt fails

[BUG]
The following sequence will set the file with nocompress flag:

  # mkfs.btrfs -f $dev
  # mount $dev $mnt -o max_inline=4,compress
  # xfs_io -f -c "pwrite 0 2k" -c sync $mnt/foobar

The inode will have NOCOMPRESS flag, even if the content itself (all 0xcd)
can still be compressed very well:

item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160
generation 9 transid 10 size 2097152 nbytes 1052672
block group 0 mode 100600 links 1 uid 0 gid 0 rdev 0
sequence 257 flags 0x8(NOCOMPRESS)

Please note that, this behavior is there even before commit 59615e2c1f63
("btrfs: reject single block sized compression early").

[CAUSE]
At compress_file_range(), after btrfs_compress_folios() call, we try
making an inlined extent by calling cow_file_range_inline().

But cow_file_range_inline() calls can_cow_file_range_inline() which has
more accurate checks on if the range can be inlined.

One of the user configurable conditions is the "max_inline=" mount
option. If that value is set low (like the example, 4 bytes, which
cannot store any header), or the compressed content is just slightly
larger than 2K (the default value, meaning a 50% compression ratio),
cow_file_range_inline() will return 1 immediately.

And since we're here only to try inline the compressed data, the range
is no larger than a single fs block.

Thus compression is never going to make it a win, we fall back to
marking the inode incompressible unavoidably.

[FIX]
Just add an extra check after inline attempt, so that if the inline
attempt failed, do not set the nocompress flag.

As there is no way to remove that flag, and the default 50% compression
ratio is way too strict for the whole inode.

CC: stable@vger.kernel.org # 6.12+
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove folio parameter from ordered io related functions
Qu Wenruo [Thu, 12 Feb 2026 09:13:56 +0000 (19:43 +1030)] 
btrfs: remove folio parameter from ordered io related functions

Both functions btrfs_finish_ordered_extent() and
btrfs_mark_ordered_io_finished() are accepting an optional folio
parameter.

That @folio is passed into can_finish_ordered_extent(), which later will
test and clear the ordered flag for the involved range.

However I do not think there is any other call site that can clear
ordered flags of an page cache folio and can affect
can_finish_ordered_extent().

There are limited *_clear_ordered() callers out of
can_finish_ordered_extent() function:

- btrfs_migrate_folio()
  This is completely unrelated, it's just migrating the ordered flag to
  the new folio.

- btrfs_cleanup_ordered_extents()
  We manually clean the ordered flags of all involved folios, then call
  btrfs_mark_ordered_io_finished() without a @folio parameter.
  So it doesn't need and didn't pass a @folio parameter in the first
  place.

- btrfs_writepage_fixup_worker()
  This function is going to be removed soon, and we should not hit that
  function anymore.

- btrfs_invalidate_folio()
  This is the real call site we need to bother with.

  If we already have a bio running, btrfs_finish_ordered_extent() in
  end_bbio_data_write() will be executed first, as
  btrfs_invalidate_folio() will wait for the writeback to finish.

  Thus if there is a running bio, it will not see the range has
  ordered flags, and just skip to the next range.

  If there is no bio running, meaning the ordered extent is created but
  the folio is not yet submitted.

  In that case btrfs_invalidate_folio() will manually clear the folio
  ordered range, but then manually finish the ordered extent with
  btrfs_dec_test_ordered_pending() without bothering the folio ordered
  flags.

  Meaning if the OE range with folio ordered flags will be finished
  manually without the need to call can_finish_ordered_extent().

This means all can_finish_ordered_extent() call sites should get a range
that has folio ordered flag set, thus the old "return false" branch
should never be triggered.

Now we can:

- Remove the @folio parameter from involved functions
  * btrfs_mark_ordered_io_finished()
  * btrfs_finish_ordered_extent()

  For call sites passing a @folio into those functions, let them
  manually clear the ordered flag of involved folios.

- Move btrfs_finish_ordered_extent() out of the loop in
  end_bbio_data_write()

  We only need to call btrfs_finish_ordered_extent() once per bbio,
  not per folio.

- Add an ASSERT() to make sure all folio ranges have ordered flags
  It's only for end_bbio_data_write().

  And we already have enough safe nets to catch over-accounting of ordered
  extents.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove the btrfs_inode parameter from btrfs_remove_ordered_extent()
Qu Wenruo [Wed, 11 Feb 2026 22:49:19 +0000 (09:19 +1030)] 
btrfs: remove the btrfs_inode parameter from btrfs_remove_ordered_extent()

We already have btrfs_ordered_extent::inode, thus there is no need to
pass a btrfs_inode parameter to btrfs_remove_ordered_extent().

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove out-of-date comments in btree_writepages()
Qu Wenruo [Wed, 11 Feb 2026 21:14:21 +0000 (07:44 +1030)] 
btrfs: remove out-of-date comments in btree_writepages()

There is a lengthy comment introduced in commit b3ff8f1d380e ("btrfs:
Don't submit any btree write bio if the fs has errors") and commit
c9583ada8cc4 ("btrfs: avoid double clean up when submit_one_bio()
failed"), explaining two things:

- Why we don't want to submit metadata write if the fs has errors

- Why we re-set @ret to 0 if it's positive

However it's no longer uptodate by the following reasons:

- We have better checks nowadays

  Commit 2618849f31e7 ("btrfs: ensure no dirty metadata is written back
  for an fs with errors") has introduced better checks, that if the
  fs is in an error state, metadata writes will not result in any bio
  but instead complete immediately.

  That covers all metadata writes better.

- Mentioned incorrect function name

  The commit c9583ada8cc4 ("btrfs: avoid double clean up when
  submit_one_bio() failed") introduced this ret > 0 handling, but at that
  time the function name submit_extent_page() was already incorrect.

  It was submit_eb_page() that could return >0 at that time,
  and submit_extent_page() could only return 0 or <0 for errors, never >0.

  Later commit b35397d1d325 ("btrfs: convert submit_extent_page() to use
  a folio") changed "submit_extent_page()" to "submit_extent_folio()" in
  the comment, but it doesn't make any difference since the function name
  is wrong from day 1.

  Finally commit 5e121ae687b8 ("btrfs: use buffer xarray for extent
  buffer writeback operations") completely reworked how metadata
  writeback works, and removed submit_eb_page(), leaving only the wrong
  function name in the comment.

  Furthermore the function submit_extent_folio() still exists in the
  latest code base, but is never utilized for metadata writeback, causing
  more confusion.

Just remove the lengthy comment, and replace the "if (ret > 0)" check
with an ASSERT(), since only btrfs_check_meta_write_pointer() can modify
@ret and it returns 0 or <0 for errors.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove bogus root search condition in load_extent_tree_free()
Filipe Manana [Sun, 8 Feb 2026 18:42:13 +0000 (18:42 +0000)] 
btrfs: remove bogus root search condition in load_extent_tree_free()

There's no need to pass the maximum between the block group's start offset
and BTRFS_SUPER_INFO_OFFSET (64K) since we can't have any block groups
allocated in the first megabyte, as that's reserved space. Furthermore,
even if we could, the correct thing to do was to pass the block group's
start offset anyway - and that's precisely what we do for block groups
hat happen to contain a superblock mirror (the range for the super block
is never marked as free and it's marked as dirty in the
fs_info->excluded_extents io tree).

So simplify this and get rid of that maximum expression.

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>
2 weeks agobtrfs: remove duplicate include of delayed-inode.h in disk-io.c
Chen Ni [Wed, 11 Feb 2026 04:40:32 +0000 (12:40 +0800)] 
btrfs: remove duplicate include of delayed-inode.h in disk-io.c

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>
2 weeks agobtrfs: pass literal booleans to functions that take boolean arguments
Filipe Manana [Tue, 10 Feb 2026 12:18:50 +0000 (12:18 +0000)] 
btrfs: pass literal booleans to functions that take boolean arguments

We have several functions with parameters defined as booleans but then we
have callers passing integers, 0 or 1, instead of false and true. While
this isn't a bug since 0 and 1 are converted to false and true, it is odd
and less readable. Change the callers to pass true and false literals
instead.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 weeks agobtrfs: remove pointless out label in qgroup_account_snapshot()
Filipe Manana [Tue, 10 Feb 2026 12:08:56 +0000 (12:08 +0000)] 
btrfs: remove pointless out label in qgroup_account_snapshot()

The 'out' label is pointless as there are no cleanups to perform there,
we can replace every goto with a direct return.

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>