tunnels: fix netns vs proto registration ordering
[safe/jmp/linux-2.6] / fs / jbd2 / commit.c
index f22d182..1bc74b6 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/jbd2.h>
-#include <linux/marker.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -26,6 +25,8 @@
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
 #include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <trace/events/jbd2.h>
 
 /*
  * Default IO end handler for temporary BJ_IO buffer_heads.
@@ -133,12 +134,12 @@ static int journal_submit_commit_record(journal_t *journal,
        bh->b_end_io = journal_end_buffer_io_sync;
 
        if (journal->j_flags & JBD2_BARRIER &&
-               !JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                        JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+           !JBD2_HAS_INCOMPAT_FEATURE(journal,
+                                      JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
                set_buffer_ordered(bh);
                barrier_done = 1;
        }
-       ret = submit_bh(WRITE, bh);
+       ret = submit_bh(WRITE_SYNC_PLUG, bh);
        if (barrier_done)
                clear_buffer_ordered(bh);
 
@@ -159,7 +160,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_PLUG, bh);
        }
        *cbh = bh;
        return ret;
@@ -190,7 +191,7 @@ retry:
                set_buffer_uptodate(bh);
                bh->b_end_io = journal_end_buffer_io_sync;
 
-               ret = submit_bh(WRITE_SYNC, bh);
+               ret = submit_bh(WRITE_SYNC_PLUG, bh);
                if (ret) {
                        unlock_buffer(bh);
                        return ret;
@@ -220,7 +221,6 @@ static int journal_submit_inode_data_buffers(struct address_space *mapping)
                .nr_to_write = mapping->nrpages * 2,
                .range_start = 0,
                .range_end = i_size_read(mapping->host),
-               .for_writepages = 1,
        };
 
        ret = generic_writepages(mapping, &wbc);
@@ -253,11 +253,13 @@ static int journal_submit_data_buffers(journal_t *journal,
                 * block allocation  with delalloc. We need to write
                 * only allocated blocks here.
                 */
+               trace_jbd2_submit_inode_data(jinode->i_vfs_inode);
                err = journal_submit_inode_data_buffers(mapping);
                if (!ret)
                        ret = err;
                spin_lock(&journal->j_list_lock);
                J_ASSERT(jinode->i_transaction == commit_transaction);
+               commit_transaction->t_flushed_data_blocks = 1;
                jinode->i_flags &= ~JI_COMMIT_RUNNING;
                wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING);
        }
@@ -285,7 +287,7 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
                if (err) {
                        /*
                         * Because AS_EIO is cleared by
-                        * wait_on_page_writeback_range(), set it again so
+                        * filemap_fdatawait_range(), set it again so
                         * that user process can get -EIO from fsync().
                         */
                        set_bit(AS_EIO,
@@ -363,10 +365,11 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        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;
+       int write_op = WRITE;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -393,18 +396,25 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        commit_transaction = journal->j_running_transaction;
        J_ASSERT(commit_transaction->t_state == T_RUNNING);
 
-       trace_mark(jbd2_start_commit, "dev %s transaction %d",
-                  journal->j_devname, commit_transaction->t_tid);
+       trace_jbd2_start_commit(journal, commit_transaction);
        jbd_debug(1, "JBD: starting commit of transaction %d\n",
                        commit_transaction->t_tid);
 
        spin_lock(&journal->j_state_lock);
        commit_transaction->t_state = T_LOCKED;
 
-       stats.u.run.rs_wait = commit_transaction->t_max_wait;
-       stats.u.run.rs_locked = jiffies;
-       stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
-                                               stats.u.run.rs_locked);
+       /*
+        * Use plugged writes here, since we want to submit several before
+        * we unplug the device. We don't do explicit unplugging in here,
+        * instead we rely on sync_buffer() doing the unplug for us.
+        */
+       if (commit_transaction->t_synchronous_commit)
+               write_op = WRITE_SYNC_PLUG;
+       trace_jbd2_commit_locking(journal, commit_transaction);
+       stats.run.rs_wait = commit_transaction->t_max_wait;
+       stats.run.rs_locked = jiffies;
+       stats.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
+                                             stats.run.rs_locked);
 
        spin_lock(&commit_transaction->t_handle_lock);
        while (commit_transaction->t_updates) {
@@ -476,9 +486,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
         */
        jbd2_journal_switch_revoke_table(journal);
 
-       stats.u.run.rs_flushing = jiffies;
-       stats.u.run.rs_locked = jbd2_time_diff(stats.u.run.rs_locked,
-                                              stats.u.run.rs_flushing);
+       trace_jbd2_commit_flushing(journal, commit_transaction);
+       stats.run.rs_flushing = jiffies;
+       stats.run.rs_locked = jbd2_time_diff(stats.run.rs_locked,
+                                            stats.run.rs_flushing);
 
        commit_transaction->t_state = T_FLUSH;
        journal->j_committing_transaction = commit_transaction;
@@ -498,7 +509,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        if (err)
                jbd2_journal_abort(journal, err);
 
-       jbd2_journal_write_revoke_records(journal, commit_transaction);
+       jbd2_journal_write_revoke_records(journal, commit_transaction,
+                                         write_op);
 
        jbd_debug(3, "JBD: commit phase 2\n");
 
@@ -511,11 +523,12 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        commit_transaction->t_state = T_COMMIT;
        spin_unlock(&journal->j_state_lock);
 
-       stats.u.run.rs_logging = jiffies;
-       stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing,
-                                                stats.u.run.rs_logging);
-       stats.u.run.rs_blocks = commit_transaction->t_outstanding_credits;
-       stats.u.run.rs_blocks_logged = 0;
+       trace_jbd2_commit_logging(journal, commit_transaction);
+       stats.run.rs_logging = jiffies;
+       stats.run.rs_flushing = jbd2_time_diff(stats.run.rs_flushing,
+                                              stats.run.rs_logging);
+       stats.run.rs_blocks = commit_transaction->t_outstanding_credits;
+       stats.run.rs_blocks_logged = 0;
 
        J_ASSERT(commit_transaction->t_nr_buffers <=
                 commit_transaction->t_outstanding_credits);
