* [PATCH] btrfs: do not check eb->refs to determine if the eb is still held
@ 2026-06-20 2:07 Qu Wenruo
2026-06-20 2:46 ` Su Yue
0 siblings, 1 reply; 3+ messages in thread
From: Qu Wenruo @ 2026-06-20 2:07 UTC (permalink / raw)
To: linux-btrfs; +Cc: Glass Su
[FALSE ALERTS]
There is a bug report that the warning inside
invalidate_and_check_btree_folios() got triggered duriong btrfs/298:
BTRFS info (device sdd): first mount of filesystem f9bf732a-a19b-44b9-99a7-614ddff168e2
BTRFS info (device sdd): using crc32c checksum algorithm
BTRFS error (device sdd): failed to find fsid cb2fdb42-b638-4f2f-badd-4127467ba674 when attempting to open seed devices
BTRFS error (device sdd): failed to read chunk tree: -2
------------[ cut here ]------------
WARNING: disk-io.c:3342 at invalidate_and_check_btree_folios+0x260/0x3c0 [btrfs], CPU#4: mount/125993
CPU: 4 UID: 0 PID: 125993 Comm: mount Tainted: G W OE 7.1.0-rc7-custom+ #1 PREEMPT(full)
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20250812-19.fc42 08/12/2025
Call trace:
invalidate_and_check_btree_folios+0x260/0x3c0 [btrfs] (P)
open_ctree+0x1f50/0x23b0 [btrfs]
btrfs_get_tree+0x89c/0xc48 [btrfs]
vfs_get_tree+0x30/0x110
vfs_cmd_create+0x58/0xe8
__arm64_sys_fsconfig+0x39c/0x518
invoke_syscall.constprop.0+0x48/0x120
el0_svc_common.constprop.0+0x40/0xe8
do_el0_svc+0x24/0x38
el0_svc+0x50/0x310
el0t_64_sync_handler+0xa0/0xe8
el0t_64_sync+0x198/0x1a0
---[ end trace 0000000000000000 ]---
BTRFS warning (device sdd): unable to release extent buffer 365985792 owner 3 gen 17 refs 3 flags 0x5
[CAUSE]
In that invalidate_and_check_btree_folios() we wait for the eb to finish
its read, then check if it's only held by us and the btree inode.
If not, then do a warning as it may be still held, and could cause
problems.
But there is a small window where the check can lead to false alerts:
Thread A (Read endio) | Thread B (Unmount)
----------------------------------+-------------------------------------
end_bbio_meta_read() |
| The eb has one extra ref held |
| by the reader, and has |
| EXTENT_BUFFER_READING flag set | invalidate_and_check_btree_folios()
| | |
|- clear_extent_buffer_reading() | |
| | |- wait_on_bit_io();
| | | The EXTENT_BUFFER_READING flag is
| | | cleared
| | |- if (refcount_read(eb->refs) > 2)
| | The eb is held by the read, us
| | and btree inode, thus it
| | will trigger the warning
|- free_extent_buffer() |
[WORKAROUND]
Unfortunately EXTENT_BUFFER_READING flag clearing is always before
extent buffer put, thus there is no simple way to make sure the read is
finished along with eb put.
For now just remove the eb->refs check until a proper protection is
introduced for clearing EXTENT_BUFFER_READING and updates of eb->refs.
Reported-by: Glass Su <glass.su@suse.com>
Link: https://lore.kernel.org/linux-btrfs/DC0C775E-13B3-47D9-9AB2-895BB11C029D@suse.com/
Fixes: 83f7e52b7ed1 ("btrfs: warn about extent buffer that can not be released")
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/disk-io.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0a7d80da9c94..39a389cdbdd4 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3328,10 +3328,14 @@ static void invalidate_and_check_btree_folios(struct btrfs_fs_info *fs_info)
wait_on_bit_io(&eb->bflags, EXTENT_BUFFER_READING,
TASK_UNINTERRUPTIBLE);
/*
- * The refs threshold is 2, one held by us at the beginning
- * of the loop, one for the ownership in the buffer tree.
+ * EXTENT_BUFFER_READING is cleared then the eb refs is put during
+ * end_bbio_meta_read(), which leaves a window where above wait
+ * finished but eb ref is still hold by endio.
+ *
+ * Thus we can not use eb->refs to determine if the eb is hold
+ * by someone else. Just check if the eb is still under IO.
*/
- if (unlikely(refcount_read(&eb->refs) > 2 || extent_buffer_under_io(eb))) {
+ if (unlikely(extent_buffer_under_io(eb))) {
WARN_ON_ONCE(IS_ENABLED(CONFIG_BTRFS_DEBUG));
btrfs_warn(fs_info,
"unable to release extent buffer %llu owner %llu gen %llu refs %u flags 0x%lx",
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] btrfs: do not check eb->refs to determine if the eb is still held
2026-06-20 2:07 [PATCH] btrfs: do not check eb->refs to determine if the eb is still held Qu Wenruo
@ 2026-06-20 2:46 ` Su Yue
2026-06-20 3:01 ` Qu Wenruo
0 siblings, 1 reply; 3+ messages in thread
From: Su Yue @ 2026-06-20 2:46 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs, Glass Su
On Sat 20 Jun 2026 at 11:37, Qu Wenruo <wqu@suse.com> wrote:
> [FALSE ALERTS]
> There is a bug report that the warning inside
> invalidate_and_check_btree_folios() got triggered duriong
> btrfs/298:
>
> BTRFS info (device sdd): first mount of filesystem
> f9bf732a-a19b-44b9-99a7-614ddff168e2
> BTRFS info (device sdd): using crc32c checksum algorithm
> BTRFS error (device sdd): failed to find fsid
> cb2fdb42-b638-4f2f-badd-4127467ba674 when attempting to open
> seed devices
> BTRFS error (device sdd): failed to read chunk tree: -2
> ------------[ cut here ]------------
> WARNING: disk-io.c:3342 at
> invalidate_and_check_btree_folios+0x260/0x3c0 [btrfs], CPU#4:
> mount/125993
> CPU: 4 UID: 0 PID: 125993 Comm: mount Tainted: G W OE
> 7.1.0-rc7-custom+ #1 PREEMPT(full)
> Hardware name: QEMU KVM Virtual Machine, BIOS
> edk2-20250812-19.fc42 08/12/2025
> Call trace:
> invalidate_and_check_btree_folios+0x260/0x3c0 [btrfs] (P)
> open_ctree+0x1f50/0x23b0 [btrfs]
> btrfs_get_tree+0x89c/0xc48 [btrfs]
> vfs_get_tree+0x30/0x110
> vfs_cmd_create+0x58/0xe8
> __arm64_sys_fsconfig+0x39c/0x518
> invoke_syscall.constprop.0+0x48/0x120
> el0_svc_common.constprop.0+0x40/0xe8
> do_el0_svc+0x24/0x38
> el0_svc+0x50/0x310
> el0t_64_sync_handler+0xa0/0xe8
> el0t_64_sync+0x198/0x1a0
> ---[ end trace 0000000000000000 ]---
> BTRFS warning (device sdd): unable to release extent buffer
> 365985792 owner 3 gen 17 refs 3 flags 0x5
>
> [CAUSE]
> In that invalidate_and_check_btree_folios() we wait for the eb
> to finish
> its read, then check if it's only held by us and the btree
> inode.
>
> If not, then do a warning as it may be still held, and could
> cause
> problems.
>
> But there is a small window where the check can lead to false
> alerts:
>
> Thread A (Read endio) | Thread B (Unmount)
> ----------------------------------+-------------------------------------
> end_bbio_meta_read() |
> | The eb has one extra ref held |
> | by the reader, and has |
> | EXTENT_BUFFER_READING flag set |
> invalidate_and_check_btree_folios()
> | | |
> |- clear_extent_buffer_reading() | |
> | | |- wait_on_bit_io();
> | | | The EXTENT_BUFFER_READING
> flag is
> | | | cleared
> | | |- if
> (refcount_read(eb->refs) > 2)
> | | The eb is held by the
> read, us
> | | and btree inode, thus it
> | | will trigger the warning
> |- free_extent_buffer() |
>
> [WORKAROUND]
> Unfortunately EXTENT_BUFFER_READING flag clearing is always
> before
> extent buffer put, thus there is no simple way to make sure the
> read is
> finished along with eb put.
>
> For now just remove the eb->refs check until a proper protection
> is
> introduced for clearing EXTENT_BUFFER_READING and updates of
> eb->refs.
>
> Reported-by: Glass Su <glass.su@suse.com>
>
Reported-by: Su Yue <glass.su@suse.com>
Also for this patch:
Reviewed-by: Su Yue <glass.su@suse.com>
> Link:
> https://lore.kernel.org/linux-btrfs/DC0C775E-13B3-47D9-9AB2-895BB11C029D@suse.com/
> Fixes: 83f7e52b7ed1 ("btrfs: warn about extent buffer that can
> not be released")
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> fs/btrfs/disk-io.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 0a7d80da9c94..39a389cdbdd4 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -3328,10 +3328,14 @@ static void
> invalidate_and_check_btree_folios(struct btrfs_fs_info *fs_info)
> wait_on_bit_io(&eb->bflags, EXTENT_BUFFER_READING,
> TASK_UNINTERRUPTIBLE);
> /*
> - * The refs threshold is 2, one held by us at the
> beginning
> - * of the loop, one for the ownership in the buffer tree.
> + * EXTENT_BUFFER_READING is cleared then the eb refs is
> put during
> + * end_bbio_meta_read(), which leaves a window where above
> wait
> + * finished but eb ref is still hold by endio.
> + *
> + * Thus we can not use eb->refs to determine if the eb is
> hold
> + * by someone else. Just check if the eb is still under
> IO.
> */
> - if (unlikely(refcount_read(&eb->refs) > 2 ||
> extent_buffer_under_io(eb))) {
> + if (unlikely(extent_buffer_under_io(eb))) {
> WARN_ON_ONCE(IS_ENABLED(CONFIG_BTRFS_DEBUG));
> btrfs_warn(fs_info,
> "unable to release extent buffer %llu owner %llu gen
> %llu refs %u flags 0x%lx",
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] btrfs: do not check eb->refs to determine if the eb is still held
2026-06-20 2:46 ` Su Yue
@ 2026-06-20 3:01 ` Qu Wenruo
0 siblings, 0 replies; 3+ messages in thread
From: Qu Wenruo @ 2026-06-20 3:01 UTC (permalink / raw)
To: Su Yue, Qu Wenruo; +Cc: linux-btrfs, Glass Su
在 2026/6/20 12:16, Su Yue 写道:
> On Sat 20 Jun 2026 at 11:37, Qu Wenruo <wqu@suse.com> wrote:
>
>> [FALSE ALERTS]
>> There is a bug report that the warning inside
>> invalidate_and_check_btree_folios() got triggered duriong btrfs/298:
>>
>> BTRFS info (device sdd): first mount of filesystem f9bf732a-
>> a19b-44b9-99a7-614ddff168e2
>> BTRFS info (device sdd): using crc32c checksum algorithm
>> BTRFS error (device sdd): failed to find fsid cb2fdb42-b638-4f2f-
>> badd-4127467ba674 when attempting to open seed devices
>> BTRFS error (device sdd): failed to read chunk tree: -2
>> ------------[ cut here ]------------
>> WARNING: disk-io.c:3342 at
>> invalidate_and_check_btree_folios+0x260/0x3c0 [btrfs], CPU#4:
>> mount/125993
>> CPU: 4 UID: 0 PID: 125993 Comm: mount Tainted: G W OE 7.1.0-
>> rc7-custom+ #1 PREEMPT(full)
>> Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20250812-19.fc42
>> 08/12/2025
>> Call trace:
>> invalidate_and_check_btree_folios+0x260/0x3c0 [btrfs] (P)
>> open_ctree+0x1f50/0x23b0 [btrfs]
>> btrfs_get_tree+0x89c/0xc48 [btrfs]
>> vfs_get_tree+0x30/0x110
>> vfs_cmd_create+0x58/0xe8
>> __arm64_sys_fsconfig+0x39c/0x518
>> invoke_syscall.constprop.0+0x48/0x120
>> el0_svc_common.constprop.0+0x40/0xe8
>> do_el0_svc+0x24/0x38
>> el0_svc+0x50/0x310
>> el0t_64_sync_handler+0xa0/0xe8
>> el0t_64_sync+0x198/0x1a0
>> ---[ end trace 0000000000000000 ]---
>> BTRFS warning (device sdd): unable to release extent buffer
>> 365985792 owner 3 gen 17 refs 3 flags 0x5
>>
>> [CAUSE]
>> In that invalidate_and_check_btree_folios() we wait for the eb to finish
>> its read, then check if it's only held by us and the btree inode.
>>
>> If not, then do a warning as it may be still held, and could cause
>> problems.
>>
>> But there is a small window where the check can lead to false alerts:
>>
>> Thread A (Read endio) | Thread B (Unmount)
>> ----------------------------------+-------------------------------------
>> end_bbio_meta_read() |
>> | The eb has one extra ref held |
>> | by the reader, and has |
>> | EXTENT_BUFFER_READING flag set | invalidate_and_check_btree_folios()
>> | | |
>> |- clear_extent_buffer_reading() | |
>> | | |- wait_on_bit_io();
>> | | | The EXTENT_BUFFER_READING flag is
>> | | | cleared
>> | | |- if (refcount_read(eb->refs) > 2)
>> | | The eb is held by the read, us
>> | | and btree inode, thus it
>> | | will trigger the warning
>> |- free_extent_buffer() |
>>
>> [WORKAROUND]
>> Unfortunately EXTENT_BUFFER_READING flag clearing is always before
>> extent buffer put, thus there is no simple way to make sure the read is
>> finished along with eb put.
>>
>> For now just remove the eb->refs check until a proper protection is
>> introduced for clearing EXTENT_BUFFER_READING and updates of eb->refs.
>>
>> Reported-by: Glass Su <glass.su@suse.com>
>>
> Reported-by: Su Yue <glass.su@suse.com>
>
> Also for this patch:
> Reviewed-by: Su Yue <glass.su@suse.com>
It turns out that I can put the EXTENT_BUFFER_READING updating inside
free_extent_buffer(), under the refs_lock protection.
By doing that, and also checking the eb->refs under refs_lock, we can
remove the race window completely.
I'll run a full tests before send out the updated fix.
Thanks,
Qu
>
>
>> Link: https://lore.kernel.org/linux-btrfs/
>> DC0C775E-13B3-47D9-9AB2-895BB11C029D@suse.com/
>> Fixes: 83f7e52b7ed1 ("btrfs: warn about extent buffer that can not be
>> released")
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>> fs/btrfs/disk-io.c | 10 +++++++---
>> 1 file changed, 7 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
>> index 0a7d80da9c94..39a389cdbdd4 100644
>> --- a/fs/btrfs/disk-io.c
>> +++ b/fs/btrfs/disk-io.c
>> @@ -3328,10 +3328,14 @@ static void
>> invalidate_and_check_btree_folios(struct btrfs_fs_info *fs_info)
>> wait_on_bit_io(&eb->bflags, EXTENT_BUFFER_READING,
>> TASK_UNINTERRUPTIBLE);
>> /*
>> - * The refs threshold is 2, one held by us at the beginning
>> - * of the loop, one for the ownership in the buffer tree.
>> + * EXTENT_BUFFER_READING is cleared then the eb refs is put
>> during
>> + * end_bbio_meta_read(), which leaves a window where above wait
>> + * finished but eb ref is still hold by endio.
>> + *
>> + * Thus we can not use eb->refs to determine if the eb is hold
>> + * by someone else. Just check if the eb is still under IO.
>> */
>> - if (unlikely(refcount_read(&eb->refs) > 2 ||
>> extent_buffer_under_io(eb))) {
>> + if (unlikely(extent_buffer_under_io(eb))) {
>> WARN_ON_ONCE(IS_ENABLED(CONFIG_BTRFS_DEBUG));
>> btrfs_warn(fs_info,
>> "unable to release extent buffer %llu owner %llu gen
>> %llu refs %u flags 0x%lx",
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-20 3:01 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-20 2:07 [PATCH] btrfs: do not check eb->refs to determine if the eb is still held Qu Wenruo
2026-06-20 2:46 ` Su Yue
2026-06-20 3:01 ` Qu Wenruo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox