wl1251: add powersave exit logic for transfers
[pandora-kernel.git] / fs / jbd2 / commit.c
index 68d704d..ab9463a 100644 (file)
@@ -326,7 +326,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        int space_left = 0;
        int first_tag = 0;
        int tag_flag;
-       int i, to_free = 0;
+       int i;
        int tag_bytes = journal_tag_bytes(journal);
        struct buffer_head *cbh = NULL; /* For transactional checksums */
        __u32 crc32_sum = ~0;
@@ -683,7 +683,7 @@ start_journal_io:
        if (commit_transaction->t_need_data_flush &&
            (journal->j_fs_dev != journal->j_dev) &&
            (journal->j_flags & JBD2_BARRIER))
-               blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
+               blkdev_issue_flush(journal->j_fs_dev, GFP_NOFS, NULL);
 
        /* Done it all: now write the commit record asynchronously. */
        if (JBD2_HAS_INCOMPAT_FEATURE(journal,
@@ -819,7 +819,7 @@ wait_for_iobuf:
        if (JBD2_HAS_INCOMPAT_FEATURE(journal,
                                      JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT) &&
            journal->j_flags & JBD2_BARRIER) {
-               blkdev_issue_flush(journal->j_dev, GFP_KERNEL, NULL);
+               blkdev_issue_flush(journal->j_dev, GFP_NOFS, NULL);
        }
 
        if (err)
@@ -996,7 +996,7 @@ restart_loop:
        journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged;
        spin_unlock(&journal->j_history_lock);
 
-       commit_transaction->t_state = T_FINISHED;
+       commit_transaction->t_state = T_COMMIT_CALLBACK;
        J_ASSERT(commit_transaction == journal->j_committing_transaction);
        journal->j_commit_sequence = commit_transaction->t_tid;
        journal->j_committing_transaction = NULL;
@@ -1011,38 +1011,44 @@ restart_loop:
                                journal->j_average_commit_time*3) / 4;
        else
                journal->j_average_commit_time = commit_time;
+
        write_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;
+       if (journal->j_checkpoint_transactions == NULL) {
+               journal->j_checkpoint_transactions = commit_transaction;
+               commit_transaction->t_cpnext = commit_transaction;
+               commit_transaction->t_cpprev = commit_transaction;
        } else {
-               if (journal->j_checkpoint_transactions == NULL) {
-                       journal->j_checkpoint_transactions = commit_transaction;
-                       commit_transaction->t_cpnext = commit_transaction;
-                       commit_transaction->t_cpprev = commit_transaction;
-               } else {
-                       commit_transaction->t_cpnext =
-                               journal->j_checkpoint_transactions;
-                       commit_transaction->t_cpprev =
-                               commit_transaction->t_cpnext->t_cpprev;
-                       commit_transaction->t_cpnext->t_cpprev =
-                               commit_transaction;
-                       commit_transaction->t_cpprev->t_cpnext =
+               commit_transaction->t_cpnext =
+                       journal->j_checkpoint_transactions;
+               commit_transaction->t_cpprev =
+                       commit_transaction->t_cpnext->t_cpprev;
+               commit_transaction->t_cpnext->t_cpprev =
+                       commit_transaction;
+               commit_transaction->t_cpprev->t_cpnext =
                                commit_transaction;
-               }
        }
        spin_unlock(&journal->j_list_lock);
-
+       /* Drop all spin_locks because commit_callback may be block.
+        * __journal_remove_checkpoint() can not destroy transaction
+        * under us because it is not marked as T_FINISHED yet */
        if (journal->j_commit_callback)
                journal->j_commit_callback(journal, commit_transaction);
 
        trace_jbd2_end_commit(journal, commit_transaction);
        jbd_debug(1, "JBD2: commit %d complete, head %d\n",
                  journal->j_commit_sequence, journal->j_tail_sequence);
-       if (to_free)
-               kfree(commit_transaction);
 
+       write_lock(&journal->j_state_lock);
+       spin_lock(&journal->j_list_lock);
+       commit_transaction->t_state = T_FINISHED;
+       /* Recheck checkpoint lists after j_list_lock was dropped */
+       if (commit_transaction->t_checkpoint_list == NULL &&
+           commit_transaction->t_checkpoint_io_list == NULL) {
+               __jbd2_journal_drop_transaction(journal, commit_transaction);
+               kfree(commit_transaction);
+       }
+       spin_unlock(&journal->j_list_lock);
+       write_unlock(&journal->j_state_lock);
        wake_up(&journal->j_wait_done_commit);
 }