@@ -535,6 +548,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
                if (is_journal_aborted(journal)) {
                        clear_buffer_jbddirty(jh2bh(jh));
                        JBUFFER_TRACE(jh, "journal is aborting: refile");
+                       jbd2_buffer_abort_trigger(jh,
+                                                 jh->b_frozen_data ?
+                                                 jh->b_frozen_triggers :
+                                                 jh->b_triggers);
                        jbd2_journal_refile_buffer(journal, jh);
                        /* If that was the last one, we need to clean up
                         * any descriptor buffers which may have been
@@ -620,6 +637,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
                JBUFFER_TRACE(jh, "ph3: write metadata");
                flags = jbd2_journal_write_metadata_buffer(commit_transaction,
                                                      jh, &new_jh, blocknr);
+               if (flags < 0) {
+                       jbd2_journal_abort(journal, flags);
+                       continue;
+               }
                set_bit(BH_JWrite, &jh2bh(new_jh)->b_state);
                wbuf[bufs++] = jh2bh(new_jh);
 
@@ -676,10 +697,10 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(WRITE, bh);
+                               submit_bh(write_op, bh);
                        }
                        cond_resched();
-                       stats.u.run.rs_blocks_logged += bufs;
+                       stats.run.rs_blocks_logged += bufs;
 
                        /* Force a new descriptor to be generated next
                            time round the loop. */
@@ -688,23 +709,27 @@ start_journal_io:
                }
        }
 
-       /* Done it all: now write the commit record asynchronously. */
+       /* 
+        * If the journal is not located on the file system device,
+        * then we must flush the file system device before we issue
+        * the commit record
+        */
+       if (commit_transaction->t_flushed_data_blocks &&
+           (journal->j_fs_dev != journal->j_dev) &&
+           (journal->j_flags & JBD2_BARRIER))
+               blkdev_issue_flush(journal->j_fs_dev, NULL);
 
