Archive-only list for syzbot
 help / color / mirror / Atom feed
From: "syzbot" <syzbot@kernel.org>
To: syzkaller-upstream-moderation@googlegroups.com
Cc: syzbot@lists.linux.dev
Subject: [PATCH RFC] jfs: replace BUG() with error return in txLock()
Date: Mon, 29 Jun 2026 22:55:11 +0000 (UTC)	[thread overview]
Message-ID: <9d2eba88-93bf-4f3c-a3b2-b554e1fffe80@mail.kernel.org> (raw)

A corrupted JFS filesystem image can cause a concurrency issue where the
block allocation map (bmap) and the inode map are out of sync.
Specifically, a block can be incorrectly marked as free in the bmap while
it is actually in use as an inode table block.

This corruption can lead to a race condition between the VFS writeback
thread and a user thread. For example, the writeback thread might lock the
inode table block's metapage to write a dirty inode. Concurrently, a user
thread might allocate the exact same block for a directory btree split (due
to the corrupted bmap) and attempt to lock its metapage. This causes
txLock() to detect that the metapage is already locked by a different
transaction for a non-aggregate inode, triggering a BUG():

------------[ cut here ]------------
kernel BUG at fs/jfs/jfs_txnmgr.c:836!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
CPU: 0 UID: 0 PID: 5543 Comm: syz.0.52 Not tainted
RIP: 0010:txLock+0x1cc3/0x1d10 fs/jfs/jfs_txnmgr.c:836
...
Call Trace:
 <TASK>
 dtSplitRoot+0x38d/0x18a0 fs/jfs/jfs_dtree.c:1924
 dtSplitUp fs/jfs/jfs_dtree.c:990 [inline]
 dtInsert+0xeb2/0x5890 fs/jfs/jfs_dtree.c:868
 jfs_create+0x730/0xae0 fs/jfs/namei.c:138
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x133a/0x3830 fs/namei.c:4856
 do_file_open+0x23e/0x4a0 fs/namei.c:4888
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_open fs/open.c:1382 [inline]
 __se_sys_open fs/open.c:1378 [inline]
 __x64_sys_open+0x11e/0x150 fs/open.c:1378
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x15f/0x560 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
 </TASK>

To fix this, replace the BUG() in txLock() with a call to jfs_error() to
mark the filesystem as corrupted, and return ERR_PTR(-EIO) to gracefully
handle the error.

Since txLock() can now return an error pointer, update all of its callers
across the JFS codebase to check for IS_ERR() and properly propagate the
error up the call stack. This includes changing the return types of several
helper functions (such as lock_index(), free_index(), modify_index(),
dtInitRoot(), xtInitRoot(), and dtInsertEntry()) from void to int, and
ensuring that resources like pinned metapages are properly released on the
new error paths.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: good-balanced Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview best-expensive syzbot
Reported-by: syzbot+a843f6ae2130a987d63b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a843f6ae2130a987d63b
Link: https://syzkaller.appspot.com/ai_job?id=62ec5f45-38f7-4129-96f4-2509f8ed6b21
To: <jfs-discussion@lists.sourceforge.net>
To: "Dave Kleikamp" <shaggy@kernel.org>
Cc: "Arnd Bergmann" <arnd@arndb.de>
Cc: "Christian Brauner (Amutable)" <brauner@kernel.org>
Cc: "Damien Le Moal" <dlemoal@kernel.org>
Cc: "Jan Kara" <jack@suse.cz>
Cc: "Jori Koolstra" <jkoolstra@xs4all.nl>
Cc: "Jeff Layton" <jlayton@kernel.org>
Cc: "Kees Cook" <kees@kernel.org>
Cc: <linux-kernel@vger.kernel.org>
Cc: "Mateusz Guzik" <mjguzik@gmail.com>
Cc: "Richard Weinberger" <richard@nod.at>
Cc: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
Cc: "Shaurya Rane" <ssrane_b23@ee.vjti.ac.in>
Cc: "Suchit Karunakaran" <suchitkarunakaran@gmail.com>
Cc: "Al Viro" <viro@zeniv.linux.org.uk>
Cc: "Yun Zhou" <yun.zhou@windriver.com>
Cc: "Hongling Zeng" <zenghongling@kylinos.cn>
Cc: "Zheng Yu" <zheng.yu@northwestern.edu>

---
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 8ce6e4458..936e408ab 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -167,8 +167,8 @@ static void dtGetKey(dtpage_t * p, int i, struct component_name * key,
 static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
 			      int ri, struct component_name * key, int flag);
 
-static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
-			  ddata_t * data, struct dt_lock **);
+static int dtInsertEntry(dtpage_t *p, int index, struct component_name *key,
+			 ddata_t *data, struct dt_lock **);
 
 static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
 			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
@@ -286,14 +286,16 @@ static struct dir_table_slot *find_index(struct inode *ip, u32 index,
 	return slot;
 }
 
