|
@@ -115,7 +115,7 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
|
|
*/
|
|
*/
|
|
void __log_wait_for_space(journal_t *journal)
|
|
void __log_wait_for_space(journal_t *journal)
|
|
{
|
|
{
|
|
- int nblocks;
|
|
|
|
|
|
+ int nblocks, space_left;
|
|
assert_spin_locked(&journal->j_state_lock);
|
|
assert_spin_locked(&journal->j_state_lock);
|
|
|
|
|
|
nblocks = jbd_space_needed(journal);
|
|
nblocks = jbd_space_needed(journal);
|
|
@@ -128,25 +128,42 @@ void __log_wait_for_space(journal_t *journal)
|
|
/*
|
|
/*
|
|
* Test again, another process may have checkpointed while we
|
|
* Test again, another process may have checkpointed while we
|
|
* were waiting for the checkpoint lock. If there are no
|
|
* 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, try to recover
|
|
|
|
+ * journal space by calling cleanup_journal_tail(), and if
|
|
|
|
+ * that doesn't work, by waiting for the currently committing
|
|
|
|
+ * transaction to complete. If there is absolutely no way
|
|
|
|
+ * to make progress, this is either a BUG or corrupted
|
|
|
|
+ * filesystem, so abort the journal and leave a stack
|
|
|
|
+ * trace for forensic evidence.
|
|
*/
|
|
*/
|
|
spin_lock(&journal->j_state_lock);
|
|
spin_lock(&journal->j_state_lock);
|
|
spin_lock(&journal->j_list_lock);
|
|
spin_lock(&journal->j_list_lock);
|
|
nblocks = jbd_space_needed(journal);
|
|
nblocks = jbd_space_needed(journal);
|
|
- if (__log_space_left(journal) < nblocks) {
|
|
|
|
|
|
+ space_left = __log_space_left(journal);
|
|
|
|
+ if (space_left < nblocks) {
|
|
int chkpt = journal->j_checkpoint_transactions != NULL;
|
|
int chkpt = journal->j_checkpoint_transactions != NULL;
|
|
|
|
+ tid_t tid = 0;
|
|
|
|
|
|
|
|
+ if (journal->j_committing_transaction)
|
|
|
|
+ tid = journal->j_committing_transaction->t_tid;
|
|
spin_unlock(&journal->j_list_lock);
|
|
spin_unlock(&journal->j_list_lock);
|
|
spin_unlock(&journal->j_state_lock);
|
|
spin_unlock(&journal->j_state_lock);
|
|
if (chkpt) {
|
|
if (chkpt) {
|
|
log_do_checkpoint(journal);
|
|
log_do_checkpoint(journal);
|
|
|
|
+ } else if (cleanup_journal_tail(journal) == 0) {
|
|
|
|
+ /* We were able to recover space; yay! */
|
|
|
|
+ ;
|
|
|
|
+ } else if (tid) {
|
|
|
|
+ log_wait_commit(journal, tid);
|
|
} else {
|
|
} else {
|
|
- printk(KERN_ERR "%s: no transactions\n",
|
|
|
|
- __func__);
|
|
|
|
|
|
+ printk(KERN_ERR "%s: needed %d blocks and "
|
|
|
|
+ "only had %d space available\n",
|
|
|
|
+ __func__, nblocks, space_left);
|
|
|
|
+ printk(KERN_ERR "%s: no way to get more "
|
|
|
|
+ "journal space\n", __func__);
|
|
|
|
+ WARN_ON(1);
|
|
journal_abort(journal, 0);
|
|
journal_abort(journal, 0);
|
|
}
|
|
}
|
|
-
|
|
|
|
spin_lock(&journal->j_state_lock);
|
|
spin_lock(&journal->j_state_lock);
|
|
} else {
|
|
} else {
|
|
spin_unlock(&journal->j_list_lock);
|
|
spin_unlock(&journal->j_list_lock);
|