jbd2: remove t_checkpoint_io_list
[platform/kernel/linux-starfive.git] / fs / jbd2 / checkpoint.c
index 51bd38d..55d6efd 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Called with j_list_lock held.
  */
-static inline void __buffer_unlink_first(struct journal_head *jh)
+static inline void __buffer_unlink(struct journal_head *jh)
 {
        transaction_t *transaction = jh->b_cp_transaction;
 
@@ -41,45 +41,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
 }
 
 /*
- * Unlink a buffer from a transaction checkpoint(io) list.
- *
- * Called with j_list_lock held.
- */
-static inline void __buffer_unlink(struct journal_head *jh)
-{
-       transaction_t *transaction = jh->b_cp_transaction;
-
-       __buffer_unlink_first(jh);
-       if (transaction->t_checkpoint_io_list == jh) {
-               transaction->t_checkpoint_io_list = jh->b_cpnext;
-               if (transaction->t_checkpoint_io_list == jh)
-                       transaction->t_checkpoint_io_list = NULL;
-       }
-}
-
-/*
- * Move a buffer from the checkpoint list to the checkpoint io list
- *
- * Called with j_list_lock held
- */
-static inline void __buffer_relink_io(struct journal_head *jh)
-{
-       transaction_t *transaction = jh->b_cp_transaction;
-
-       __buffer_unlink_first(jh);
-
-       if (!transaction->t_checkpoint_io_list) {
-               jh->b_cpnext = jh->b_cpprev = jh;
-       } else {
-               jh->b_cpnext = transaction->t_checkpoint_io_list;
-               jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev;
-               jh->b_cpprev->b_cpnext = jh;
-               jh->b_cpnext->b_cpprev = jh;
-       }
-       transaction->t_checkpoint_io_list = jh;
-}
-
-/*
  * Check a checkpoint buffer could be release or not.
  *
  * Requires j_list_lock
@@ -183,6 +144,7 @@ __flush_batch(journal_t *journal, int *batch_count)
                struct buffer_head *bh = journal->j_chkpt_bhs[i];
                BUFFER_TRACE(bh, "brelse");
                __brelse(bh);
+               journal->j_chkpt_bhs[i] = NULL;
        }
        *batch_count = 0;
 }
@@ -242,6 +204,11 @@ restart:
                jh = transaction->t_checkpoint_list;
                bh = jh2bh(jh);
 
+               /*
+                * The buffer may be writing back, or flushing out in the
+                * last couple of cycles, or re-adding into a new transaction,
+                * need to check it again until it's unlocked.
+                */
                if (buffer_locked(bh)) {
                        get_bh(bh);
                        spin_unlock(&journal->j_list_lock);
@@ -287,28 +254,32 @@ restart:
                }
                if (!buffer_dirty(bh)) {
                        BUFFER_TRACE(bh, "remove from checkpoint");
-                       if (__jbd2_journal_remove_checkpoint(jh))
-                               /* The transaction was released; we're done */
+                       /*
+                        * If the transaction was released or the checkpoint
+                        * list was empty, we're done.
+                        */
+                       if (__jbd2_journal_remove_checkpoint(jh) ||
+                           !transaction->t_checkpoint_list)
                                goto out;
-                       continue;
+               } else {
+                       /*
+                        * We are about to write the buffer, it could be
+                        * raced by some other transaction shrink or buffer
+                        * re-log logic once we release the j_list_lock,
+                        * leave it on the checkpoint list and check status
+                        * again to make sure it's clean.
+                        */
+                       BUFFER_TRACE(bh, "queue");
+                       get_bh(bh);
+                       J_ASSERT_BH(bh, !buffer_jwrite(bh));
+                       journal->j_chkpt_bhs[batch_count++] = bh;
+                       transaction->t_chp_stats.cs_written++;
+                       transaction->t_checkpoint_list = jh->b_cpnext;
                }
