diff options
Diffstat (limited to 'fs/jbd/checkpoint.c')
-rw-r--r-- | fs/jbd/checkpoint.c | 31 |
1 files changed, 24 insertions, 7 deletions
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 1bd8d4acc6f2..61f32f3868cd 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -115,7 +115,7 @@ static int __try_to_free_cp_buf(struct journal_head *jh) | |||
115 | */ | 115 | */ |
116 | void __log_wait_for_space(journal_t *journal) | 116 | void __log_wait_for_space(journal_t *journal) |
117 | { | 117 | { |
118 | int nblocks; | 118 | int nblocks, space_left; |
119 | assert_spin_locked(&journal->j_state_lock); | 119 | assert_spin_locked(&journal->j_state_lock); |
120 | 120 | ||
121 | nblocks = jbd_space_needed(journal); | 121 | nblocks = jbd_space_needed(journal); |
@@ -128,25 +128,42 @@ void __log_wait_for_space(journal_t *journal) | |||
128 | /* | 128 | /* |
129 | * Test again, another process may have checkpointed while we | 129 | * Test again, another process may have checkpointed while we |
130 | * were waiting for the checkpoint lock. If there are no | 130 | * were waiting for the checkpoint lock. If there are no |
131 | * outstanding transactions there is nothing to checkpoint and | 131 | * transactions ready to be checkpointed, try to recover |
132 | * we can't make progress. Abort the journal in this case. | 132 | * journal space by calling cleanup_journal_tail(), and if |
133 | * that doesn't work, by waiting for the currently committing | ||
134 | * transaction to complete. If there is absolutely no way | ||
135 | * to make progress, this is either a BUG or corrupted | ||
136 | * filesystem, so abort the journal and leave a stack | ||
137 | * trace for forensic evidence. | ||
133 | */ | 138 | */ |
134 | spin_lock(&journal->j_state_lock); | 139 | spin_lock(&journal->j_state_lock); |
135 | spin_lock(&journal->j_list_lock); | 140 | spin_lock(&journal->j_list_lock); |
136 | nblocks = jbd_space_needed(journal); | 141 | nblocks = jbd_space_needed(journal); |
137 | if (__log_space_left(journal) < nblocks) { | 142 | space_left = __log_space_left(journal); |
143 | if (space_left < nblocks) { | ||
138 | int chkpt = journal->j_checkpoint_transactions != NULL; | 144 | int chkpt = journal->j_checkpoint_transactions != NULL; |
145 | tid_t tid = 0; | ||
139 | 146 | ||
147 | if (journal->j_committing_transaction) | ||
148 | tid = journal->j_committing_transaction->t_tid; | ||
140 | spin_unlock(&journal->j_list_lock); | 149 | spin_unlock(&journal->j_list_lock); |
141 | spin_unlock(&journal->j_state_lock); | 150 | spin_unlock(&journal->j_state_lock); |
142 | if (chkpt) { | 151 | if (chkpt) { |
143 | log_do_checkpoint(journal); | 152 | log_do_checkpoint(journal); |
153 | } else if (cleanup_journal_tail(journal) == 0) { | ||
154 | /* We were able to recover space; yay! */ | ||
155 | ; | ||
156 | } else if (tid) { | ||
157 | log_wait_commit(journal, tid); | ||
144 | } else { | 158 | } else { |
145 | printk(KERN_ERR "%s: no transactions\n", | 159 | printk(KERN_ERR "%s: needed %d blocks and " |
146 | __func__); | 160 | "only had %d space available\n", |
161 | __func__, nblocks, space_left); | ||
162 | printk(KERN_ERR "%s: no way to get more " | ||
163 | "journal space\n", __func__); | ||
164 | WARN_ON(1); | ||
147 | journal_abort(journal, 0); | 165 | journal_abort(journal, 0); |
148 | } | 166 | } |
149 | |||
150 | spin_lock(&journal->j_state_lock); | 167 | spin_lock(&journal->j_state_lock); |
151 | } else { | 168 | } else { |
152 | spin_unlock(&journal->j_list_lock); | 169 | spin_unlock(&journal->j_list_lock); |