-static inline void lock_index(tid_t tid, struct inode *ip, struct metapage * mp,
-			      u32 index)
+static inline int lock_index(tid_t tid, struct inode *ip, struct metapage *mp,
+			     u32 index)
 {
 	struct tlock *tlck;
 	struct linelock *llck;
 	struct lv *lv;
 
 	tlck = txLock(tid, ip, mp, tlckDATA);
+	if (IS_ERR(tlck))
+		return PTR_ERR(tlck);
 	llck = (struct linelock *) tlck->lock;
 
 	if (llck->index >= llck->maxcnt)
@@ -307,6 +309,8 @@ static inline void lock_index(tid_t tid, struct inode *ip, struct metapage * mp,
 	lv->offset = ((index - 2) & 511) >> 1;
 	lv->length = 1;
 	llck->index++;
+
+	return 0;
 }
 
 /*
@@ -383,7 +387,13 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
 		/*
 		 * Initialize empty x-tree
 		 */
-		xtInitRoot(tid, ip);
+		if (xtInitRoot(tid, ip)) {
+			memcpy(&jfs_ip->i_dirtable, temp_table,
+			       sizeof(temp_table));
+			dbFree(ip, xaddr, sbi->nbperpage);
+			dquot_free_block(ip, sbi->nbperpage);
+			goto clean_up;
+		}
 
 		/*
 		 * Add the first block to the xtree
@@ -408,6 +418,13 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
 			goto clean_up;
 		}
 		tlck = txLock(tid, ip, mp, tlckDATA);
+		if (IS_ERR(tlck)) {
+			release_metapage(mp);
+			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+			memcpy(&jfs_ip->i_dirtable, temp_table,
+			       sizeof(temp_table));
+			goto clean_up;
+		}
 		llck = (struct linelock *) & tlck->lock;
 		ASSERT(llck->index == 0);
 		lv = &llck->lv[0];
@@ -453,7 +470,10 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
 		goto clean_up;
 	}
 
-	lock_index(tid, ip, mp, index);
+	if (lock_index(tid, ip, mp, index)) {
+		release_metapage(mp);
+		goto clean_up;
+	}
 
 	dirtab_slot =
 	    (struct dir_table_slot *) ((char *) mp->data + page_offset);
@@ -478,27 +498,31 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
  *
  *	Marks an entry to the directory index table as free.
  */
-static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
+static int free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
 {
 	struct dir_table_slot *dirtab_slot;
 	s64 lblock;
 	struct metapage *mp = NULL;
+	int rc = 0;
 
 	dirtab_slot = find_index(ip, index, &mp, &lblock);
 
 	if (!dirtab_slot)
-		return;
+		return 0;
 
 	dirtab_slot->flag = DIR_INDEX_FREE;
 	dirtab_slot->slot = dirtab_slot->addr1 = 0;
 	dirtab_slot->addr2 = cpu_to_le32(next);
 
 	if (mp) {
-		lock_index(tid, ip, mp, index);
-		mark_metapage_dirty(mp);
+		rc = lock_index(tid, ip, mp, index);
+		if (!rc)
+			mark_metapage_dirty(mp);
 		release_metapage(mp);
 	} else
 		set_cflag(COMMIT_Dirtable, ip);
+
+	return rc;
 }
 
 /*
@@ -506,24 +530,28 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
  *
  *	Changes an entry in the directory index table
  */
-static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
-			 int slot, struct metapage ** mp, s64 *lblock)
+static int modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
+			int slot, struct metapage **mp, s64 *lblock)
 {
 	struct dir_table_slot *dirtab_slot;
+	int rc = 0;
 
 	dirtab_slot = find_index(ip, index, mp, lblock);
 
 	if (!dirtab_slot)
-		return;
+		return 0;
 
 	DTSaddress(dirtab_slot, bn);
 	dirtab_slot->slot = slot;
 
 	if (*mp) {
-		lock_index(tid, ip, *mp, index);
-		mark_metapage_dirty(*mp);
+		rc = lock_index(tid, ip, *mp, index);
+		if (!rc)
+			mark_metapage_dirty(*mp);
 	} else
 		set_cflag(COMMIT_Dirtable, ip);
+
+	return rc;
 }
 
 /*
@@ -879,6 +907,10 @@ int dtInsert(tid_t tid, struct inode *ip,
 	 * acquire a transaction lock on the leaf page
 	 */
 	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(mp);
+		return PTR_ERR(tlck);
+	}
 	dtlck = (struct dt_lock *) & tlck->lock;
 	ASSERT(dtlck->index == 0);
 	lv = & dtlck->lv[0];
@@ -888,7 +920,11 @@ int dtInsert(tid_t tid, struct inode *ip,
 	lv->length = 1;
 	dtlck->index++;
 
-	dtInsertEntry(p, index, name, &data, &dtlck);
+	rc = dtInsertEntry(p, index, name, &data, &dtlck);
+	if (rc) {
+		DT_PUTPAGE(mp);
+		return rc;
+	}
 
 	/* linelock stbl of non-root leaf page */
 	if (!(p->header.flag & BT_ROOT)) {
@@ -1256,9 +1292,15 @@ static int dtSplitUp(tid_t tid,
 			 * acquire a transaction lock on the parent page
 			 */
 			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
-			dtlck = (struct dt_lock *) & tlck->lock;
+			if (IS_ERR(tlck)) {
+				rc = PTR_ERR(tlck);
+				DT_PUTPAGE(smp);
+				DT_PUTPAGE(rmp);
+				goto splitOut;
+			}
+			dtlck = (struct dt_lock *)&tlck->lock;
 			ASSERT(dtlck->index == 0);
-			lv = & dtlck->lv[0];
+			lv = &dtlck->lv[0];
 
 			/* linelock header */
 			lv->offset = 0;
@@ -1270,13 +1312,18 @@ static int dtSplitUp(tid_t tid,
 				lv++;
 				n = skip >> L2DTSLOTSIZE;
 				lv->offset = sp->header.stblindex + n;
-				lv->length =
-				    ((sp->header.nextindex -
-				      1) >> L2DTSLOTSIZE) - n + 1;
+				lv->length = ((sp->header.nextindex - 1) >>
+					      L2DTSLOTSIZE) -
+					     n + 1;
 				dtlck->index++;
 			}
 
-			dtInsertEntry(sp, skip, &key, data, &dtlck);
+			rc = dtInsertEntry(sp, skip, &key, data, &dtlck);
+			if (rc) {
+				DT_PUTPAGE(smp);
+				DT_PUTPAGE(rmp);
+				goto splitOut;
+			}
 
 			/* exit propagate up */
 			break;
@@ -1375,6 +1422,10 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
 	 * acquire a transaction lock on the new right page
 	 */
 	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(rmp);
+		return PTR_ERR(tlck);
+	}
 	rdtlck = (struct dt_lock *) & tlck->lock;
 
 	rp = (dtpage_t *) rmp->data;
@@ -1388,6 +1439,10 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
 	 * action:
 	 */
 	tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(rmp);
+		return PTR_ERR(tlck);
+	}
 	sdtlck = (struct dt_lock *) & tlck->lock;
 
 	/* linelock header of split page */
@@ -1452,7 +1507,11 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
 		f->next = -1;
 
 		/* insert entry at the first entry of the new right page */
-		dtInsertEntry(rp, 0, split->key, split->data, &rdtlck);
+		rc = dtInsertEntry(rp, 0, split->key, split->data, &rdtlck);
+		if (rc) {
+			DT_PUTPAGE(rmp);
+			return rc;
+		}
 
 		goto out;
 	}
