]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/jbd2/checkpoint.c
Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / fs / jbd2 / checkpoint.c
index 9203c3332f170887a2aff921c81946826ddd1cf9..17159cacbd9ec95aba6f7b0a942680322858159d 100644 (file)
@@ -116,7 +116,7 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
  */
 void __jbd2_log_wait_for_space(journal_t *journal)
 {
-       int nblocks;
+       int nblocks, space_left;
        assert_spin_locked(&journal->j_state_lock);
 
        nblocks = jbd_space_needed(journal);
@@ -129,25 +129,43 @@ void __jbd2_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, 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_list_lock);
                nblocks = jbd_space_needed(journal);
-               if (__jbd2_log_space_left(journal) < nblocks) {
+               space_left = __jbd2_log_space_left(journal);
+               if (space_left < nblocks) {
                        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_state_lock);
                        if (chkpt) {
                                jbd2_log_do_checkpoint(journal);
+                       } else if (jbd2_cleanup_journal_tail(journal) == 0) {
+                               /* We were able to recover space; yay! */
+                               ;
+                       } else if (tid) {
+                               jbd2_log_wait_commit(journal, tid);
                        } 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 in %s\n", __func__,
+                                      journal->j_devname);
+                               WARN_ON(1);
                                jbd2_journal_abort(journal, 0);
                        }
-
                        spin_lock(&journal->j_state_lock);
                } else {
                        spin_unlock(&journal->j_list_lock);
@@ -231,16 +249,14 @@ restart:
        return ret;
 }
 
-#define NR_BATCH       64
-
 static void
-__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
+__flush_batch(journal_t *journal, int *batch_count)
 {
        int i;
 
-       ll_rw_block(SWRITE, *batch_count, bhs);
+       ll_rw_block(SWRITE, *batch_count, journal->j_chkpt_bhs);
        for (i = 0; i < *batch_count; i++) {
-               struct buffer_head *bh = bhs[i];
+               struct buffer_head *bh = journal->j_chkpt_bhs[i];
                clear_buffer_jwrite(bh);
                BUFFER_TRACE(bh, "brelse");
                __brelse(bh);
@@ -259,8 +275,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
  * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
  */
 static int __process_buffer(journal_t *journal, struct journal_head *jh,
-                       struct buffer_head **bhs, int *batch_count,
-                       transaction_t *transaction)
+                           int *batch_count, transaction_t *transaction)
 {
        struct buffer_head *bh = jh2bh(jh);
        int ret = 0;
@@ -307,14 +322,14 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
                get_bh(bh);
                J_ASSERT_BH(bh, !buffer_jwrite(bh));
                set_buffer_jwrite(bh);
-               bhs[*batch_count] = bh;
+               journal->j_chkpt_bhs[*batch_count] = bh;
                __buffer_relink_io(jh);
                jbd_unlock_bh_state(bh);
                transaction->t_chp_stats.cs_written++;
                (*batch_count)++;
-               if (*batch_count == NR_BATCH) {
+               if (*batch_count == JBD2_NR_BATCH) {
                        spin_unlock(&journal->j_list_lock);
-                       __flush_batch(journal, bhs, batch_count);
+                       __flush_batch(journal, batch_count);
                        ret = 1;
                }
        }
@@ -370,7 +385,6 @@ restart:
        if (journal->j_checkpoint_transactions == transaction &&
                        transaction->t_tid == this_tid) {
                int batch_count = 0;
-               struct buffer_head *bhs[NR_BATCH];
                struct journal_head *jh;
                int retry = 0, err;
 
@@ -384,7 +398,7 @@ restart:
                                retry = 1;
                                break;
                        }
-                       retry = __process_buffer(journal, jh, bhs, &batch_count,
+                       retry = __process_buffer(journal, jh, &batch_count,
                                                 transaction);
                        if (retry < 0 && !result)
                                result = retry;
@@ -401,7 +415,7 @@ restart:
                                spin_unlock(&journal->j_list_lock);
                                retry = 1;
                        }
-                       __flush_batch(journal, bhs, &batch_count);
+                       __flush_batch(journal, &batch_count);
                }
 
                if (retry) {
@@ -668,6 +682,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
           safely remove this transaction from the log */
 
        __jbd2_journal_drop_transaction(journal, transaction);
+       kfree(transaction);
 
        /* Just in case anybody was waiting for more transactions to be
            checkpointed... */
@@ -742,5 +757,4 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
        J_ASSERT(journal->j_running_transaction != transaction);
 
        jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
-       kfree(transaction);
 }