]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/jbd2/checkpoint.c
jbd2: jbd2_log_wait_for_space improve error detetcion
[mirror_ubuntu-bionic-kernel.git] / fs / jbd2 / checkpoint.c
index f1507e5b7c9a2ce57e96d6b4f28ace1008bcddaf..1fbf59938cc0f71cefcddebf3e36650bfcf36dd5 100644 (file)
@@ -96,15 +96,8 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
 
        if (jh->b_transaction == NULL && !buffer_locked(bh) &&
            !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
-               /*
-                * Get our reference so that bh cannot be freed before
-                * we unlock it
-                */
-               get_bh(bh);
                JBUFFER_TRACE(jh, "remove from checkpoint list");
                ret = __jbd2_journal_remove_checkpoint(jh) + 1;
-               BUFFER_TRACE(bh, "release");
-               __brelse(bh);
        }
        return ret;
 }
@@ -122,8 +115,6 @@ void __jbd2_log_wait_for_space(journal_t *journal)
 
        nblocks = jbd2_space_needed(journal);
        while (jbd2_log_space_left(journal) < nblocks) {
-               if (journal->j_flags & JBD2_ABORT)
-                       return;
                write_unlock(&journal->j_state_lock);
                mutex_lock(&journal->j_checkpoint_mutex);
 
@@ -139,6 +130,10 @@ void __jbd2_log_wait_for_space(journal_t *journal)
                 * trace for forensic evidence.
                 */
                write_lock(&journal->j_state_lock);
+               if (journal->j_flags & JBD2_ABORT) {
+                       mutex_unlock(&journal->j_checkpoint_mutex);
+                       return;
+               }
                spin_lock(&journal->j_list_lock);
                nblocks = jbd2_space_needed(journal);
                space_left = jbd2_log_space_left(journal);
@@ -183,58 +178,6 @@ void __jbd2_log_wait_for_space(journal_t *journal)
        }
 }
 
-/*
- * Clean up transaction's list of buffers submitted for io.
- * We wait for any pending IO to complete and remove any clean
- * buffers. Note that we take the buffers in the opposite ordering
- * from the one in which they were submitted for IO.
- *
- * Return 0 on success, and return <0 if some buffers have failed
- * to be written out.
- *
- * Called with j_list_lock held.
- */
-static int __wait_cp_io(journal_t *journal, transaction_t *transaction)
-{
-       struct journal_head *jh;
-       struct buffer_head *bh;
-       tid_t this_tid;
-       int released = 0;
-       int ret = 0;
-
-       this_tid = transaction->t_tid;
-restart:
-       /* Did somebody clean up the transaction in the meanwhile? */
-       if (journal->j_checkpoint_transactions != transaction ||
-                       transaction->t_tid != this_tid)
-               return ret;
-       while (!released && transaction->t_checkpoint_io_list) {
-               jh = transaction->t_checkpoint_io_list;
-               bh = jh2bh(jh);
-               get_bh(bh);
-               if (buffer_locked(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 restart;
-               }
-               if (unlikely(buffer_write_io_error(bh)))
-                       ret = -EIO;
-
-               /*
-                * 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
-                */
-               released = __jbd2_journal_remove_checkpoint(jh);
-               __brelse(bh);
-       }
-
-       return ret;
-}
-
 static void
 __flush_batch(journal_t *journal, int *batch_count)
 {
@@ -268,7 +211,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
        struct buffer_head      *bh;
        transaction_t           *transaction;
        tid_t                   this_tid;
-       int                     err, result, batch_count = 0;
+       int                     result, batch_count = 0;
 
        jbd_debug(1, "Start checkpoint\n");
 
@@ -343,12 +286,11 @@ restart:
                if (!buffer_dirty(bh)) {
                        if (unlikely(buffer_write_io_error(bh)) && !result)
                                result = -EIO;
-                       get_bh(bh);
                        BUFFER_TRACE(bh, "remove from checkpoint");
-                       __jbd2_journal_remove_checkpoint(jh);
-                       spin_unlock(&journal->j_list_lock);
-                       __brelse(bh);
-                       goto retry;
+                       if (__jbd2_journal_remove_checkpoint(jh))
+                               /* The transaction was released; we're done */
+                               goto out;
+                       continue;
                }
                /*
                 * Important: we are about to write the buffer, and
@@ -384,9 +326,36 @@ restart:
         * Now we issued all of the transaction's buffers, let's deal
         * with the buffers that are out for I/O.
         */
-       err = __wait_cp_io(journal, transaction);
-       if (!result)
-               result = err;
+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)) {
+                       spin_unlock(&journal->j_list_lock);
+                       get_bh(bh);
+                       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;
+               }
+               if (unlikely(buffer_write_io_error(bh)) && !result)
+                       result = -EIO;
+
+               /*
+                * 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);
        if (result < 0)