@@ -1476,6 +1535,11 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
 		 * acquire a transaction lock on the next page
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		if (IS_ERR(tlck)) {
+			DT_PUTPAGE(mp);
+			DT_PUTPAGE(rmp);
+			return PTR_ERR(tlck);
+		}
 		jfs_info("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p",
 			tlck, ip, mp);
 		dtlck = (struct dt_lock *) & tlck->lock;
@@ -1577,40 +1641,54 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
 		mp = NULL;
 		stbl = DT_GETSTBL(rp);
 		for (n = 0; n < rp->header.nextindex; n++) {
-			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
-			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp, &lblock);
+			ldtentry = (struct ldtentry *)&rp->slot[stbl[n]];
+			rc = modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+					  rbn, n, &mp, &lblock);
+			if (rc)
+				break;
 		}
 		if (mp)
 			release_metapage(mp);
+		if (rc) {
+			DT_PUTPAGE(rmp);
+			return rc;
+		}
 	}
 
 	/*
-	 * the skipped index was on the left page,
-	 */
+		 * the skipped index was on the left page,
+		 */
 	if (skip <= off) {
 		/* insert the new entry in the split page */
-		dtInsertEntry(sp, skip, split->key, split->data, &sdtlck);
+		rc = dtInsertEntry(sp, skip, split->key, split->data, &sdtlck);
+		if (rc) {
+			DT_PUTPAGE(rmp);
+			return rc;
+		}
 
 		/* linelock stbl of split page */
 		if (sdtlck->index >= sdtlck->maxcnt)
-			sdtlck = (struct dt_lock *) txLinelock(sdtlck);
-		slv = & sdtlck->lv[sdtlck->index];
+			sdtlck = (struct dt_lock *)txLinelock(sdtlck);
+		slv = &sdtlck->lv[sdtlck->index];
 		n = skip >> L2DTSLOTSIZE;
 		slv->offset = sp->header.stblindex + n;
 		slv->length =
-		    ((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
+			((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
 		sdtlck->index++;
 	}
 	/*
-	 * the skipped index was on the right page,
-	 */
+		 * the skipped index was on the right page,
+		 */
 	else {
 		/* adjust the skip index to reflect the new position */
 		skip -= nxt;
 
 		/* insert the new entry in the right page */
-		dtInsertEntry(rp, skip, split->key, split->data, &rdtlck);
+		rc = dtInsertEntry(rp, skip, split->key, split->data, &rdtlck);
+		if (rc) {
+			DT_PUTPAGE(rmp);
+			return rc;
+		}
 	}
 
       out:
@@ -1702,13 +1780,19 @@ static int dtExtendPage(tid_t tid,
 			stbl = DT_GETSTBL(sp);
 			for (n = 0; n < sp->header.nextindex; n++) {
 				ldtentry =
-				    (struct ldtentry *) & sp->slot[stbl[n]];
-				modify_index(tid, ip,
-					     le32_to_cpu(ldtentry->index),
-					     xaddr, n, &mp, &lblock);
+					(struct ldtentry *)&sp->slot[stbl[n]];
+				rc = modify_index(tid, ip,
+						  le32_to_cpu(ldtentry->index),
+						  xaddr, n, &mp, &lblock);
+				if (rc)
+					break;
 			}
 			if (mp)
 				release_metapage(mp);
+			if (rc) {
+				DT_PUTPAGE(pmp);
+				return rc;
+			}
 		}
 	}
 
@@ -1724,7 +1808,11 @@ static int dtExtendPage(tid_t tid,
 	 * acquire a transaction lock on the extended/leaf page
 	 */
 	tlck = txLock(tid, ip, smp, tlckDTREE | type);
-	dtlck = (struct dt_lock *) & tlck->lock;
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(pmp);
+		return PTR_ERR(tlck);
+	}
+	dtlck = (struct dt_lock *)&tlck->lock;
 	lv = & dtlck->lv[0];
 
 	/* update buffer extent descriptor of extended page */
@@ -1811,7 +1899,11 @@ static int dtExtendPage(tid_t tid,
 	/*
 	 * insert the new entry
 	 */
-	dtInsertEntry(sp, split->index, split->key, split->data, &dtlck);
+	rc = dtInsertEntry(sp, split->index, split->key, split->data, &dtlck);
+	if (rc) {
+		DT_PUTPAGE(pmp);
+		return rc;
+	}
 
 	BT_MARK_DIRTY(pmp, ip);
 	/*
@@ -1830,8 +1922,12 @@ static int dtExtendPage(tid_t tid,
 	 * acquire a transaction lock on the parent/root page
 	 */
 	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
-	dtlck = (struct dt_lock *) & tlck->lock;
-	lv = & dtlck->lv[dtlck->index];
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(pmp);
+		return PTR_ERR(tlck);
+	}
+	dtlck = (struct dt_lock *)&tlck->lock;
+	lv = &dtlck->lv[dtlck->index];
 
 	/* linelock parent entry - 1st slot */
 	lv->offset = 1;
@@ -1922,6 +2018,10 @@ static int dtSplitRoot(tid_t tid,
 	 * acquire a transaction lock on the new right page
 	 */
 	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(rmp);
+		return PTR_ERR(tlck);
+	}
 	dtlck = (struct dt_lock *) & tlck->lock;
 
 	rp->header.flag =
@@ -1993,17 +2093,27 @@ static int dtSplitRoot(tid_t tid,
 		stbl = DT_GETSTBL(rp);
 		for (n = 0; n < rp->header.nextindex; n++) {
 			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
-			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp, &lblock);
+			rc = modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+					  rbn, n, &mp, &lblock);
+			if (rc)
+				break;
 		}
 		if (mp)
 			release_metapage(mp);
+		if (rc) {
+			DT_PUTPAGE(rmp);
+			return rc;
+		}
 	}
 	/*
 	 * insert the new entry into the new right/child page
 	 * (skip index in the new right page will not change)
 	 */
-	dtInsertEntry(rp, split->index, split->key, split->data, &dtlck);
+	rc = dtInsertEntry(rp, split->index, split->key, split->data, &dtlck);
+	if (rc) {
+		DT_PUTPAGE(rmp);
+		return rc;
+	}
 
 	/*
 	 *	reset parent/root page
@@ -2019,6 +2129,10 @@ static int dtSplitRoot(tid_t tid,
 	 * acquire a transaction lock on the root page (in-memory inode)
 	 */
 	tlck = txLock(tid, ip, smp, tlckDTREE | tlckNEW | tlckBTROOT);
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(rmp);
+		return PTR_ERR(tlck);
+	}
 	dtlck = (struct dt_lock *) & tlck->lock;
 
 	/* linelock root */
