From: Christian Borntraeger <borntraeger@linux.ibm.com>
To: Chris Mason <clm@fb.com>, David Sterba <dsterba@suse.com>,
Qu Wenruo <wqu@suse.com>
Cc: linux-btrfs@vger.kernel.org,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Lockdep circular dependency: btrfs_swap_activate() calls sysfs_notify()
Date: Fri, 31 Jul 2026 12:57:37 +0200 [thread overview]
Message-ID: <782c4d5c-d93b-42b3-b4ca-58deb3d8a894@linux.ibm.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 6384 bytes --]
One or more of the following files ( btrfs-swapon-kernfs-repro.sh ) violates IBM policy and all attachment(s) have been removed from the message.
**********************************************************************
We had the calltrace at the bottom of this mail in our CI logs
I also attached an AI generated reproducer that triggers this easily.
For convenience, here is what AI came up with analysing the log, but
I would like your take on it. Let me know if you want to see the
AI proposed fix.
----
btrfs_swap_activate() takes the inode's i_mmap_lock for write very
early (inode.c:10120) and holds it across the entire function; the
comment there explains the intent, which is to keep mmap writes from
racing with the delalloc flush and the extent range lock.
There are three btrfs_exclop_finish() calls inside that window:
fs/btrfs/inode.c:10181 error path, swapfile on a rw subvolume
with an active snapshot
fs/btrfs/inode.c:10202 error path, could not lock the snapshot drew
lock
fs/btrfs/inode.c:10399 the common "out:" path -- taken on both
success and failure
and btrfs_exclop_finish() (fs/btrfs/fs.c:224) ends with an unconditional
sysfs_notify(). So the offending edge is taken on *every* successful
swapon of a btrfs swap file, not only on an error path.
The sysfs_notify() itself does nothing but a kernfs lookup plus a poll
wakeup for userspace watching the "exclusive_operation" attribute. It
has no dependency whatsoever on i_mmap_lock, or on the inode at all.
Both kernfs_rwsem acquisitions in the cycle are read acquisitions
({++++}), so the two of them alone cannot deadlock. A real hang needs a
third task waiting to take kernfs_rwsem for write, because rwsem
write-fairness makes a later down_read() block behind a queued writer:
T_swapon: holds i_mmap_lock(write)
blocks in down_read(kernfs_rwsem) [queued behind T_w]
T_w: blocks in down_write(kernfs_rwsem) [waiting for T_dir]
e.g. any sysfs node create/remove -- device hotplug,
module load, cgroup or block-device attribute changes
T_dir: holds kernfs_rwsem(read) in kernfs_fop_readdir
faults on the user dirent buffer -> mmap_lock
-> btrfs_page_mkwrite -> down_read(i_mmap_lock)
blocks behind T_swapon's write holder
-> three-way deadlock.
That is a narrow race, which is consistent with this having gone
unnoticed for years, but every step of it is ordinary system activity.
The dependency is genuine and worth fixing rather than annotating away.
Suggested fix is to get the sysfs_notify() out from under i_mmap_lock
real life log found in our CI:
----------------------------
LOCKDEP_CIRCULAR (suite: tela-distro, case: tests/test_mempig/test_mempig)
WARNING: possible circular locking dependency detected
7.2.0-20260730.rc5.git10.af7a8a7752eb.300.fc44.s390x+debug #1 Not tainted
------------------------------------------------------
swapon/172010 is trying to acquire lock:
000002ea80a485a0 (&root->kernfs_rwsem){++++}-{3:3}, at: kernfs_find_and_get_ns+0x3c/0x80
but task is already holding lock:
000002ebc465d270 (&ei->i_mmap_lock){++++}-{3:3}, at: btrfs_swap_activate+0x9a/0x1240
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #3 (&ei->i_mmap_lock){++++}-{3:3}:
lock_acquire+0x150/0x3f0
down_read+0x5a/0x280
btrfs_page_mkwrite+0x258/0x870
do_page_mkwrite+0x60/0x160
do_wp_page+0x128/0x750
__handle_mm_fault+0x1be/0x590
handle_mm_fault+0xa2/0x370
do_exception+0x292/0x590
__do_pgm_check+0x168/0x430
pgm_check_handler+0x114/0x160
-> #2 (sb_pagefaults){.+.+}-{0:0}:
lock_acquire+0x150/0x3f0
percpu_down_read_internal.constprop.0+0x54/0x120
btrfs_page_mkwrite+0xa6/0x870
do_page_mkwrite+0x60/0x160
do_fault+0x132/0x4a0
__handle_mm_fault+0x1be/0x590
handle_mm_fault+0xa2/0x370
do_exception+0x1a0/0x590
__do_pgm_check+0x168/0x430
pgm_check_handler+0x114/0x160
-> #1 (&mm->mmap_lock){++++}-{3:3}:
lock_acquire+0x150/0x3f0
__might_fault+0x7a/0xa0
filldir64+0x11c/0x210
kernfs_fop_readdir+0x150/0x4c0
iterate_dir+0xcc/0x2d0
__do_sys_getdents64+0x7a/0x130
__do_syscall+0x172/0x750
system_call+0x72/0x90
-> #0 (&root->kernfs_rwsem){++++}-{3:3}:
check_prev_add+0x160/0xf40
__lock_acquire+0x12aa/0x15a0
lock_acquire+0x150/0x3f0
down_read+0x5a/0x280
kernfs_find_and_get_ns+0x3c/0x80
sysfs_notify+0x60/0xc0
btrfs_swap_activate+0x83c/0x1240
__do_sys_swapon+0x278/0x9c0
__do_syscall+0x172/0x750
system_call+0x72/0x90
other info that might help us debug this:
Chain exists of:
&root->kernfs_rwsem --> sb_pagefaults --> &ei->i_mmap_lock
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&ei->i_mmap_lock);
lock(sb_pagefaults);
lock(&ei->i_mmap_lock);
rlock(&root->kernfs_rwsem);
*** DEADLOCK ***
2 locks held by swapon/172010:
#0: 000002ebc465d3f0 (&sb->s_type->i_mutex_key#20){++++}-{3:3}, at: __do_sys_swapon+0x5be/0x9c0
#1: 000002ebc465d270 (&ei->i_mmap_lock){++++}-{3:3}, at: btrfs_swap_activate+0x9a/0x1240
stack backtrace:
CPU: 6 UID: 0 PID: 172010 Comm: swapon Not tainted 7.2.0-20260730.rc5.git10.af7a8a7752eb.300.fc44.s390x+debug #1 PREEMPT
Hardware name: IBM 8561 T01 701 (z/VM 7.4.0)
Call Trace:
[<000003f7d5ab4e3e>] dump_stack_lvl+0xae/0x108
[<000003f7d5bbef24>] print_circular_bug+0x1a4/0x230
[<000003f7d5bbf13c>] check_noncircular+0x18c/0x1b0
[<000003f7d5bc0510>] check_prev_add+0x160/0xf40
[<000003f7d5bc408a>] __lock_acquire+0x12aa/0x15a0
[<000003f7d5bc44d0>] lock_acquire+0x150/0x3f0
[<000003f7d6c447ca>] down_read+0x5a/0x280
[<000003f7d60ad61c>] kernfs_find_and_get_ns+0x3c/0x80
[<000003f7d60b3b70>] sysfs_notify+0x60/0xc0
[<000003f7d635653c>] btrfs_swap_activate+0x83c/0x1240
[<000003f7d5f1d268>] __do_sys_swapon+0x278/0x9c0
[<000003f7d6c369a2>] __do_syscall+0x172/0x750
[<000003f7d6c4baa2>] system_call+0x72/0x90
INFO: lockdep is turned off.
next reply other threads:[~2026-07-31 10:57 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 10:57 Christian Borntraeger [this message]
2026-07-31 11:12 ` Qu Wenruo
2026-07-31 11:14 ` Christian Borntraeger
2026-08-03 9:07 ` Christian Borntraeger
2026-08-03 9:44 ` Qu Wenruo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=782c4d5c-d93b-42b3-b4ca-58deb3d8a894@linux.ibm.com \
--to=borntraeger@linux.ibm.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=wqu@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®