These changes are a raw update to a vanilla kernel 4.1.10, with the
[kvmfornfv.git] / kernel / fs / jbd2 / checkpoint.c
index 9c00e2e..78c1545 100644 (file)
@@ -419,12 +419,12 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
  * journal_clean_one_cp_list
  *
  * Find all the written-back checkpoint buffers in the given list and
- * release them.
+ * release them. If 'destroy' is set, clean all buffers unconditionally.
  *
  * Called with j_list_lock held.
  * Returns 1 if we freed the transaction, 0 otherwise.
  */
-static int journal_clean_one_cp_list(struct journal_head *jh)
+static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
 {
        struct journal_head *last_jh;
        struct journal_head *next_jh = jh;
@@ -438,7 +438,10 @@ static int journal_clean_one_cp_list(struct journal_head *jh)
        do {
                jh = next_jh;
                next_jh = jh->b_cpnext;
-               ret = __try_to_free_cp_buf(jh);
+               if (!destroy)
+                       ret = __try_to_free_cp_buf(jh);
+               else
+                       ret = __jbd2_journal_remove_checkpoint(jh) + 1;
                if (!ret)
                        return freed;
                if (ret == 2)
@@ -461,10 +464,11 @@ static int journal_clean_one_cp_list(struct journal_head *jh)
  * journal_clean_checkpoint_list
  *
  * Find all the written-back checkpoint buffers in the journal and release them.
+ * If 'destroy' is set, release all buffers unconditionally.
  *
  * Called with j_list_lock held.
  */
-void __jbd2_journal_clean_checkpoint_list(journal_t *journal)
+void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
 {
        transaction_t *transaction, *last_transaction, *next_transaction;
        int ret;
@@ -478,7 +482,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal)
        do {
                transaction = next_transaction;
                next_transaction = transaction->t_cpnext;
-               ret = journal_clean_one_cp_list(transaction->t_checkpoint_list);
+               ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
+                                               destroy);
                /*
                 * This function only frees up some memory if possible so we
                 * dont have an obligation to finish processing. Bail out if
@@ -494,7 +499,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal)
                 * we can possibly see not yet submitted buffers on io_list
                 */
                ret = journal_clean_one_cp_list(transaction->
-                               t_checkpoint_io_list);
+                               t_checkpoint_io_list, destroy);
                if (need_resched())
                        return;
                /*
@@ -507,6 +512,28 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal)
        } while (transaction != last_transaction);
 }
 
+/*
+ * Remove buffers from all checkpoint lists as journal is aborted and we just
+ * need to free memory
+ */
+void jbd2_journal_destroy_checkpoint(journal_t *journal)
+{
+       /*
+        * We loop because __jbd2_journal_clean_checkpoint_list() may abort
+        * early due to a need of rescheduling.
+        */
+       while (1) {
+               spin_lock(&journal->j_list_lock);
+               if (!journal->j_checkpoint_transactions) {
+                       spin_unlock(&journal->j_list_lock);
+                       break;
+               }
+               __jbd2_journal_clean_checkpoint_list(journal, true);
+               spin_unlock(&journal->j_list_lock);
+               cond_resched();
+       }
+}
+
 /*
  * journal_remove_checkpoint: called after a buffer has been committed
  * to disk (either by being write-back flushed to disk, or being