Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[safe/jmp/linux-2.6] / fs / jbd2 / commit.c
index c8a1bac..62804e5 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/crc32.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
+#include <linux/bio.h>
 
 /*
  * Default IO end handler for temporary BJ_IO buffer_heads.
@@ -137,7 +138,7 @@ static int journal_submit_commit_record(journal_t *journal,
                set_buffer_ordered(bh);
                barrier_done = 1;
        }
-       ret = submit_bh(WRITE, bh);
+       ret = submit_bh(WRITE_SYNC, bh);
        if (barrier_done)
                clear_buffer_ordered(bh);
 
@@ -158,7 +159,7 @@ static int journal_submit_commit_record(journal_t *journal,
                lock_buffer(bh);
                set_buffer_uptodate(bh);
                clear_buffer_dirty(bh);
-               ret = submit_bh(WRITE, bh);
+               ret = submit_bh(WRITE_SYNC, bh);
        }
        *cbh = bh;
        return ret;
@@ -168,12 +169,34 @@ static int journal_submit_commit_record(journal_t *journal,
  * This function along with journal_submit_commit_record
  * allows to write the commit record asynchronously.
  */
-static int journal_wait_on_commit_record(struct buffer_head *bh)
+static int journal_wait_on_commit_record(journal_t *journal,
+                                        struct buffer_head *bh)
 {
        int ret = 0;
 
+retry:
        clear_buffer_dirty(bh);
        wait_on_buffer(bh);
+       if (buffer_eopnotsupp(bh) && (journal->j_flags & JBD2_BARRIER)) {
+               printk(KERN_WARNING
+                      "JBD2: wait_on_commit_record: sync failed on %s - "
+                      "disabling barriers\n", journal->j_devname);
+               spin_lock(&journal->j_state_lock);
+               journal->j_flags &= ~JBD2_BARRIER;
+               spin_unlock(&journal->j_state_lock);
+
+               lock_buffer(bh);
+               clear_buffer_dirty(bh);
+               set_buffer_uptodate(bh);
+               bh->b_end_io = journal_end_buffer_io_sync;
+
+               ret = submit_bh(WRITE_SYNC, bh);
+               if (ret) {
+                       unlock_buffer(bh);
+                       return ret;
+               }
+               goto retry;
+       }
 
        if (unlikely(!buffer_uptodate(bh)))
                ret = -EIO;
@@ -332,13 +355,15 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        int flags;
        int err;
        unsigned long long blocknr;
+       ktime_t start_time;
+       u64 commit_time;
        char *tagp = NULL;
        journal_header_t *header;
        journal_block_tag_t *tag = NULL;
        int space_left = 0;
        int first_tag = 0;
        int tag_flag;
-       int i;
+       int i, to_free = 0;
        int tag_bytes = journal_tag_bytes(journal);
        struct buffer_head *cbh = NULL; /* For transactional checksums */
        __u32 crc32_sum = ~0;
@@ -458,6 +483,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        commit_transaction->t_state = T_FLUSH;
        journal->j_committing_transaction = commit_transaction;
        journal->j_running_transaction = NULL;
+       start_time = ktime_get();
        commit_transaction->t_log_start = journal->j_head;
        wake_up(&journal->j_wait_transaction_locked);
        spin_unlock(&journal->j_state_lock);
@@ -803,7 +829,7 @@ wait_for_iobuf:
                        __jbd2_journal_abort_hard(journal);
        }
        if (!err && !is_journal_aborted(journal))
-               err = journal_wait_on_commit_record(cbh);
+               err = journal_wait_on_commit_record(journal, cbh);
 
        if (err)
                jbd2_journal_abort(journal, err);
@@ -981,14 +1007,23 @@ restart_loop:
        J_ASSERT(commit_transaction == journal->j_committing_transaction);
        journal->j_commit_sequence = commit_transaction->t_tid;
        journal->j_committing_transaction = NULL;
-       spin_unlock(&journal->j_state_lock);
+       commit_time = ktime_to_ns(ktime_sub(ktime_get(), start_time));
 
-       if (journal->j_commit_callback)
-               journal->j_commit_callback(journal, commit_transaction);
+       /*
+        * weight the commit time higher than the average time so we don't
+        * react too strongly to vast changes in the commit time
+        */
+       if (likely(journal->j_average_commit_time))
+               journal->j_average_commit_time = (commit_time +
+                               journal->j_average_commit_time*3) / 4;
+       else
+               journal->j_average_commit_time = commit_time;
+       spin_unlock(&journal->j_state_lock);
 
        if (commit_transaction->t_checkpoint_list == NULL &&
            commit_transaction->t_checkpoint_io_list == NULL) {
                __jbd2_journal_drop_transaction(journal, commit_transaction);
+               to_free = 1;
        } else {
                if (journal->j_checkpoint_transactions == NULL) {
                        journal->j_checkpoint_transactions = commit_transaction;
@@ -1007,11 +1042,16 @@ restart_loop:
        }
        spin_unlock(&journal->j_list_lock);
 
+       if (journal->j_commit_callback)
+               journal->j_commit_callback(journal, commit_transaction);
+
        trace_mark(jbd2_end_commit, "dev %s transaction %d head %d",
-                  journal->j_devname, journal->j_commit_sequence,
+                  journal->j_devname, commit_transaction->t_tid,
                   journal->j_tail_sequence);
        jbd_debug(1, "JBD: commit %d complete, head %d\n",
                  journal->j_commit_sequence, journal->j_tail_sequence);
+       if (to_free)
+               kfree(commit_transaction);
 
        wake_up(&journal->j_wait_done_commit);
 }