@@ -2139,7 +2253,11 @@ int dtDelete(tid_t tid,
 			    (struct ldtentry *) & p->slot[stbl[index + 1]];
 			next_index = le32_to_cpu(ldtentry->index);
 		}
-		free_index(tid, ip, table_index, next_index);
+		rc = free_index(tid, ip, table_index, next_index);
+		if (rc) {
+			DT_PUTPAGE(mp);
+			return rc;
+		}
 	}
 	/*
 	 * the leaf page becomes empty, delete the page
@@ -2159,6 +2277,10 @@ int dtDelete(tid_t tid,
 		 * acquire a transaction lock on the leaf page
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		if (IS_ERR(tlck)) {
+			DT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/*
@@ -2202,12 +2324,18 @@ int dtDelete(tid_t tid,
 			for (i = index; i < p->header.nextindex; i++) {
 				ldtentry =
 				    (struct ldtentry *) & p->slot[stbl[i]];
-				modify_index(tid, ip,
-					     le32_to_cpu(ldtentry->index),
-					     bn, i, &imp, &lblock);
+				rc = modify_index(tid, ip,
+						  le32_to_cpu(ldtentry->index),
+						  bn, i, &imp, &lblock);
+				if (rc)
+					break;
 			}
 			if (imp)
 				release_metapage(imp);
+			if (rc) {
+				DT_PUTPAGE(mp);
+				return rc;
+			}
 		}
 
 		DT_PUTPAGE(mp);
@@ -2251,11 +2379,11 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
 		 *
 		 * dtInitRoot() acquires txlock on the root
 		 */
-		dtInitRoot(tid, ip, PARENT(ip));
+		rc = dtInitRoot(tid, ip, PARENT(ip));
 
 		DT_PUTPAGE(fmp);
 
-		return 0;
+		return rc;
 	}
 
 	/*
@@ -2319,19 +2447,19 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
 		 */
 		if (nextindex == 1) {
 			/*
-			 * keep the root internal page which has become empty
-			 */
+				 * keep the root internal page which has become empty
+				 */
 			if (p->header.flag & BT_ROOT) {
 				/*
-				 * reset the root
-				 *
-				 * dtInitRoot() acquires txlock on the root
-				 */
-				dtInitRoot(tid, ip, PARENT(ip));
+					 * reset the root
+					 *
+					 * dtInitRoot() acquires txlock on the root
+					 */
+				rc = dtInitRoot(tid, ip, PARENT(ip));
 
 				DT_PUTPAGE(mp);
 
-				return 0;
+				return rc;
 			}
 			/*
 			 * free the parent page
@@ -2381,6 +2509,10 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
 		 * action: router entry deletion
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		if (IS_ERR(tlck)) {
+			DT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
@@ -2464,6 +2596,10 @@ static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
 		 * action: update prev pointer;
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		if (IS_ERR(tlck)) {
+			DT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		jfs_info("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p",
 			tlck, ip, mp);
 		dtlck = (struct dt_lock *) & tlck->lock;
@@ -2493,6 +2629,10 @@ static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
 		 * action: update next pointer;
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		if (IS_ERR(tlck)) {
+			DT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		jfs_info("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p",
 			tlck, ip, mp);
 		dtlck = (struct dt_lock *) & tlck->lock;
@@ -2518,7 +2658,7 @@ static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
  *
  * initialize directory root (inline in inode)
  */
-void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
+int dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	dtroot_t *p;
@@ -2570,6 +2710,8 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
 	 */
 	tlck = txLock(tid, ip, (struct metapage *) & jfs_ip->bxflag,
 		      tlckDTREE | tlckENTRY | tlckBTROOT);
+	if (IS_ERR(tlck))
+		return PTR_ERR(tlck);
 	dtlck = (struct dt_lock *) & tlck->lock;
 
 	/* linelock root */
@@ -2600,7 +2742,7 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
 	/* init '..' entry */
 	p->header.idotdot = cpu_to_le32(idotdot);
 
-	return;
+	return 0;
 }
 
 /*
@@ -2637,6 +2779,12 @@ static int add_missing_indices(struct inode *inode, s64 bn)
 	ASSERT(p->header.flag & BT_LEAF);
 
 	tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY);
+	if (IS_ERR(tlck)) {
+		rc = PTR_ERR(tlck);
+		DT_PUTPAGE(mp);
+		txAbort(tid, 0);
+		goto end;
+	}
 	if (BT_IS_ROOT(mp))
 		tlck->type |= tlckBTROOT;
 
@@ -3624,8 +3772,8 @@ static void dtGetKey(dtpage_t * p, int i,	/* entry index */
  *
  * return: entry slot index
  */
