aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDuane Griffin <duaneg@dghda.com>2008-10-08 23:28:31 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-10-08 23:28:31 -0400
commit23f8b79eae8a74e42a006ffa7c456e295c7e1c0d (patch)
treeb62700cd7ff65268a50cfd8d8652d220f7c5c9a4 /fs
parentc806e68f5647109350ec546fee5b526962970fd2 (diff)
jbd2: abort instead of waiting for nonexistent transaction
The __jbd2_log_wait_for_space function sits in a loop checkpointing transactions until there is sufficient space free in the journal. However, if there are no transactions to be processed (e.g. because the free space calculation is wrong due to a corrupted filesystem) it will never progress. Check for space being required when no transactions are outstanding and abort the journal instead of endlessly looping. This patch fixes the bug reported by Sami Liedes at: http://bugzilla.kernel.org/show_bug.cgi?id=10976 Signed-off-by: Duane Griffin <duaneg@dghda.com> Cc: Sami Liedes <sliedes@cc.hut.fi> Cc: <linux-ext4@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/jbd2/checkpoint.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 91389c8aee8a..af4651bf3570 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -126,14 +126,29 @@ void __jbd2_log_wait_for_space(journal_t *journal)
126 126
127 /* 127 /*
128 * Test again, another process may have checkpointed while we 128 * Test again, another process may have checkpointed while we
129 * were waiting for the checkpoint lock 129 * were waiting for the checkpoint lock. If there are no
130 * outstanding transactions there is nothing to checkpoint and
131 * we can't make progress. Abort the journal in this case.
130 */ 132 */
131 spin_lock(&journal->j_state_lock); 133 spin_lock(&journal->j_state_lock);
134 spin_lock(&journal->j_list_lock);
132 nblocks = jbd_space_needed(journal); 135 nblocks = jbd_space_needed(journal);
133 if (__jbd2_log_space_left(journal) < nblocks) { 136 if (__jbd2_log_space_left(journal) < nblocks) {
137 int chkpt = journal->j_checkpoint_transactions != NULL;
138
139 spin_unlock(&journal->j_list_lock);
134 spin_unlock(&journal->j_state_lock); 140 spin_unlock(&journal->j_state_lock);
135 jbd2_log_do_checkpoint(journal); 141 if (chkpt) {
142 jbd2_log_do_checkpoint(journal);
143 } else {
144 printk(KERN_ERR "%s: no transactions\n",
145 __func__);
146 jbd2_journal_abort(journal, 0);
147 }
148
136 spin_lock(&journal->j_state_lock); 149 spin_lock(&journal->j_state_lock);
150 } else {
151 spin_unlock(&journal->j_list_lock);
137 } 152 }
138 mutex_unlock(&journal->j_checkpoint_mutex); 153 mutex_unlock(&journal->j_checkpoint_mutex);
139 } 154 }