+       /* Done it all: now write the commit record asynchronously. */
        if (JBD2_HAS_INCOMPAT_FEATURE(journal,
-               JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+                                     JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
                err = journal_submit_commit_record(journal, commit_transaction,
                                                 &cbh, crc32_sum);
                if (err)
                        __jbd2_journal_abort_hard(journal);
+               if (journal->j_flags & JBD2_BARRIER)
+                       blkdev_issue_flush(journal->j_dev, NULL);
        }
 
-       /*
-        * This is the right place to wait for data buffers both for ASYNC
-        * and !ASYNC commit. If commit is ASYNC, we need to wait only after
-        * the commit block went to disk (which happens above). If commit is
-        * SYNC, we need to wait for data buffers before we start writing
-        * commit block, which happens below in such setting.
-        */
        err = journal_finish_inode_data_buffers(journal, commit_transaction);
        if (err) {
                printk(KERN_WARNING
@@ -818,7 +843,7 @@ wait_for_iobuf:
        jbd_debug(3, "JBD: commit phase 5\n");
 
        if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
-               JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+                                      JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
                err = journal_submit_commit_record(journal, commit_transaction,
                                                &cbh, crc32_sum);
                if (err)
@@ -870,6 +895,9 @@ restart_loop:
                 * data.
                 *
                 * Otherwise, we can just throw away the frozen data now.
+                *
+                * We also know that the frozen data has already fired
+                * its triggers if they exist, so we can clear that too.
                 */
                if (jh->b_committed_data) {
                        jbd2_free(jh->b_committed_data, bh->b_size);
@@ -877,10 +905,12 @@ restart_loop:
                        if (jh->b_frozen_data) {
                                jh->b_committed_data = jh->b_frozen_data;
                                jh->b_frozen_data = NULL;
+                               jh->b_frozen_triggers = NULL;
                        }
                } else if (jh->b_frozen_data) {
                        jbd2_free(jh->b_frozen_data, bh->b_size);
                        jh->b_frozen_data = NULL;
+                       jh->b_frozen_triggers = NULL;
                }
 
                spin_lock(&journal->j_list_lock);
@@ -965,33 +995,30 @@ restart_loop:
        J_ASSERT(commit_transaction->t_state == T_COMMIT);
 
        commit_transaction->t_start = jiffies;
-       stats.u.run.rs_logging = jbd2_time_diff(stats.u.run.rs_logging,
-                                               commit_transaction->t_start);
+       stats.run.rs_logging = jbd2_time_diff(stats.run.rs_logging,
+                                             commit_transaction->t_start);
 
        /*
-        * File the transaction for history
+        * File the transaction statistics
         */
-       stats.ts_type = JBD2_STATS_RUN;
        stats.ts_tid = commit_transaction->t_tid;
-       stats.u.run.rs_handle_count = commit_transaction->t_handle_count;
-       spin_lock(&journal->j_history_lock);
-       memcpy(journal->j_history + journal->j_history_cur, &stats,
-                       sizeof(stats));
-       if (++journal->j_history_cur == journal->j_history_max)
-               journal->j_history_cur = 0;
+       stats.run.rs_handle_count = commit_transaction->t_handle_count;
+       trace_jbd2_run_stats(journal->j_fs_dev->bd_dev,
+                            commit_transaction->t_tid, &stats.run);
 
        /*
         * Calculate overall stats
         */
+       spin_lock(&journal->j_history_lock);
        journal->j_stats.ts_tid++;
-       journal->j_stats.u.run.rs_wait += stats.u.run.rs_wait;
-       journal->j_stats.u.run.rs_running += stats.u.run.rs_running;
-       journal->j_stats.u.run.rs_locked += stats.u.run.rs_locked;
-       journal->j_stats.u.run.rs_flushing += stats.u.run.rs_flushing;
-       journal->j_stats.u.run.rs_logging += stats.u.run.rs_logging;
-       journal->j_stats.u.run.rs_handle_count += stats.u.run.rs_handle_count;
-       journal->j_stats.u.run.rs_blocks += stats.u.run.rs_blocks;
-       journal->j_stats.u.run.rs_blocks_logged += stats.u.run.rs_blocks_logged;
+       journal->j_stats.run.rs_wait += stats.run.rs_wait;
+       journal->j_stats.run.rs_running += stats.run.rs_running;
+       journal->j_stats.run.rs_locked += stats.run.rs_locked;
+       journal->j_stats.run.rs_flushing += stats.run.rs_flushing;
+       journal->j_stats.run.rs_logging += stats.run.rs_logging;
+       journal->j_stats.run.rs_handle_count += stats.run.rs_handle_count;
+       journal->j_stats.run.rs_blocks += stats.run.rs_blocks;
+       journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged;
        spin_unlock(&journal->j_history_lock);
 
        commit_transaction->t_state = T_FINISHED;
@@ -1011,12 +1038,10 @@ restart_loop:
                journal->j_average_commit_time = commit_time;
        spin_unlock(&journal->j_state_lock);
 
-       if (journal->j_commit_callback)
-               journal->j_commit_callback(journal, commit_transaction);
-
        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;
@@ -1035,11 +1060,14 @@ restart_loop:
        }
        spin_unlock(&journal->j_list_lock);
 
-       trace_mark(jbd2_end_commit, "dev %s transaction %d head %d",
-                  journal->j_devname, journal->j_commit_sequence,
-                  journal->j_tail_sequence);
+       if (journal->j_commit_callback)
+               journal->j_commit_callback(journal, commit_transaction);
+
+       trace_jbd2_end_commit(journal, commit_transaction);
        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);
 }