2006-10-20 06:51:01

by Andrew Morton

[permalink] [raw]
Subject: [patch 73/76] ext3/4: fix J_ASSERT(transaction->t_updates > 0) in journal_stop()

From: OGAWA Hirofumi <[email protected]>

A disk generated some I/O error, after it, I hitted
J_ASSERT(transaction->t_updates > 0) in journal_stop().

It seems to happened on ext3_truncate() path from stack trace. Then,
maybe the following case may trigger J_ASSERT(transaction->t_updates > 0).

ext3_truncate()
-> ext3_free_branches()
-> ext3_journal_test_restart()
-> ext3_journal_restart()
-> journal_restart()
transaction->t_updates--;
/* another process aborted journal */
-> start_this_handle()
returns -EROFS without transaction->t_updates++;

-> ext3_journal_stop()
-> journal_stop()
J_ASSERT(transaction->t_updates > 0)

If journal was aborted in middle of journal_restart(), ext3_truncate()
may trigger J_ASSERT().

Signed-off-by: OGAWA Hirofumi <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
---

fs/jbd/transaction.c | 5 +++--
fs/jbd2/transaction.c | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)

diff -puN fs/jbd/transaction.c~ext3-fix-j_asserttransaction-t_updates-0-in-journal_stop fs/jbd/transaction.c
--- a/fs/jbd/transaction.c~ext3-fix-j_asserttransaction-t_updates-0-in-journal_stop
+++ a/fs/jbd/transaction.c
@@ -1314,13 +1314,14 @@ int journal_stop(handle_t *handle)
int old_handle_count, err;
pid_t pid;

- J_ASSERT(transaction->t_updates > 0);
J_ASSERT(journal_current_handle() == handle);

if (is_handle_aborted(handle))
err = -EIO;
- else
+ else {
+ J_ASSERT(transaction->t_updates > 0);
err = 0;
+ }

if (--handle->h_ref > 0) {
jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
diff -puN fs/jbd2/transaction.c~ext3-fix-j_asserttransaction-t_updates-0-in-journal_stop fs/jbd2/transaction.c
--- a/fs/jbd2/transaction.c~ext3-fix-j_asserttransaction-t_updates-0-in-journal_stop
+++ a/fs/jbd2/transaction.c
@@ -1314,13 +1314,14 @@ int jbd2_journal_stop(handle_t *handle)
int old_handle_count, err;
pid_t pid;

- J_ASSERT(transaction->t_updates > 0);
J_ASSERT(journal_current_handle() == handle);

if (is_handle_aborted(handle))
err = -EIO;
- else
+ else {
+ J_ASSERT(transaction->t_updates > 0);
err = 0;
+ }

if (--handle->h_ref > 0) {
jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
_