All of lore.kernel.org
 help / color / mirror / Atom feed
* [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

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.