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+a843f6...@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-dis...@lists.sourceforge.net>
To: "Dave Kleikamp" <
sha...@kernel.org>
Cc: "Arnd Bergmann" <
ar...@arndb.de>
Cc: "Christian Brauner (Amutable)" <
bra...@kernel.org>
Cc: "Damien Le Moal" <
dle...@kernel.org>
Cc: "Jan Kara" <
ja...@suse.cz>
Cc: "Jori Koolstra" <
jkoo...@xs4all.nl>
Cc: "Jeff Layton" <
jla...@kernel.org>
Cc: "Kees Cook" <
ke...@kernel.org>
Cc: <
linux-...@vger.kernel.org>
Cc: "Mateusz Guzik" <
mjg...@gmail.com>
Cc: "Richard Weinberger" <
ric...@nod.at>
Cc: "Mike Rapoport (Microsoft)" <
rp...@kernel.org>
Cc: "Shaurya Rane" <
ssran...@ee.vjti.ac.in>
Cc: "Suchit Karunakaran" <
suchitka...@gmail.com>
Cc: "Al Viro" <
vi...@zeniv.linux.org.uk>
Cc: "Yun Zhou" <
yun....@windriver.com>
Cc: "Hongling Zeng" <
zengho...@kylinos.cn>
Cc: "Zheng Yu" <
zhen...@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
syzk...@googlegroups.com.