[PATCH] [CHECKER] Double txEnd calls causing the kernel to panic(JFS 2.4, kernel 2.4.19)

From: Dave Kleikamp
Date: Tue May 04 2004 - 14:02:01 EST


On Fri, 2004-04-30 at 17:33, Junfeng Yang wrote:
> The common pattern in JFS is to call txCommit then call txEnd to end a
> transction. But if diWrite in txCommit fails (it fails when
> read_cache_page fails to get a page), txAbortCommit will be called.
> txAbortCommit will subsequently call txEnd and set tblk->next to
> txAnchor.freetid. Later on, when the second txEnd gets called on the same
> tid, the assertion assert(tblk->next) in txEnd will always fail.

The obvious fix here is that txAbortCommit should not call txEnd(). By
fixing this and the bug reported in your other note, "Kernel panic when
diWrite fails to get a page", txAbortCommit becomes functionally
equivalent to txAbort(), which has neither problem. The fix then, is to
kill txAbortCommit, and have txCommit call txAbort instead.

Here is the patch, which will be pushed to Marcelo & Linus soon.

===== fs/jfs/jfs_txnmgr.c 1.33 vs edited =====
--- 1.33/fs/jfs/jfs_txnmgr.c Mon Apr 12 10:54:51 2004
+++ edited/fs/jfs/jfs_txnmgr.c Tue May 4 13:34:39 2004
@@ -1,5 +1,5 @@
/*
- * Copyright (C) International Business Machines Corp., 2000-2003
+ * Copyright (C) International Business Machines Corp., 2000-2004
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
@@ -175,7 +175,6 @@
struct tlock * tlck);
static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
-static void txAbortCommit(struct commit * cd);
static void txAllocPMap(struct inode *ip, struct maplock * maplock,
struct tblock * tblk);
static void txForce(struct tblock * tblk);
@@ -1295,7 +1294,7 @@

out:
if (rc != 0)
- txAbortCommit(&cd);
+ txAbort(tid, 1);

TheEnd:
jfs_info("txCommit: tid = %d, returning %d", tid, rc);
@@ -2632,64 +2631,6 @@

return;
}
-
-
-/*
- * txAbortCommit()
- *
- * function: abort commit.
- *
- * frees tlocks of transaction; line-locks and segment locks for all
- * segments in comdata structure. frees malloc storage
- * sets state of file-system to FM_MDIRTY in super-block.
- * log age of page-frames in memory for which caller has
- * are reset to 0 (to avoid logwarap).
- */
-static void txAbortCommit(struct commit * cd)
-{
- struct tblock *tblk;
- tid_t tid;
- lid_t lid, next;
- struct metapage *mp;
-
- jfs_warn("txAbortCommit: cd:0x%p", cd);
-
- /*
- * free tlocks of the transaction
- */
- tid = cd->tid;
- tblk = tid_to_tblock(tid);
- for (lid = tblk->next; lid; lid = next) {
- next = lid_to_tlock(lid)->next;
-
- mp = lid_to_tlock(lid)->mp;
- if (mp) {
- mp->lid = 0;
-
- /*
- * reset lsn of page to avoid logwarap;
- */
- if (mp->xflag & COMMIT_PAGE)
- LogSyncRelease(mp);
- }
-
- /* insert tlock at head of freelist */
- TXN_LOCK();
- txLockFree(lid);
- TXN_UNLOCK();
- }
-
- tblk->next = tblk->last = 0;
-
- /* free the transaction block */
- txEnd(tid);
-
- /*
- * mark filesystem dirty
- */
- jfs_error(cd->sb, "txAbortCommit");
-}
-

/*
* txLazyCommit(void)

--
David Kleikamp
IBM Linux Technology Center

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/