-               /*
-                * Important: we are about to write the buffer, and
-                * possibly block, while still holding the journal
-                * lock.  We cannot afford to let the transaction
-                * logic start messing around with this buffer before
-                * we write it to disk, as that would break
-                * recoverability.
-                */
-               BUFFER_TRACE(bh, "queue");
-               get_bh(bh);
-               J_ASSERT_BH(bh, !buffer_jwrite(bh));
-               journal->j_chkpt_bhs[batch_count++] = bh;
-               __buffer_relink_io(jh);
-               transaction->t_chp_stats.cs_written++;
+
                if ((batch_count == JBD2_NR_BATCH) ||
-                   need_resched() ||
-                   spin_needbreak(&journal->j_list_lock))
+                   need_resched() || spin_needbreak(&journal->j_list_lock) ||
+                   jh2bh(transaction->t_checkpoint_list) == journal->j_chkpt_bhs[0])
                        goto unlock_and_flush;
        }
 
@@ -322,38 +293,6 @@ restart:
                        goto restart;
        }
 
-       /*
-        * Now we issued all of the transaction's buffers, let's deal
-        * with the buffers that are out for I/O.
-        */
-restart2:
-       /* Did somebody clean up the transaction in the meanwhile? */
-       if (journal->j_checkpoint_transactions != transaction ||
-           transaction->t_tid != this_tid)
-               goto out;
-
-       while (transaction->t_checkpoint_io_list) {
-               jh = transaction->t_checkpoint_io_list;
-               bh = jh2bh(jh);
-               if (buffer_locked(bh)) {
-                       get_bh(bh);
-                       spin_unlock(&journal->j_list_lock);
-                       wait_on_buffer(bh);
-                       /* the journal_head may have gone by now */
-                       BUFFER_TRACE(bh, "brelse");
-                       __brelse(bh);
-                       spin_lock(&journal->j_list_lock);
-                       goto restart2;
-               }
-
-               /*
-                * Now in whatever state the buffer currently is, we
-                * know that it has been written out and so we can
-                * drop it from the list
-                */
-               if (__jbd2_journal_remove_checkpoint(jh))
-                       break;
-       }
 out:
        spin_unlock(&journal->j_list_lock);
        result = jbd2_cleanup_journal_tail(journal);
@@ -547,15 +486,6 @@ again:
                        break;
                if (need_resched() || spin_needbreak(&journal->j_list_lock))
                        break;
-               if (released)
-                       continue;
-
-               nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
-                                                      nr_to_scan, &released);
-               if (*nr_to_scan == 0)
-                       break;
-               if (need_resched() || spin_needbreak(&journal->j_list_lock))
-                       break;
        } while (transaction != last_transaction);
 
        if (transaction != last_transaction) {
@@ -610,17 +540,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
                 */
                if (need_resched())
                        return;
-               if (ret)
-                       continue;
-               /*
-                * It is essential that we are as careful as in the case of
-                * t_checkpoint_list with removing the buffer from the list as
-                * we can possibly see not yet submitted buffers on io_list
-                */
-               ret = journal_clean_one_cp_list(transaction->
-                               t_checkpoint_io_list, destroy);
-               if (need_resched())
-                       return;
                /*
                 * Stop scanning if we couldn't free the transaction. This
                 * avoids pointless scanning of transactions which still
@@ -705,7 +624,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
        jbd2_journal_put_journal_head(jh);
 
        /* Is this transaction empty? */
-       if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
+       if (transaction->t_checkpoint_list)
                return 0;
 
        /*
@@ -797,7 +716,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
        J_ASSERT(transaction->t_forget == NULL);
        J_ASSERT(transaction->t_shadow_list == NULL);
        J_ASSERT(transaction->t_checkpoint_list == NULL);
-       J_ASSERT(transaction->t_checkpoint_io_list == NULL);
        J_ASSERT(atomic_read(&transaction->t_updates) == 0);
        J_ASSERT(journal->j_committing_transaction != transaction);
        J_ASSERT(journal->j_running_transaction != transaction);