-static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
-			  ddata_t * data, struct dt_lock ** dtlock)
+static int dtInsertEntry(dtpage_t *p, int index, struct component_name *key,
+			 ddata_t *data, struct dt_lock **dtlock)
 {
 	struct dtslot *h, *t;
 	struct ldtentry *lh = NULL;
@@ -3640,6 +3788,7 @@ static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
 	int xsi, n;
 	s64 bn = 0;
 	struct metapage *mp = NULL;
+	int rc = 0;
 
 	klen = key->namlen;
 	kname = key->name;
@@ -3752,18 +3901,22 @@ static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
 			s64 lblock;
 
 			/*
-			 * Need to update slot number for entries that moved
-			 * in the stbl
-			 */
+				 * Need to update slot number for entries that moved
+				 * in the stbl
+				 */
 			mp = NULL;
 			for (n = index + 1; n <= nextindex; n++) {
-				lh = (struct ldtentry *) & (p->slot[stbl[n]]);
-				modify_index(data->leaf.tid, data->leaf.ip,
-					     le32_to_cpu(lh->index), bn, n,
-					     &mp, &lblock);
+				lh = (struct ldtentry *)&(p->slot[stbl[n]]);
+				rc = modify_index(data->leaf.tid, data->leaf.ip,
+						  le32_to_cpu(lh->index), bn, n,
+						  &mp, &lblock);
+				if (rc)
+					break;
 			}
 			if (mp)
 				release_metapage(mp);
+			if (rc)
+				return rc;
 		}
 	}
 
@@ -3771,8 +3924,9 @@ static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
 
 	/* advance next available entry index of stbl */
 	++p->header.nextindex;
-}
 
+	return 0;
+}
 
 /*
  *	dtMoveEntry()
@@ -4270,6 +4424,10 @@ int dtModify(tid_t tid, struct inode *ip,
 	 * acquire a transaction lock on the leaf page of named entry
 	 */
 	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	if (IS_ERR(tlck)) {
+		DT_PUTPAGE(mp);
+		return PTR_ERR(tlck);
+	}
 	dtlck = (struct dt_lock *) & tlck->lock;
 
 	/* get slot index of the entry */
diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
index dfc87b669..33528521f 100644
--- a/fs/jfs/jfs_dtree.h
+++ b/fs/jfs/jfs_dtree.h
@@ -238,7 +238,7 @@ typedef union {
 /*
  *	external declarations
  */
-extern void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot);
+extern int dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot);
 
 extern int dtSearch(struct inode *ip, struct component_name * key,
 		    ino_t * data, struct btstack * btstack, int flag);
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index b84ba4d7d..4a0f76501 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -650,8 +650,12 @@ int diWrite(tid_t tid, struct inode *ip)
 	 * acquire transaction lock on the on-disk inode;
 	 * N.B. tlock is acquired on ipimap not ip;
 	 */
-	if ((ditlck =
-	     txLock(tid, ipimap, mp, tlckINODE | tlckENTRY)) == NULL)
+	ditlck = txLock(tid, ipimap, mp, tlckINODE | tlckENTRY);
+	if (IS_ERR(ditlck)) {
+		release_metapage(mp);
+		return PTR_ERR(ditlck);
+	}
+	if (ditlck == NULL)
 		goto retry;
 	dilinelock = (struct linelock *) & ditlck->lock;
 
@@ -1231,6 +1235,7 @@ int diFree(struct inode *ip)
 	tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
 	mutex_lock(&JFS_IP(ipimap)->commit_mutex);
 
+retry:
 	/* acquire tlock of the iag page of the freed ixad
 	 * to force the page NOHOMEOK (even though no data is
 	 * logged from the iag page) until NOREDOPAGE|FREEXTENT log
@@ -1239,6 +1244,16 @@ int diFree(struct inode *ip)
 	 * N.B. linelock is overlaid as freed extent descriptor;
 	 */
 	tlck = txLock(tid, ipimap, mp, tlckINODE | tlckFREE);
+	if (IS_ERR(tlck)) {
+		rc = PTR_ERR(tlck);
+		txAbort(tid, 0);
+		mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
+		AG_UNLOCK(imap, agno);
+		release_metapage(mp);
+		return rc;
+	}
+	if (tlck == NULL)
+		goto retry;
 	pxdlock = (struct pxd_lock *) & tlck->lock;
 	pxdlock->flag = mlckFREEPXD;
 	pxdlock->pxd = freepxd;
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 083dbbb0c..f5e28dc24 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -820,39 +820,32 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
 	 * page is being locked by another transaction:
 	 */
       waitLock:
