]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
jbd2: fast commit recovery path
authorHarshad Shirwadkar <harshadshirwadkar@gmail.com>
Thu, 15 Oct 2020 20:37:58 +0000 (13:37 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 22 Oct 2020 03:22:37 +0000 (23:22 -0400)
This patch adds fast commit recovery support in JBD2.

Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
Link: https://lore.kernel.org/r/20201015203802.3597742-7-harshadshirwadkar@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/fast_commit.c
fs/jbd2/recovery.c
include/linux/jbd2.h

index 79e947c431987ab0da03b8f67efb8d67e7ab9e28..888d9d217d5bdfe99056da00bb0366be34a32339 100644 (file)
@@ -1188,8 +1188,23 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
        trace_ext4_fc_stats(sb);
 }
 
+/*
+ * Main recovery path entry point.
+ */
+static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
+                               enum passtype pass, int off, tid_t expected_tid)
+{
+       return 0;
+}
+
 void ext4_fc_init(struct super_block *sb, journal_t *journal)
 {
+       /*
+        * We set replay callback even if fast commit disabled because we may
+        * could still have fast commit blocks that need to be replayed even if
+        * fast commit has now been turned off.
+        */
+       journal->j_fc_replay_callback = ext4_fc_replay;
        if (!test_opt2(sb, JOURNAL_FAST_COMMIT))
                return;
        journal->j_fc_cleanup_callback = ext4_fc_cleanup;
index fb134c7a12c89b164fb6dec4323a82539d1ae7d9..eb2606133cd8689055f697c7fc0f4902e09a66f6 100644 (file)
@@ -35,7 +35,6 @@ struct recovery_info
        int             nr_revoke_hits;
 };
 
-enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
 static int do_one_pass(journal_t *journal,
                                struct recovery_info *info, enum passtype pass);
 static int scan_revoke_records(journal_t *, struct buffer_head *,
@@ -225,10 +224,51 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
 /* Make sure we wrap around the log correctly! */
 #define wrap(journal, var)                                             \
 do {                                                                   \
-       if (var >= (journal)->j_last)                                   \
-               var -= ((journal)->j_last - (journal)->j_first);        \
+       unsigned long _wrap_last =                                      \
+               jbd2_has_feature_fast_commit(journal) ?                 \
+                       (journal)->j_fc_last : (journal)->j_last;       \
+                                                                       \
+       if (var >= _wrap_last)                                          \
+               var -= (_wrap_last - (journal)->j_first);               \
 } while (0)
 
+static int fc_do_one_pass(journal_t *journal,
+                         struct recovery_info *info, enum passtype pass)
+{
+       unsigned int expected_commit_id = info->end_transaction;
+       unsigned long next_fc_block;
+       struct buffer_head *bh;
+       int err = 0;
+
+       next_fc_block = journal->j_fc_first;
+       if (!journal->j_fc_replay_callback)
+               return 0;
+
+       while (next_fc_block <= journal->j_fc_last) {
+               jbd_debug(3, "Fast commit replay: next block %ld",
+                         next_fc_block);
+               err = jread(&bh, journal, next_fc_block);
+               if (err) {
+                       jbd_debug(3, "Fast commit replay: read error");
+                       break;
+               }
+
+               jbd_debug(3, "Processing fast commit blk with seq %d");
+               err = journal->j_fc_replay_callback(journal, bh, pass,
+                                       next_fc_block - journal->j_fc_first,
+                                       expected_commit_id);
+               next_fc_block++;
+               if (err < 0 || err == JBD2_FC_REPLAY_STOP)
+                       break;
+               err = 0;
+       }
+
+       if (err)
+               jbd_debug(3, "Fast commit replay failed, err = %d\n", err);
+
+       return err;
+}
+
 /**
  * jbd2_journal_recover - recovers a on-disk journal
  * @journal: the journal to recover
@@ -472,7 +512,9 @@ static int do_one_pass(journal_t *journal,
                                break;
 
                jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
-                         next_commit_ID, next_log_block, journal->j_last);
+                         next_commit_ID, next_log_block,
+                         jbd2_has_feature_fast_commit(journal) ?
+                         journal->j_fc_last : journal->j_last);
 
                /* Skip over each chunk of the transaction looking
                 * either the next descriptor block or the final commit
@@ -834,6 +876,13 @@ static int do_one_pass(journal_t *journal,
                                success = -EIO;
                }
        }
+
+       if (jbd2_has_feature_fast_commit(journal) &&  pass != PASS_REVOKE) {
+               err = fc_do_one_pass(journal, info, pass);
+               if (err)
+                       success = err;
+       }
+
        if (block_error && success == 0)
                success = -EIO;
        return success;
index a009d9b9c6209b3210de3f051b5b510e2f9f938c..fb3d71ad6eeafbef597200be28d867f664321848 100644 (file)
@@ -751,6 +751,11 @@ jbd2_time_diff(unsigned long start, unsigned long end)
 
 #define JBD2_NR_BATCH  64
 
+enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
+
+#define JBD2_FC_REPLAY_STOP    0
+#define JBD2_FC_REPLAY_CONTINUE        1
+
 /**
  * struct journal_s - The journal_s type is the concrete type associated with
  *     journal_t.
@@ -1248,6 +1253,21 @@ struct journal_s
         */
        void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
 
+       /*
+        * @j_fc_replay_callback:
+        *
+        * File-system specific function that performs replay of a fast
+        * commit. JBD2 calls this function for each fast commit block found in
+        * the journal. This function should return JBD2_FC_REPLAY_CONTINUE
+        * to indicate that the block was processed correctly and more fast
+        * commit replay should continue. Return value of JBD2_FC_REPLAY_STOP
+        * indicates the end of replay (no more blocks remaining). A negative
+        * return value indicates error.
+        */
+       int (*j_fc_replay_callback)(struct journal_s *journal,
+                                   struct buffer_head *bh,
+                                   enum passtype pass, int off,
+                                   tid_t expected_commit_id);
 };
 
 #define jbd2_might_wait_for_commit(j) \