Whamcloud - gitweb
Use mallinfo2 instead of mallinfo if available
[tools/e2fsprogs.git] / e2fsck / recovery.c
index 4c457b3..8ca3527 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * linux/fs/jbd2/recovery.c
  *
@@ -5,10 +6,6 @@
  *
  * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
  *
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- *
  * Journal recovery routines for the generic filesystem journaling code;
  * part of the ext2fs journaling system.
  */
@@ -38,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 *,
@@ -78,8 +74,8 @@ static int do_readahead(journal_t *journal, unsigned int start)
 
        /* Do up to 128K of readahead */
        max = start + (128 * 1024 / journal->j_blocksize);
-       if (max > journal->j_maxlen)
-               max = journal->j_maxlen;
+       if (max > journal->j_total_len)
+               max = journal->j_total_len;
 
        /* Do the readahead itself.  We'll submit MAXBUF buffer_heads at
         * a time to the block device IO layer. */
@@ -87,7 +83,7 @@ static int do_readahead(journal_t *journal, unsigned int start)
        nbufs = 0;
 
        for (next = start; next < max; next++) {
-               err = journal_bmap(journal, next, &blocknr);
+               err = jbd2_journal_bmap(journal, next, &blocknr);
 
                if (err) {
                        printk(KERN_ERR "JBD2: bad block at offset %u\n",
@@ -104,7 +100,7 @@ static int do_readahead(journal_t *journal, unsigned int start)
                if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
                        bufs[nbufs++] = bh;
                        if (nbufs == MAXBUF) {
-                               ll_rw_block(READ, nbufs, bufs);
+                               ll_rw_block(REQ_OP_READ, 0, nbufs, bufs);
                                journal_brelse_array(bufs, nbufs);
                                nbufs = 0;
                        }
@@ -113,7 +109,7 @@ static int do_readahead(journal_t *journal, unsigned int start)
        }
 
        if (nbufs)
-               ll_rw_block(READ, nbufs, bufs);
+               ll_rw_block(REQ_OP_READ, 0, nbufs, bufs);
        err = 0;
 
 failed:
@@ -124,27 +120,6 @@ failed:
 
 #endif /* __KERNEL__ */
 
-static inline __u32 get_be32(__be32 *p)
-{
-       unsigned char *cp = (unsigned char *) p;
-       __u32 ret;
-
-       ret = *cp++;
-       ret = (ret << 8) + *cp++;
-       ret = (ret << 8) + *cp++;
-       ret = (ret << 8) + *cp++;
-       return ret;
-}
-
-static inline __u16 get_be16(__be16 *p)
-{
-       unsigned char *cp = (unsigned char *) p;
-       __u16 ret;
-
-       ret = *cp++;
-       ret = (ret << 8) + *cp++;
-       return ret;
-}
 
 /*
  * Read a block from the journal
@@ -159,12 +134,12 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
 
        *bhp = NULL;
 
-       if (offset >= journal->j_maxlen) {
+       if (offset >= journal->j_total_len) {
                printk(KERN_ERR "JBD2: corrupted journal superblock\n");
                return -EFSCORRUPTED;
        }
 
-       err = journal_bmap(journal, offset, &blocknr);
+       err = jbd2_journal_bmap(journal, offset, &blocknr);
 
        if (err) {
                printk(KERN_ERR "JBD2: bad block at offset %u\n",
@@ -195,24 +170,23 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
        return 0;
 }
 
-static int jbd2_descr_block_csum_verify(journal_t *j,
-                                       void *buf)
+static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf)
 {
-       struct journal_block_tail *tail;
-       __u32 provided;
+       struct jbd2_journal_block_tail *tail;
+       __be32 provided;
        __u32 calculated;
 
-       if (!journal_has_csum_v2or3(j))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
-       tail = (struct journal_block_tail *)((char *)buf + j->j_blocksize -
-                       sizeof(struct journal_block_tail));
+       tail = (struct jbd2_journal_block_tail *)((char *)buf +
+               j->j_blocksize - sizeof(struct jbd2_journal_block_tail));
        provided = tail->t_checksum;
        tail->t_checksum = 0;
        calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
        tail->t_checksum = provided;
 
-       return provided == ext2fs_cpu_to_be32(calculated);
+       return provided == cpu_to_be32(calculated);
 }
 
 /*
@@ -222,24 +196,24 @@ static int jbd2_descr_block_csum_verify(journal_t *j,
 static int count_tags(journal_t *journal, struct buffer_head *bh)
 {
        char *                  tagp;
-       journal_block_tag_t *   tag;
+       journal_block_tag_t     tag;
        int                     nr = 0, size = journal->j_blocksize;
        int                     tag_bytes = journal_tag_bytes(journal);
 
-       if (journal_has_csum_v2or3(journal))
-               size -= sizeof(struct journal_block_tail);
+       if (jbd2_journal_has_csum_v2or3(journal))
+               size -= sizeof(struct jbd2_journal_block_tail);
 
        tagp = &bh->b_data[sizeof(journal_header_t)];
 
        while ((tagp - bh->b_data + tag_bytes) <= size) {
-               tag = (journal_block_tag_t *) tagp;
+               memcpy(&tag, tagp, sizeof(tag));
 
                nr++;
                tagp += tag_bytes;
-               if (!(get_be16(&tag->t_flags) & JFS_FLAG_SAME_UUID))
+               if (!(tag.t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID)))
                        tagp += 16;
 
-               if (get_be16(&tag->t_flags) & JFS_FLAG_LAST_TAG)
+               if (tag.t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG))
                        break;
        }
 
@@ -250,12 +224,52 @@ 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\n",
+                         next_fc_block);
+               err = jread(&bh, journal, next_fc_block);
+               if (err) {
+                       jbd_debug(3, "Fast commit replay: read error\n");
+                       break;
+               }
+
+               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;
+}
+
 /**
- * journal_recover - recovers a on-disk journal
+ * jbd2_journal_recover - recovers a on-disk journal
  * @journal: the journal to recover
  *
  * The primary function for recovering the log contents when mounting a
@@ -266,7 +280,7 @@ do {                                                                        \
  * blocks.  In the third and final pass, we replay any un-revoked blocks
  * in the log.
  */
-int journal_recover(journal_t *journal)
+int jbd2_journal_recover(journal_t *journal)
 {
        int                     err, err2;
        journal_superblock_t *  sb;
@@ -284,8 +298,8 @@ int journal_recover(journal_t *journal)
 
        if (!sb->s_start) {
                jbd_debug(1, "No recovery required, last transaction %d\n",
-                         ext2fs_be32_to_cpu(sb->s_sequence));
-               journal->j_transaction_sequence = ext2fs_be32_to_cpu(sb->s_sequence) + 1;
+                         be32_to_cpu(sb->s_sequence));
+               journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;
                return 0;
        }
 
@@ -305,13 +319,13 @@ int journal_recover(journal_t *journal)
         * any existing commit records in the log. */
        journal->j_transaction_sequence = ++info.end_transaction;
 
-       journal_clear_revoke(journal);
+       jbd2_journal_clear_revoke(journal);
        err2 = sync_blockdev(journal->j_fs_dev);
        if (!err)
                err = err2;
        /* Make sure all replayed data is on permanent storage */
-       if (journal->j_flags & JFS_BARRIER) {
-               err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
+       if (journal->j_flags & JBD2_BARRIER) {
+               err2 = blkdev_issue_flush(journal->j_fs_dev);
                if (!err)
                        err = err2;
        }
@@ -319,19 +333,19 @@ int journal_recover(journal_t *journal)
 }
 
 /**
- * journal_skip_recovery - Start journal and wipe exiting records
+ * jbd2_journal_skip_recovery - Start journal and wipe exiting records
  * @journal: journal to startup
  *
  * Locate any valid recovery information from the journal and set up the
  * journal structures in memory to ignore it (presumably because the
  * caller has evidence that it is out of date).
- * This function does'nt appear to be exorted..
+ * This function doesn't appear to be exported..
  *
  * We perform one pass over the journal to allow us to tell the user how
  * much recovery information is being erased, and to let us initialise
  * the journal transaction sequence numbers to the next unused ID.
  */
-int journal_skip_recovery(journal_t *journal)
+int jbd2_journal_skip_recovery(journal_t *journal)
 {
        int                     err;
 
@@ -345,9 +359,9 @@ int journal_skip_recovery(journal_t *journal)
                printk(KERN_ERR "JBD2: error %d scanning journal\n", err);
                ++journal->j_transaction_sequence;
        } else {
-#ifdef CONFIG_JFS_DEBUG
-               int dropped = info.end_transaction -
-                       ext2fs_be32_to_cpu(journal->j_superblock->s_sequence);
+#ifdef CONFIG_JBD2_DEBUG
+               int dropped = info.end_transaction - 
+                       be32_to_cpu(journal->j_superblock->s_sequence);
                jbd_debug(1,
                          "JBD2: ignoring %d transaction%s from the journal.\n",
                          dropped, (dropped == 1) ? "" : "s");
@@ -362,9 +376,9 @@ int journal_skip_recovery(journal_t *journal)
 static inline unsigned long long read_tag_block(journal_t *journal,
                                                journal_block_tag_t *tag)
 {
-       unsigned long long block = get_be32(&tag->t_blocknr);
-       if (jfs_has_feature_64bit(journal))
-               block |= (u64)get_be32(&tag->t_blocknr_high) << 32;
+       unsigned long long block = be32_to_cpu(tag->t_blocknr);
+       if (jbd2_has_feature_64bit(journal))
+               block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32;
        return block;
 }
 
@@ -403,10 +417,10 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
 static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
 {
        struct commit_header *h;
-       __u32 provided;
+       __be32 provided;
        __u32 calculated;
 
-       if (!journal_has_csum_v2or3(j))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        h = buf;
@@ -415,27 +429,27 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
        calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
        h->h_chksum[0] = provided;
 
-       return provided == ext2fs_cpu_to_be32(calculated);
+       return provided == cpu_to_be32(calculated);
 }
 
 static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
+                                     journal_block_tag3_t *tag3,
                                      void *buf, __u32 sequence)
 {
-       journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
        __u32 csum32;
-       __u32 seq;
+       __be32 seq;
 
-       if (!journal_has_csum_v2or3(j))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
-       seq = ext2fs_cpu_to_be32(sequence);
+       seq = cpu_to_be32(sequence);
        csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
        csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize);
 
-       if (jfs_has_feature_csum3(j))
-               return get_be32(&tag3->t_checksum) == csum32;
-
-       return get_be16(&tag->t_checksum) == (csum32 & 0xFFFF);
+       if (jbd2_has_feature_csum3(j))
+               return tag3->t_checksum == cpu_to_be32(csum32);
+       else
+               return tag->t_checksum == cpu_to_be16(csum32);
 }
 
 static int do_one_pass(journal_t *journal,
@@ -453,6 +467,8 @@ static int do_one_pass(journal_t *journal,
        __u32                   crc32_sum = ~0; /* Transactional Checksums */
        int                     descr_csum_size = 0;
        int                     block_error = 0;
+       bool                    need_check_commit_time = false;
+       __u64                   last_trans_commit_time = 0, commit_time;
 
        /*
         * First thing is to establish what we expect to find in the log
@@ -461,8 +477,8 @@ static int do_one_pass(journal_t *journal,
         */
 
        sb = journal->j_superblock;
-       next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
-       next_log_block = ext2fs_be32_to_cpu(sb->s_start);
+       next_commit_ID = be32_to_cpu(sb->s_sequence);
+       next_log_block = be32_to_cpu(sb->s_start);
 
        first_commit_ID = next_commit_ID;
        if (pass == PASS_SCAN)
@@ -480,7 +496,7 @@ static int do_one_pass(journal_t *journal,
        while (1) {
                int                     flags;
                char *                  tagp;
-               journal_block_tag_t *   tag;
+               journal_block_tag_t     tag;
                struct buffer_head *    obh;
                struct buffer_head *    nbh;
 
@@ -495,7 +511,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
@@ -517,13 +535,13 @@ static int do_one_pass(journal_t *journal,
 
                tmp = (journal_header_t *)bh->b_data;
 
-               if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
+               if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {
                        brelse(bh);
                        break;
                }
 
-               blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
-               sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
+               blocktype = be32_to_cpu(tmp->h_blocktype);
+               sequence = be32_to_cpu(tmp->h_sequence);
                jbd_debug(3, "Found magic %d, sequence %d\n",
                          blocktype, sequence);
 
@@ -537,17 +555,29 @@ static int do_one_pass(journal_t *journal,
                 * to do with it?  That depends on the pass... */
 
                switch(blocktype) {
-               case JFS_DESCRIPTOR_BLOCK:
+               case JBD2_DESCRIPTOR_BLOCK:
                        /* Verify checksum first */
-                       if (journal_has_csum_v2or3(journal))
+                       if (jbd2_journal_has_csum_v2or3(journal))
                                descr_csum_size =
-                                       sizeof(struct journal_block_tail);
+                                       sizeof(struct jbd2_journal_block_tail);
                        if (descr_csum_size > 0 &&
-                           !jbd2_descr_block_csum_verify(journal,
-                                                         bh->b_data)) {
-                               err = -EFSBADCRC;
-                               brelse(bh);
-                               goto failed;
+                           !jbd2_descriptor_block_csum_verify(journal,
+                                                              bh->b_data)) {
+                               /*
+                                * PASS_SCAN can see stale blocks due to lazy
+                                * journal init. Don't error out on those yet.
+                                */
+                               if (pass != PASS_SCAN) {
+                                       pr_err("JBD2: Invalid checksum recovering block %lu in log\n",
+                                              next_log_block);
+                                       err = -EFSBADCRC;
+                                       brelse(bh);
+                                       goto failed;
+                               }
+                               need_check_commit_time = true;
+                               jbd_debug(1,
+                                       "invalid descriptor block found in %lu\n",
+                                       next_log_block);
                        }
 
                        /* If it is a valid descriptor block, replay it
@@ -556,7 +586,8 @@ static int do_one_pass(journal_t *journal,
                         * just skip over the blocks it describes. */
                        if (pass != PASS_REPLAY) {
                                if (pass == PASS_SCAN &&
-                                   jfs_has_feature_checksum(journal) &&
+                                   jbd2_has_feature_checksum(journal) &&
+                                   !need_check_commit_time &&
                                    !info->end_transaction) {
                                        if (calc_chksums(journal, bh,
                                                        &next_log_block,
@@ -582,8 +613,8 @@ static int do_one_pass(journal_t *journal,
                               <= journal->j_blocksize - descr_csum_size) {
                                unsigned long io_block;
 
-                               tag = (journal_block_tag_t *) tagp;
-                               flags = get_be16(&tag->t_flags);
+                               memcpy(&tag, tagp, sizeof(tag));
+                               flags = be16_to_cpu(tag.t_flags);
 
                                io_block = next_log_block++;
                                wrap(journal, next_log_block);
@@ -601,12 +632,12 @@ static int do_one_pass(journal_t *journal,
 
                                        J_ASSERT(obh != NULL);
                                        blocknr = read_tag_block(journal,
-                                                                tag);
+                                                                &tag);
 
                                        /* If the block has been
                                         * revoked, then we're all done
                                         * here. */
-                                       if (journal_test_revoke
+                                       if (jbd2_journal_test_revoke
                                            (journal, blocknr,
                                             next_commit_ID)) {
                                                brelse(obh);
@@ -616,14 +647,14 @@ static int do_one_pass(journal_t *journal,
 
                                        /* Look for block corruption */
                                        if (!jbd2_block_tag_csum_verify(
-                                               journal, tag, obh->b_data,
-                                               ext2fs_be32_to_cpu(tmp->h_sequence))) {
+                       journal, &tag, (journal_block_tag3_t *)tagp,
+                       obh->b_data, be32_to_cpu(tmp->h_sequence))) {
                                                brelse(obh);
                                                success = -EFSBADCRC;
                                                printk(KERN_ERR "JBD2: Invalid "
                                                       "checksum recovering "
-                                                      "block %llu in log\n",
-                                                      blocknr);
+                                                      "data block %llu in "
+                                                      "log\n", blocknr);
                                                block_error = 1;
                                                goto skip_write;
                                        }
@@ -646,10 +677,9 @@ static int do_one_pass(journal_t *journal,
                                        lock_buffer(nbh);
                                        memcpy(nbh->b_data, obh->b_data,
                                                        journal->j_blocksize);
-                                       if (flags & JFS_FLAG_ESCAPE) {
-                                               __u32 magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
-                                               memcpy(nbh->b_data, &magic,
-                                                      sizeof(magic));
+                                       if (flags & JBD2_FLAG_ESCAPE) {
+                                               *((__be32 *)nbh->b_data) =
+                                               cpu_to_be32(JBD2_MAGIC_NUMBER);
                                        }
 
                                        BUFFER_TRACE(nbh, "marking dirty");
@@ -665,17 +695,17 @@ static int do_one_pass(journal_t *journal,
 
                        skip_write:
                                tagp += tag_bytes;
-                               if (!(flags & JFS_FLAG_SAME_UUID))
+                               if (!(flags & JBD2_FLAG_SAME_UUID))
                                        tagp += 16;
 
-                               if (flags & JFS_FLAG_LAST_TAG)
+                               if (flags & JBD2_FLAG_LAST_TAG)
                                        break;
                        }
 
                        brelse(bh);
                        continue;
 
-               case JFS_COMMIT_BLOCK:
+               case JBD2_COMMIT_BLOCK:
                        /*     How to differentiate between interrupted commit
                         *               and journal corruption ?
                         *
@@ -706,20 +736,46 @@ static int do_one_pass(journal_t *journal,
                         *       mentioned conditions. Hence assume
                         *       "Interrupted Commit".)
                         */
+                       commit_time = be64_to_cpu(
+                               ((struct commit_header *)bh->b_data)->h_commit_sec);
+                       /*
+                        * If need_check_commit_time is set, it means we are in
+                        * PASS_SCAN and csum verify failed before. If
+                        * commit_time is increasing, it's the same journal,
+                        * otherwise it is stale journal block, just end this
+                        * recovery.
+                        */
+                       if (need_check_commit_time) {
+                               if (commit_time >= last_trans_commit_time) {
+                                       pr_err("JBD2: Invalid checksum found in transaction %u\n",
+                                              next_commit_ID);
+                                       err = -EFSBADCRC;
+                                       brelse(bh);
+                                       goto failed;
+                               }
+                       ignore_crc_mismatch:
+                               /*
+                                * It likely does not belong to same journal,
+                                * just end this recovery with success.
+                                */
+                               jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n",
+                                         next_commit_ID);
+                               brelse(bh);
+                               goto done;
+                       }
 
-                       /* Found an expected commit block: if checksums
-                        * are present verify them in PASS_SCAN; else not
+                       /*
+                        * Found an expected commit block: if checksums
+                        * are present, verify them in PASS_SCAN; else not
                         * much to do other than move on to the next sequence
-                        * number. */
+                        * number.
+                        */
                        if (pass == PASS_SCAN &&
-                           jfs_has_feature_checksum(journal)) {
-                               int chksum_err, chksum_seen;
+                           jbd2_has_feature_checksum(journal)) {
                                struct commit_header *cbh =
                                        (struct commit_header *)bh->b_data;
                                unsigned found_chksum =
-                                       ext2fs_be32_to_cpu(cbh->h_chksum[0]);
-
-                               chksum_err = chksum_seen = 0;
+                                       be32_to_cpu(cbh->h_chksum[0]);
 
                                if (info->end_transaction) {
                                        journal->j_failed_commit =
@@ -728,56 +784,52 @@ static int do_one_pass(journal_t *journal,
                                        break;
                                }
 
-                               if (crc32_sum == found_chksum &&
-                                   cbh->h_chksum_type == JFS_CRC32_CHKSUM &&
-                                   cbh->h_chksum_size ==
-                                               JFS_CRC32_CHKSUM_SIZE)
-                                      chksum_seen = 1;
-                               else if (!(cbh->h_chksum_type == 0 &&
-                                            cbh->h_chksum_size == 0 &&
-                                            found_chksum == 0 &&
-                                            !chksum_seen))
-                               /*
-                                * If fs is mounted using an old kernel and then
-                                * kernel with journal_chksum is used then we
-                                * get a situation where the journal flag has
-                                * checksum flag set but checksums are not
-                                * present i.e chksum = 0, in the individual
-                                * commit blocks.
-                                * Hence to avoid checksum failures, in this
-                                * situation, this extra check is added.
-                                */
-                                               chksum_err = 1;
-
-                               if (chksum_err) {
-                                       info->end_transaction = next_commit_ID;
+                               /* Neither checksum match nor unused? */
+                               if (!((crc32_sum == found_chksum &&
+                                      cbh->h_chksum_type ==
+                                               JBD2_CRC32_CHKSUM &&
+                                      cbh->h_chksum_size ==
+                                               JBD2_CRC32_CHKSUM_SIZE) ||
+                                     (cbh->h_chksum_type == 0 &&
+                                      cbh->h_chksum_size == 0 &&
+                                      found_chksum == 0)))
+                                       goto chksum_error;
 
-                                       if (!jfs_has_feature_async_commit(journal)){
-                                               journal->j_failed_commit =
-                                                       next_commit_ID;
-                                               brelse(bh);
-                                               break;
-                                       }
-                               }
                                crc32_sum = ~0;
                        }
                        if (pass == PASS_SCAN &&
                            !jbd2_commit_block_csum_verify(journal,
                                                           bh->b_data)) {
+                       chksum_error:
+                               if (commit_time < last_trans_commit_time)
+                                       goto ignore_crc_mismatch;
                                info->end_transaction = next_commit_ID;
 
-                               if (!jfs_has_feature_async_commit(journal)) {
+                               if (!jbd2_has_feature_async_commit(journal)) {
                                        journal->j_failed_commit =
                                                next_commit_ID;
                                        brelse(bh);
                                        break;
                                }
                        }
+                       if (pass == PASS_SCAN)
+                               last_trans_commit_time = commit_time;
                        brelse(bh);
                        next_commit_ID++;
                        continue;
 
-               case JFS_REVOKE_BLOCK:
+               case JBD2_REVOKE_BLOCK:
+                       /*
+                        * Check revoke block crc in pass_scan, if csum verify
+                        * failed, check commit block time later.
+                        */
+                       if (pass == PASS_SCAN &&
+                           !jbd2_descriptor_block_csum_verify(journal,
+                                                              bh->b_data)) {
+                               jbd_debug(1, "JBD2: invalid revoke block found in %lu\n",
+                                         next_log_block);
+                               need_check_commit_time = true;
+                       }
                        /* If we aren't in the REVOKE pass, then we can
                         * just skip over this block. */
                        if (pass != PASS_REVOKE) {
@@ -822,6 +874,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;
@@ -830,51 +889,28 @@ static int do_one_pass(journal_t *journal,
        return err;
 }
 
-static int jbd2_revoke_block_csum_verify(journal_t *j,
-                                        void *buf)
-{
-       struct journal_revoke_tail *tail;
-       __u32 provided;
-       __u32 calculated;
-
-       if (!journal_has_csum_v2or3(j))
-               return 1;
-
-       tail = (struct journal_revoke_tail *)((char *)buf + j->j_blocksize -
-                       sizeof(struct journal_revoke_tail));
-       provided = tail->r_checksum;
-       tail->r_checksum = 0;
-       calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
-       tail->r_checksum = provided;
-
-       return provided == ext2fs_cpu_to_be32(calculated);
-}
-
 /* Scan a revoke record, marking all blocks mentioned as revoked. */
 
 static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
                               tid_t sequence, struct recovery_info *info)
 {
-       journal_revoke_header_t *header;
+       jbd2_journal_revoke_header_t *header;
        int offset, max;
        unsigned csum_size = 0;
        __u32 rcount;
        int record_len = 4;
 
-       header = (journal_revoke_header_t *) bh->b_data;
-       offset = sizeof(journal_revoke_header_t);
-       rcount = ext2fs_be32_to_cpu(header->r_count);
-
-       if (!jbd2_revoke_block_csum_verify(journal, header))
-               return -EFSBADCRC;
+       header = (jbd2_journal_revoke_header_t *) bh->b_data;
+       offset = sizeof(jbd2_journal_revoke_header_t);
+       rcount = be32_to_cpu(header->r_count);
 
-       if (journal_has_csum_v2or3(journal))
-               csum_size = sizeof(struct journal_revoke_tail);
+       if (jbd2_journal_has_csum_v2or3(journal))
+               csum_size = sizeof(struct jbd2_journal_block_tail);
        if (rcount > journal->j_blocksize - csum_size)
                return -EINVAL;
        max = rcount;
 
-       if (jfs_has_feature_64bit(journal))
+       if (jbd2_has_feature_64bit(journal))
                record_len = 8;
 
        while (offset + record_len <= max) {
@@ -882,11 +918,11 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
                int err;
 
                if (record_len == 4)
-                       blocknr = ext2fs_be32_to_cpu(* ((__u32 *) (bh->b_data+offset)));
+                       blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));
                else
-                       blocknr = ext2fs_be64_to_cpu(* ((__u64 *) (bh->b_data+offset)));
+                       blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset)));
                offset += record_len;
-               err = journal_set_revoke(journal, blocknr, sequence);
+               err = jbd2_journal_set_revoke(journal, blocknr, sequence);
                if (err)
                        return err;
                ++info->nr_revokes;