-	/* Only locks on ipimap or ipaimap should reach here */
-	/* assert(jfs_ip->fileset == AGGREGATE_I); */
-	if (jfs_ip->fileset != AGGREGATE_I) {
-		printk(KERN_ERR "txLock: trying to lock locked page!");
-		print_hex_dump(KERN_ERR, "ip: ", DUMP_PREFIX_ADDRESS, 16, 4,
-			       ip, sizeof(*ip), 0);
-		print_hex_dump(KERN_ERR, "mp: ", DUMP_PREFIX_ADDRESS, 16, 4,
-			       mp, sizeof(*mp), 0);
-		print_hex_dump(KERN_ERR, "Locker's tblock: ",
-			       DUMP_PREFIX_ADDRESS, 16, 4, tid_to_tblock(tid),
-			       sizeof(struct tblock), 0);
-		print_hex_dump(KERN_ERR, "Tlock: ", DUMP_PREFIX_ADDRESS, 16, 4,
-			       tlck, sizeof(*tlck), 0);
-		BUG();
-	}
-	INCREMENT(stattx.waitlock);	/* statistics */
-	TXN_UNLOCK();
-	release_metapage(mp);
-	TXN_LOCK();
-	xtid = tlck->tid;	/* reacquire after dropping TXN_LOCK */
-
-	jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
-		 tid, xtid, lid);
-
-	/* Recheck everything since dropping TXN_LOCK */
-	if (xtid && (tlck->mp == mp) && (mp->lid == lid))
-		TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
-	else
-		TXN_UNLOCK();
-	jfs_info("txLock: awakened     tid = %d, lid = %d", tid, lid);
-
-	return NULL;
-}
+	      /* Only locks on ipimap or ipaimap should reach here */
+	      /* assert(jfs_ip->fileset == AGGREGATE_I); */
+	      if (jfs_ip->fileset != AGGREGATE_I) {
+		      TXN_UNLOCK();
+		      jfs_error(ip->i_sb,
+				"txLock: trying to lock locked page!\n");
+		      return ERR_PTR(-EIO);
+	      }
+	      INCREMENT(stattx.waitlock); /* statistics */
+	      TXN_UNLOCK();
+	      release_metapage(mp);
+	      TXN_LOCK();
+	      xtid = tlck->tid; /* reacquire after dropping TXN_LOCK */
+
+	      jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
+		       tid, xtid, lid);
+
+	      /* Recheck everything since dropping TXN_LOCK */
+	      if (xtid && (tlck->mp == mp) && (mp->lid == lid))
+		      TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+	      else
+		      TXN_UNLOCK();
+	      jfs_info("txLock: awakened     tid = %d, lid = %d", tid, lid);
+
+	      return NULL;
+      }
 
 /*
  * NAME:	txRelease()
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index 28c3cf960..2944a8dbd 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -643,6 +643,10 @@ 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);
+		if (IS_ERR(tlck)) {
+			rc = PTR_ERR(tlck);
+			goto out;
+		}
 		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset =
 		    (xtlck->lwm.offset) ? min(index,
@@ -734,6 +738,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);
+			if (IS_ERR(tlck))
+				return PTR_ERR(tlck);
 			xtlck = (struct xtlock *) & tlck->lock;
 			xtlck->lwm.offset = (xtlck->lwm.offset) ?
 			    min(skip, (int)xtlck->lwm.offset) : skip;
@@ -904,6 +910,11 @@ xtSplitUp(tid_t tid,
 			if (!test_cflag(COMMIT_Nolink, ip)) {
 				tlck = txLock(tid, ip, smp,
 					      tlckXTREE | tlckGROW);
+				if (IS_ERR(tlck)) {
+					XT_PUTPAGE(smp);
+					XT_PUTPAGE(rmp);
+					return PTR_ERR(tlck);
+				}
 				xtlck = (struct xtlock *) & tlck->lock;
 				xtlck->lwm.offset = (xtlck->lwm.offset) ?
 				    min(skip, (int)xtlck->lwm.offset) : skip;
@@ -1012,12 +1023,22 @@ xtSplitPage(tid_t tid, struct inode *ip,
 		 * acquire a transaction lock on the new right page;
 		 */
 		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
+		if (IS_ERR(tlck)) {
+			rc = PTR_ERR(tlck);
+			XT_PUTPAGE(rmp);
+			goto clean_up;
+		}
 		rxtlck = (struct xtlock *) & tlck->lock;
 		rxtlck->lwm.offset = XTENTRYSTART;
 		/*
 		 * acquire a transaction lock on the split page
 		 */
 		tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+		if (IS_ERR(tlck)) {
+			rc = PTR_ERR(tlck);
+			XT_PUTPAGE(rmp);
+			goto clean_up;
+		}
 		sxtlck = (struct xtlock *) & tlck->lock;
 	}
 
