[PATCH] jbd: Make __log_wait_for_space wait for the committing transaction to finish

From: Theodore Ts'o
Date: Sat Nov 01 2008 - 12:36:41 EST


Commit be07c4ed introducd a regression because it assumed that if
there were no transactions ready to be checkpointed, that no progress
could be made on making space available in the journal, and so the
journal should be aborted. This assumption is false; for small
journals, the currently committing transaction could be responsible
for chewing up the required space in the log, so we need to wait for
the currently committing transaction to finish before trying to force
a checkpoint operation.

Signed-off-by: "Theodore Ts'o" <tytso@xxxxxxx>
Cc: Duane Griffin <duaneg@xxxxxxxxx>

diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 1bd8d4a..89faee1 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -128,25 +128,36 @@ void __log_wait_for_space(journal_t *journal)
/*
* Test again, another process may have checkpointed while we
* were waiting for the checkpoint lock. If there are no
- * outstanding transactions there is nothing to checkpoint and
- * we can't make progress. Abort the journal in this case.
+ * transactions ready to be checkpointed, we may need to
+ * wait for the currently committing transaction to complete
+ * first. If there are no outstanding transactions we can't
+ * make progress. This should never happen, so call trigger
+ * a BUG so we can debug the situation.
*/
spin_lock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
nblocks = jbd_space_needed(journal);
if (__log_space_left(journal) < nblocks) {
int chkpt = journal->j_checkpoint_transactions != NULL;
+ int tid = 0;

+ if (journal->j_committing_transaction)
+ tid = journal->j_committing_transaction->t_tid;
spin_unlock(&journal->j_list_lock);
spin_unlock(&journal->j_state_lock);
if (chkpt) {
log_do_checkpoint(journal);
+ } else if (tid) {
+ log_wait_commit(journal, tid);
} else {
- printk(KERN_ERR "%s: no transactions\n",
- __func__);
- journal_abort(journal, 0);
+ printk(KERN_ALERT "%s: needed %d blocks and "
+ "only had %d space available\n",
+ __func__, nblocks,
+ __log_space_left(journal));
+ printk(KERN_ALERT "%s: no way to get more "
+ "journal space\n", __func__);
+ BUG();
}
-
spin_lock(&journal->j_state_lock);
} else {
spin_unlock(&journal->j_list_lock);
--
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/