[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251224233133.41078-1-swilczek.lx@gmail.com>
Date: Thu, 25 Dec 2025 00:31:33 +0100
From: Szymon Wilczek <swilczek.lx@...il.com>
To: Dave Kleikamp <shaggy@...nel.org>
Cc: jfs-discussion@...ts.sourceforge.net,
linux-kernel@...r.kernel.org,
syzbot+a63afa301d1258d09267@...kaller.appspotmail.com,
Szymon Wilczek <swilczek.lx@...il.com>
Subject: [PATCH] jfs: add missing tlckBTROOT to txLock calls on inline btree roots
JFS uses "fake" metapages (pointers into the inode's btree root area)
for btree roots that reside inline in the inode. These fake metapages
are identified by the absence of the COMMIT_PAGE flag in xflag.
The txUnlock() and txRelease() functions check for the tlckBTROOT flag
to avoid treating these fake metapages as real disk pages. When txLock()
is called on an inline btree root without tlckBTROOT, txUnlock() later
tries to access mp->nohomeok which doesn't exist in the fake metapage
structure, causing:
BUG at fs/jfs/jfs_txnmgr.c:932 assert(mp->nohomeok > 0)
This was triggered during directory operations where dtInsert(),
dtDelete(), dtSplitUp(), dtDeleteUp(), xtInsert(), and xtSplitUp()
could operate on inline roots without setting tlckBTROOT.
Fix by adding the tlckBTROOT flag conditionally using BT_IS_ROOT()
check in all txLock() calls that may operate on inline btree roots.
This matches the existing pattern used in dtInitRoot() and
add_missing_indices().
Reported-by: syzbot+a63afa301d1258d09267@...kaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a63afa301d1258d09267
Signed-off-by: Szymon Wilczek <swilczek.lx@...il.com>
---
fs/jfs/jfs_dtree.c | 12 ++++++++----
fs/jfs/jfs_xtree.c | 9 ++++++---
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 0ab83bb7bbdf..c35f4b6f4544 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -881,7 +881,8 @@ int dtInsert(tid_t tid, struct inode *ip,
/*
* acquire a transaction lock on the leaf page
*/
- tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+ tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY |
+ (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
dtlck = (struct dt_lock *) & tlck->lock;
ASSERT(dtlck->index == 0);
lv = & dtlck->lv[0];
@@ -1258,7 +1259,8 @@ static int dtSplitUp(tid_t tid,
/*
* acquire a transaction lock on the parent page
*/
- tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+ tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY |
+ (BT_IS_ROOT(smp) ? tlckBTROOT : 0));
dtlck = (struct dt_lock *) & tlck->lock;
ASSERT(dtlck->index == 0);
lv = & dtlck->lv[0];
@@ -2161,7 +2163,8 @@ int dtDelete(tid_t tid,
/*
* acquire a transaction lock on the leaf page
*/
- tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+ tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY |
+ (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
dtlck = (struct dt_lock *) & tlck->lock;
/*
@@ -2383,7 +2386,8 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
*
* action: router entry deletion
*/
- tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+ tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY |
+ (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
dtlck = (struct dt_lock *) & tlck->lock;
/* linelock header */
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index 28c3cf960c6f..de7d4d5e67a8 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -642,7 +642,8 @@ int xtInsert(tid_t tid, /* transaction id */
/* Don't log it if there are no links to the file */
if (!test_cflag(COMMIT_Nolink, ip)) {
- tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+ tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW |
+ (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
xtlck = (struct xtlock *) & tlck->lock;
xtlck->lwm.offset =
(xtlck->lwm.offset) ? min(index,
@@ -733,7 +734,8 @@ xtSplitUp(tid_t tid,
/* Don't log it if there are no links to the file */
if (!test_cflag(COMMIT_Nolink, ip)) {
- tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+ tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW |
+ tlckBTROOT);
xtlck = (struct xtlock *) & tlck->lock;
xtlck->lwm.offset = (xtlck->lwm.offset) ?
min(skip, (int)xtlck->lwm.offset) : skip;
@@ -903,7 +905,8 @@ xtSplitUp(tid_t tid,
/* Don't log it if there are no links to the file */
if (!test_cflag(COMMIT_Nolink, ip)) {
tlck = txLock(tid, ip, smp,
- tlckXTREE | tlckGROW);
+ tlckXTREE | tlckGROW |
+ (BT_IS_ROOT(smp) ? tlckBTROOT : 0));
xtlck = (struct xtlock *) & tlck->lock;
xtlck->lwm.offset = (xtlck->lwm.offset) ?
min(skip, (int)xtlck->lwm.offset) : skip;
--
2.52.0
Powered by blists - more mailing lists