@@ -1089,8 +1110,15 @@ xtSplitPage(tid_t tid, struct inode *ip,
 		 *
 		 * action:sibling pointer update;
 		 */
-		if (!test_cflag(COMMIT_Nolink, ip))
+		if (!test_cflag(COMMIT_Nolink, ip)) {
 			tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+			if (IS_ERR(tlck)) {
+				rc = PTR_ERR(tlck);
+				XT_PUTPAGE(mp);
+				XT_PUTPAGE(rmp);
+				goto clean_up;
+			}
+		}
 
 		p->header.prev = cpu_to_le64(rbn);
 
@@ -1295,6 +1323,10 @@ xtSplitRoot(tid_t tid,
 
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
+		if (IS_ERR(tlck)) {
+			XT_PUTPAGE(rmp);
+			return PTR_ERR(tlck);
+		}
 		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset = XTENTRYSTART;
 		xtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
@@ -1326,6 +1358,10 @@ xtSplitRoot(tid_t tid,
 
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, split->mp, tlckXTREE | tlckGROW);
+		if (IS_ERR(tlck)) {
+			XT_PUTPAGE(rmp);
+			return PTR_ERR(tlck);
+		}
 		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset = XTENTRYSTART;
 		xtlck->lwm.length = 1;
@@ -1397,6 +1433,10 @@ int xtExtend(tid_t tid,		/* transaction id */
 	BT_MARK_DIRTY(mp, ip);
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		if (IS_ERR(tlck)) {
+			XT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		xtlck = (struct xtlock *) & tlck->lock;
 	}
 
@@ -1552,6 +1592,10 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 	 */
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		if (IS_ERR(tlck)) {
+			XT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		xtlck = (struct xtlock *) & tlck->lock;
 	}
 
@@ -1730,10 +1774,10 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 		if (IS_ERR(p))
 			return PTR_ERR(p);
 		/*
-		 * if leaf root has been split, original root has been
-		 * copied to new child page, i.e., original entry now
-		 * resides on the new child page;
-		 */
+			 * if leaf root has been split, original root has been
+			 * copied to new child page, i.e., original entry now
+			 * resides on the new child page;
+			 */
 		if (p->header.flag & BT_INTERNAL) {
 			ASSERT(p->header.nextindex ==
 			       cpu_to_le16(XTENTRYSTART + 1));
@@ -1748,8 +1792,13 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 
 			BT_MARK_DIRTY(mp, ip);
 			if (!test_cflag(COMMIT_Nolink, ip)) {
-				tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
-				xtlck = (struct xtlock *) & tlck->lock;
+				tlck = txLock(tid, ip, mp,
+					      tlckXTREE | tlckGROW);
+				if (IS_ERR(tlck)) {
+					XT_PUTPAGE(mp);
+					return PTR_ERR(tlck);
+				}
+				xtlck = (struct xtlock *)&tlck->lock;
 			}
 		} else {
 			/* is nXAD on new page ? */
@@ -1810,6 +1859,10 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 		BT_MARK_DIRTY(mp, ip);
 		if (!test_cflag(COMMIT_Nolink, ip)) {
 			tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+			if (IS_ERR(tlck)) {
+				XT_PUTPAGE(mp);
+				return PTR_ERR(tlck);
+			}
 			xtlck = (struct xtlock *) & tlck->lock;
 		}
 
@@ -1902,8 +1955,13 @@ printf("xtUpdate.updateLeft.split p:0x%p\n", p);
 
 			BT_MARK_DIRTY(mp, ip);
 			if (!test_cflag(COMMIT_Nolink, ip)) {
-				tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
-				xtlck = (struct xtlock *) & tlck->lock;
+				tlck = txLock(tid, ip, mp,
+					      tlckXTREE | tlckGROW);
+				if (IS_ERR(tlck)) {
+					XT_PUTPAGE(mp);
+					return PTR_ERR(tlck);
+				}
+				xtlck = (struct xtlock *)&tlck->lock;
 			}
 		}
 	} else {
@@ -2082,6 +2140,10 @@ int xtAppend(tid_t tid,		/* transaction id */
 	 * action: xad insertion/extension;
 	 */
 	tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+	if (IS_ERR(tlck)) {
+		rc = PTR_ERR(tlck);
+		goto out;
+	}
 	xtlck = (struct xtlock *) & tlck->lock;
 
 	/* insert the new entry: mark the entry NEW */
@@ -2111,17 +2173,21 @@ int xtAppend(tid_t tid,		/* transaction id */
  *
  * initialize file root (inline in inode)
  */
-void xtInitRoot(tid_t tid, struct inode *ip)
+int xtInitRoot(tid_t tid, struct inode *ip)
 {
 	xtroot_t *p;
+	struct tlock *tlck;
 
 	/*
 	 * acquire a transaction lock on the root
 	 *
 	 * action:
 	 */
-	txLock(tid, ip, (struct metapage *) &JFS_IP(ip)->bxflag,
+	tlck = txLock(tid, ip, (struct metapage *)&JFS_IP(ip)->bxflag,
 		      tlckXTREE | tlckNEW);
+	if (IS_ERR(tlck))
+		return PTR_ERR(tlck);
+
 	p = &JFS_IP(ip)->i_xtroot;
 
 	p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
@@ -2134,8 +2200,7 @@ void xtInitRoot(tid_t tid, struct inode *ip)
 		ip->i_size = 0;
 	}
 
-
-	return;
+	return 0;
 }
 
 
@@ -2295,13 +2360,18 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
 	 * sure that the next pointer is zero.
 	 */
 	if (p->header.next) {
-		if (log)
+		if (log) {
 			/*
-			 * Make sure this change to the header is logged.
-			 * If we really truncate this leaf, the flag
-			 * will be changed to tlckTRUNCATE
-			 */
-			tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
+				 * Make sure this change to the header is logged.
+				 * If we really truncate this leaf, the flag
+				 * will be changed to tlckTRUNCATE
+				 */
+			tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+			if (IS_ERR(tlck)) {
+				XT_PUTPAGE(mp);
+				return PTR_ERR(tlck);
+			}
+		}
 		BT_MARK_DIRTY(mp, ip);
 		p->header.next = 0;
 	}
@@ -2310,8 +2380,8 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
 		goto getChild;
 
 	/*
-	 *	leaf page
-	 */
+		 *	leaf page
+		 */
 	freed = 0;
 
 	/* does region covered by leaf page precede Teof ? */
@@ -2327,16 +2397,20 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
 	if (log) {
 		if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
 			/*
-			 * We need to limit the size of the transaction
-			 * to avoid exhausting pagecache & tlocks
-			 */
+				 * We need to limit the size of the transaction
+				 * to avoid exhausting pagecache & tlocks
+				 */
 			XT_PUTPAGE(mp);
 			newsize = (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
 			goto getParent;
 		}
 		tlck = txLock(tid, ip, mp, tlckXTREE);
+		if (IS_ERR(tlck)) {
+			XT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
 		tlck->type = tlckXTREE | tlckTRUNCATE;
-		xtlck = (struct xtlock *) & tlck->lock;
+		xtlck = (struct xtlock *)&tlck->lock;
 		xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
 	}
 	BT_MARK_DIRTY(mp, ip);
@@ -2533,20 +2607,24 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
 		/* has any entry deleted from parent ? */
 		if (index < le16_to_cpu(p->header.nextindex) - 1) {
 			/* (re)acquire tlock on the parent page */
-			if (log) {	/* COMMIT_PWMAP */
+			if (log) { /* COMMIT_PWMAP */
 				/* txCommit() with tlckTRUNCATE:
-				 * free child extents covered by parent [);
-				 */
+					 * free child extents covered by parent [);
+					 */
 				tlck = txLock(tid, ip, mp, tlckXTREE);
-				xtlck = (struct xtlock *) & tlck->lock;
+				if (IS_ERR(tlck)) {
+					XT_PUTPAGE(mp);
+					return PTR_ERR(tlck);
+				}
+				xtlck = (struct xtlock *)&tlck->lock;
 				if (!(tlck->type & tlckTRUNCATE)) {
 					xtlck->hwm.offset =
-					    le16_to_cpu(p->header.
-							nextindex) - 1;
-					tlck->type =
-					    tlckXTREE | tlckTRUNCATE;
+						le16_to_cpu(
+							p->header.nextindex) -
+						1;
+					tlck->type = tlckXTREE | tlckTRUNCATE;
 				}
-			} else {	/* COMMIT_WMAP */
+			} else { /* COMMIT_WMAP */
 
 				/* free child extents covered by parent */
 				xadlock.xdlist = &p->xad[index + 1];
@@ -2605,20 +2683,24 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
 	}
 
 	/*
-	 * parent page become empty: free the page
-	 */
+		 * parent page become empty: free the page
+		 */
 	if (index == XTENTRYSTART) {
-		if (log) {	/* COMMIT_PWMAP */
+		if (log) { /* COMMIT_PWMAP */
 			/* txCommit() with tlckFREE:
-			 * free child extents covered by parent;
-			 * invalidate parent if COMMIT_PWMAP;
-			 */
+				 * free child extents covered by parent;
+				 * invalidate parent if COMMIT_PWMAP;
+				 */
 			tlck = txLock(tid, ip, mp, tlckXTREE);
-			xtlck = (struct xtlock *) & tlck->lock;
+			if (IS_ERR(tlck)) {
+				XT_PUTPAGE(mp);
+				return PTR_ERR(tlck);
+			}
+			xtlck = (struct xtlock *)&tlck->lock;
 			xtlck->hwm.offset =
-			    le16_to_cpu(p->header.nextindex) - 1;
+				le16_to_cpu(p->header.nextindex) - 1;
 			tlck->type = tlckXTREE | tlckFREE;
-		} else {	/* COMMIT_WMAP */
+		} else { /* COMMIT_WMAP */
 
 			/* free child extents covered by parent */
 			xadlock.xdlist = &p->xad[XTENTRYSTART];
@@ -2832,8 +2914,12 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
 		return (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
 	}
 	tlck = txLock(tid, ip, mp, tlckXTREE);
+	if (IS_ERR(tlck)) {
+		XT_PUTPAGE(mp);
+		return PTR_ERR(tlck);
+	}
 	tlck->type = tlckXTREE | tlckFREE;
-	xtlck = (struct xtlock *) & tlck->lock;
+	xtlck = (struct xtlock *)&tlck->lock;
 	xtlck->hwm.offset = index;
 
 
@@ -2865,7 +2951,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
 		 * invalidate parent if COMMIT_PWMAP;
 		 */
 		tlck = txLock(tid, ip, mp, tlckXTREE);
-		xtlck = (struct xtlock *) & tlck->lock;
+		if (IS_ERR(tlck)) {
+			XT_PUTPAGE(mp);
+			return PTR_ERR(tlck);
+		}
+		xtlck = (struct xtlock *)&tlck->lock;
 		xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
 		tlck->type = tlckXTREE | tlckFREE;
 
diff --git a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h
index 0f6cf5a1c..fd654908f 100644
--- a/fs/jfs/jfs_xtree.h
+++ b/fs/jfs/jfs_xtree.h
@@ -99,7 +99,7 @@ typedef union {
  */
 extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
 		    int *pflag, s64 * paddr, int *plen, int flag);
-extern void xtInitRoot(tid_t tid, struct inode *ip);
+extern int xtInitRoot(tid_t tid, struct inode *ip);
 extern int xtInsert(tid_t tid, struct inode *ip,
 		    int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag);
 extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen,
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 442d62679..1d538b107 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -128,7 +128,11 @@ static int jfs_create(struct mnt_idmap *idmap, struct inode *dip,
 	/*
 	 * initialize the child XAD tree root in-line in inode
 	 */
-	xtInitRoot(tid, ip);
+	rc = xtInitRoot(tid, ip);
+	if (rc) {
+		txAbort(tid, 0);
+		goto out3;
+	}
 
 	/*
 	 * create entry in parent directory for child directory
@@ -261,7 +265,11 @@ static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip,
 	/*
 	 * initialize the child directory in-line in inode
 	 */
-	dtInitRoot(tid, ip, dip->i_ino);
+	rc = dtInitRoot(tid, ip, dip->i_ino);
+	if (rc) {
+		txAbort(tid, 0);
+		goto out3;
+	}
 
 	/*
 	 * create entry in parent directory for child directory
@@ -944,7 +952,11 @@ static int jfs_symlink(struct mnt_idmap *idmap, struct inode *dip,
 	/*
 	 * write symbolic link target path name
 	 */
-	xtInitRoot(tid, ip);
+	rc = xtInitRoot(tid, ip);
+	if (rc) {
+		txAbort(tid, 0);
+		goto out3;
+	}
 
 	/*
 	 * write source path name inline in on-disk inode (fast symbolic link)
@@ -1260,6 +1272,10 @@ static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 			tlck = txLock(tid, old_ip,
 				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
 				      tlckDTREE | tlckBTROOT | tlckRELINK);
+			if (IS_ERR(tlck)) {
+				rc = PTR_ERR(tlck);
+				goto out_tx;
+			}
 			dtlck = (struct dt_lock *) & tlck->lock;
 			ASSERT(dtlck->index == 0);
 			lv = & dtlck->lv[0];


base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzkaller@googlegroups.com.

             reply	other threads:[~2026-06-29 22:55 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-29 22:55 syzbot [this message]
2026-07-13 16:43 ` [PATCH RFC] jfs: replace BUG() with error return in txLock() Bartosz Chronowski

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=9d2eba88-93bf-4f3c-a3b2-b554e1fffe80@mail.kernel.org \
    --to=syzbot@kernel.org \
    --cc=syzbot@lists.linux.dev \
    --cc=syzkaller-upstream-moderation@googlegroups.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