1f5166768STheodore Ts'o // SPDX-License-Identifier: GPL-2.0+ 2470decc6SDave Kleikamp /* 358862699SUwe Kleine-König * linux/fs/jbd2/recovery.c 4470decc6SDave Kleikamp * 5470decc6SDave Kleikamp * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 6470decc6SDave Kleikamp * 7470decc6SDave Kleikamp * Copyright 1999-2000 Red Hat Software --- All Rights Reserved 8470decc6SDave Kleikamp * 9470decc6SDave Kleikamp * Journal recovery routines for the generic filesystem journaling code; 10470decc6SDave Kleikamp * part of the ext2fs journaling system. 11470decc6SDave Kleikamp */ 12470decc6SDave Kleikamp 13470decc6SDave Kleikamp #ifndef __KERNEL__ 14470decc6SDave Kleikamp #include "jfs_user.h" 15470decc6SDave Kleikamp #else 16470decc6SDave Kleikamp #include <linux/time.h> 17470decc6SDave Kleikamp #include <linux/fs.h> 18f7f4bccbSMingming Cao #include <linux/jbd2.h> 19470decc6SDave Kleikamp #include <linux/errno.h> 20818d276cSGirish Shilamkar #include <linux/crc32.h> 2179feb521SJan Kara #include <linux/blkdev.h> 22470decc6SDave Kleikamp #endif 23470decc6SDave Kleikamp 24470decc6SDave Kleikamp /* 25470decc6SDave Kleikamp * Maintain information about the progress of the recovery job, so that 26470decc6SDave Kleikamp * the different passes can carry information between them. 27470decc6SDave Kleikamp */ 28470decc6SDave Kleikamp struct recovery_info 29470decc6SDave Kleikamp { 30470decc6SDave Kleikamp tid_t start_transaction; 31470decc6SDave Kleikamp tid_t end_transaction; 32470decc6SDave Kleikamp 33470decc6SDave Kleikamp int nr_replays; 34470decc6SDave Kleikamp int nr_revokes; 35470decc6SDave Kleikamp int nr_revoke_hits; 36470decc6SDave Kleikamp }; 37470decc6SDave Kleikamp 38470decc6SDave Kleikamp static int do_one_pass(journal_t *journal, 39470decc6SDave Kleikamp struct recovery_info *info, enum passtype pass); 40470decc6SDave Kleikamp static int scan_revoke_records(journal_t *, struct buffer_head *, 41470decc6SDave Kleikamp tid_t, struct recovery_info *); 42470decc6SDave Kleikamp 43470decc6SDave Kleikamp #ifdef __KERNEL__ 44470decc6SDave Kleikamp 45470decc6SDave Kleikamp /* Release readahead buffers after use */ 46470decc6SDave Kleikamp static void journal_brelse_array(struct buffer_head *b[], int n) 47470decc6SDave Kleikamp { 48470decc6SDave Kleikamp while (--n >= 0) 49470decc6SDave Kleikamp brelse (b[n]); 50470decc6SDave Kleikamp } 51470decc6SDave Kleikamp 52470decc6SDave Kleikamp 53470decc6SDave Kleikamp /* 54470decc6SDave Kleikamp * When reading from the journal, we are going through the block device 55470decc6SDave Kleikamp * layer directly and so there is no readahead being done for us. We 56470decc6SDave Kleikamp * need to implement any readahead ourselves if we want it to happen at 57470decc6SDave Kleikamp * all. Recovery is basically one long sequential read, so make sure we 58470decc6SDave Kleikamp * do the IO in reasonably large chunks. 59470decc6SDave Kleikamp * 60470decc6SDave Kleikamp * This is not so critical that we need to be enormously clever about 61470decc6SDave Kleikamp * the readahead size, though. 128K is a purely arbitrary, good-enough 62470decc6SDave Kleikamp * fixed value. 63470decc6SDave Kleikamp */ 64470decc6SDave Kleikamp 65470decc6SDave Kleikamp #define MAXBUF 8 66470decc6SDave Kleikamp static int do_readahead(journal_t *journal, unsigned int start) 67470decc6SDave Kleikamp { 68470decc6SDave Kleikamp int err; 69470decc6SDave Kleikamp unsigned int max, nbufs, next; 7018eba7aaSMingming Cao unsigned long long blocknr; 71470decc6SDave Kleikamp struct buffer_head *bh; 72470decc6SDave Kleikamp 73470decc6SDave Kleikamp struct buffer_head * bufs[MAXBUF]; 74470decc6SDave Kleikamp 75470decc6SDave Kleikamp /* Do up to 128K of readahead */ 76470decc6SDave Kleikamp max = start + (128 * 1024 / journal->j_blocksize); 77ede7dc7fSHarshad Shirwadkar if (max > journal->j_total_len) 78ede7dc7fSHarshad Shirwadkar max = journal->j_total_len; 79470decc6SDave Kleikamp 80470decc6SDave Kleikamp /* Do the readahead itself. We'll submit MAXBUF buffer_heads at 81470decc6SDave Kleikamp * a time to the block device IO layer. */ 82470decc6SDave Kleikamp 83470decc6SDave Kleikamp nbufs = 0; 84470decc6SDave Kleikamp 85470decc6SDave Kleikamp for (next = start; next < max; next++) { 86f7f4bccbSMingming Cao err = jbd2_journal_bmap(journal, next, &blocknr); 87470decc6SDave Kleikamp 88470decc6SDave Kleikamp if (err) { 89f2a44523SEryu Guan printk(KERN_ERR "JBD2: bad block at offset %u\n", 90470decc6SDave Kleikamp next); 91470decc6SDave Kleikamp goto failed; 92470decc6SDave Kleikamp } 93470decc6SDave Kleikamp 94470decc6SDave Kleikamp bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); 95470decc6SDave Kleikamp if (!bh) { 96470decc6SDave Kleikamp err = -ENOMEM; 97470decc6SDave Kleikamp goto failed; 98470decc6SDave Kleikamp } 99470decc6SDave Kleikamp 100470decc6SDave Kleikamp if (!buffer_uptodate(bh) && !buffer_locked(bh)) { 101470decc6SDave Kleikamp bufs[nbufs++] = bh; 102470decc6SDave Kleikamp if (nbufs == MAXBUF) { 103*8c004d1fSZhang Yi bh_readahead_batch(nbufs, bufs, 0); 104470decc6SDave Kleikamp journal_brelse_array(bufs, nbufs); 105470decc6SDave Kleikamp nbufs = 0; 106470decc6SDave Kleikamp } 107470decc6SDave Kleikamp } else 108470decc6SDave Kleikamp brelse(bh); 109470decc6SDave Kleikamp } 110470decc6SDave Kleikamp 111470decc6SDave Kleikamp if (nbufs) 112*8c004d1fSZhang Yi bh_readahead_batch(nbufs, bufs, 0); 113470decc6SDave Kleikamp err = 0; 114470decc6SDave Kleikamp 115470decc6SDave Kleikamp failed: 116470decc6SDave Kleikamp if (nbufs) 117470decc6SDave Kleikamp journal_brelse_array(bufs, nbufs); 118470decc6SDave Kleikamp return err; 119470decc6SDave Kleikamp } 120470decc6SDave Kleikamp 121470decc6SDave Kleikamp #endif /* __KERNEL__ */ 122470decc6SDave Kleikamp 123470decc6SDave Kleikamp 124470decc6SDave Kleikamp /* 125470decc6SDave Kleikamp * Read a block from the journal 126470decc6SDave Kleikamp */ 127470decc6SDave Kleikamp 128470decc6SDave Kleikamp static int jread(struct buffer_head **bhp, journal_t *journal, 129470decc6SDave Kleikamp unsigned int offset) 130470decc6SDave Kleikamp { 131470decc6SDave Kleikamp int err; 13218eba7aaSMingming Cao unsigned long long blocknr; 133470decc6SDave Kleikamp struct buffer_head *bh; 134470decc6SDave Kleikamp 135470decc6SDave Kleikamp *bhp = NULL; 136470decc6SDave Kleikamp 137ede7dc7fSHarshad Shirwadkar if (offset >= journal->j_total_len) { 138f2a44523SEryu Guan printk(KERN_ERR "JBD2: corrupted journal superblock\n"); 1396a797d27SDarrick J. Wong return -EFSCORRUPTED; 140470decc6SDave Kleikamp } 141470decc6SDave Kleikamp 142f7f4bccbSMingming Cao err = jbd2_journal_bmap(journal, offset, &blocknr); 143470decc6SDave Kleikamp 144470decc6SDave Kleikamp if (err) { 145f2a44523SEryu Guan printk(KERN_ERR "JBD2: bad block at offset %u\n", 146470decc6SDave Kleikamp offset); 147470decc6SDave Kleikamp return err; 148470decc6SDave Kleikamp } 149470decc6SDave Kleikamp 150470decc6SDave Kleikamp bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); 151470decc6SDave Kleikamp if (!bh) 152470decc6SDave Kleikamp return -ENOMEM; 153470decc6SDave Kleikamp 154470decc6SDave Kleikamp if (!buffer_uptodate(bh)) { 155*8c004d1fSZhang Yi /* 156*8c004d1fSZhang Yi * If this is a brand new buffer, start readahead. 157*8c004d1fSZhang Yi * Otherwise, we assume we are already reading it. 158*8c004d1fSZhang Yi */ 159*8c004d1fSZhang Yi bool need_readahead = !buffer_req(bh); 160*8c004d1fSZhang Yi 161*8c004d1fSZhang Yi bh_read_nowait(bh, 0); 162*8c004d1fSZhang Yi if (need_readahead) 163470decc6SDave Kleikamp do_readahead(journal, offset); 164470decc6SDave Kleikamp wait_on_buffer(bh); 165470decc6SDave Kleikamp } 166470decc6SDave Kleikamp 167470decc6SDave Kleikamp if (!buffer_uptodate(bh)) { 168f2a44523SEryu Guan printk(KERN_ERR "JBD2: Failed to read block at offset %u\n", 169470decc6SDave Kleikamp offset); 170470decc6SDave Kleikamp brelse(bh); 171470decc6SDave Kleikamp return -EIO; 172470decc6SDave Kleikamp } 173470decc6SDave Kleikamp 174470decc6SDave Kleikamp *bhp = bh; 175470decc6SDave Kleikamp return 0; 176470decc6SDave Kleikamp } 177470decc6SDave Kleikamp 1781101cd4dSJan Kara static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf) 1793caa487fSDarrick J. Wong { 1803caa487fSDarrick J. Wong struct jbd2_journal_block_tail *tail; 18118a6ea1eSDarrick J. Wong __be32 provided; 18218a6ea1eSDarrick J. Wong __u32 calculated; 1833caa487fSDarrick J. Wong 184db9ee220SDarrick J. Wong if (!jbd2_journal_has_csum_v2or3(j)) 1853caa487fSDarrick J. Wong return 1; 1863caa487fSDarrick J. Wong 1874009cc7aSTheodore Ts'o tail = (struct jbd2_journal_block_tail *)((char *)buf + 1884009cc7aSTheodore Ts'o j->j_blocksize - sizeof(struct jbd2_journal_block_tail)); 1893caa487fSDarrick J. Wong provided = tail->t_checksum; 1903caa487fSDarrick J. Wong tail->t_checksum = 0; 1913caa487fSDarrick J. Wong calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); 1923caa487fSDarrick J. Wong tail->t_checksum = provided; 1933caa487fSDarrick J. Wong 19418a6ea1eSDarrick J. Wong return provided == cpu_to_be32(calculated); 1953caa487fSDarrick J. Wong } 196470decc6SDave Kleikamp 197470decc6SDave Kleikamp /* 198470decc6SDave Kleikamp * Count the number of in-use tags in a journal descriptor block. 199470decc6SDave Kleikamp */ 200470decc6SDave Kleikamp 201b517bea1SZach Brown static int count_tags(journal_t *journal, struct buffer_head *bh) 202470decc6SDave Kleikamp { 203470decc6SDave Kleikamp char * tagp; 204a20d1cebSTheodore Ts'o journal_block_tag_t tag; 205b517bea1SZach Brown int nr = 0, size = journal->j_blocksize; 206b517bea1SZach Brown int tag_bytes = journal_tag_bytes(journal); 207470decc6SDave Kleikamp 208db9ee220SDarrick J. Wong if (jbd2_journal_has_csum_v2or3(journal)) 2093caa487fSDarrick J. Wong size -= sizeof(struct jbd2_journal_block_tail); 2103caa487fSDarrick J. Wong 211470decc6SDave Kleikamp tagp = &bh->b_data[sizeof(journal_header_t)]; 212470decc6SDave Kleikamp 213b517bea1SZach Brown while ((tagp - bh->b_data + tag_bytes) <= size) { 214a20d1cebSTheodore Ts'o memcpy(&tag, tagp, sizeof(tag)); 215470decc6SDave Kleikamp 216470decc6SDave Kleikamp nr++; 217b517bea1SZach Brown tagp += tag_bytes; 218a20d1cebSTheodore Ts'o if (!(tag.t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID))) 219470decc6SDave Kleikamp tagp += 16; 220470decc6SDave Kleikamp 221a20d1cebSTheodore Ts'o if (tag.t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG)) 222470decc6SDave Kleikamp break; 223470decc6SDave Kleikamp } 224470decc6SDave Kleikamp 225470decc6SDave Kleikamp return nr; 226470decc6SDave Kleikamp } 227470decc6SDave Kleikamp 228470decc6SDave Kleikamp 229470decc6SDave Kleikamp /* Make sure we wrap around the log correctly! */ 230470decc6SDave Kleikamp #define wrap(journal, var) \ 231470decc6SDave Kleikamp do { \ 2325b849b5fSHarshad Shirwadkar unsigned long _wrap_last = \ 2335b849b5fSHarshad Shirwadkar jbd2_has_feature_fast_commit(journal) ? \ 2345b849b5fSHarshad Shirwadkar (journal)->j_fc_last : (journal)->j_last; \ 2355b849b5fSHarshad Shirwadkar \ 2365b849b5fSHarshad Shirwadkar if (var >= _wrap_last) \ 2375b849b5fSHarshad Shirwadkar var -= (_wrap_last - (journal)->j_first); \ 238470decc6SDave Kleikamp } while (0) 239470decc6SDave Kleikamp 2405b849b5fSHarshad Shirwadkar static int fc_do_one_pass(journal_t *journal, 2415b849b5fSHarshad Shirwadkar struct recovery_info *info, enum passtype pass) 2425b849b5fSHarshad Shirwadkar { 2435b849b5fSHarshad Shirwadkar unsigned int expected_commit_id = info->end_transaction; 2445b849b5fSHarshad Shirwadkar unsigned long next_fc_block; 2455b849b5fSHarshad Shirwadkar struct buffer_head *bh; 2465b849b5fSHarshad Shirwadkar int err = 0; 2475b849b5fSHarshad Shirwadkar 2485b849b5fSHarshad Shirwadkar next_fc_block = journal->j_fc_first; 2495b849b5fSHarshad Shirwadkar if (!journal->j_fc_replay_callback) 2505b849b5fSHarshad Shirwadkar return 0; 2515b849b5fSHarshad Shirwadkar 2525b849b5fSHarshad Shirwadkar while (next_fc_block <= journal->j_fc_last) { 253cb3b3bf2SJan Kara jbd2_debug(3, "Fast commit replay: next block %ld\n", 2545b849b5fSHarshad Shirwadkar next_fc_block); 2555b849b5fSHarshad Shirwadkar err = jread(&bh, journal, next_fc_block); 2565b849b5fSHarshad Shirwadkar if (err) { 257cb3b3bf2SJan Kara jbd2_debug(3, "Fast commit replay: read error\n"); 2585b849b5fSHarshad Shirwadkar break; 2595b849b5fSHarshad Shirwadkar } 2605b849b5fSHarshad Shirwadkar 2615b849b5fSHarshad Shirwadkar err = journal->j_fc_replay_callback(journal, bh, pass, 2625b849b5fSHarshad Shirwadkar next_fc_block - journal->j_fc_first, 2635b849b5fSHarshad Shirwadkar expected_commit_id); 2645b849b5fSHarshad Shirwadkar next_fc_block++; 2655b849b5fSHarshad Shirwadkar if (err < 0 || err == JBD2_FC_REPLAY_STOP) 2665b849b5fSHarshad Shirwadkar break; 2675b849b5fSHarshad Shirwadkar err = 0; 2685b849b5fSHarshad Shirwadkar } 2695b849b5fSHarshad Shirwadkar 2705b849b5fSHarshad Shirwadkar if (err) 271cb3b3bf2SJan Kara jbd2_debug(3, "Fast commit replay failed, err = %d\n", err); 2725b849b5fSHarshad Shirwadkar 2735b849b5fSHarshad Shirwadkar return err; 2745b849b5fSHarshad Shirwadkar } 2755b849b5fSHarshad Shirwadkar 276470decc6SDave Kleikamp /** 277f7f4bccbSMingming Cao * jbd2_journal_recover - recovers a on-disk journal 278470decc6SDave Kleikamp * @journal: the journal to recover 279470decc6SDave Kleikamp * 280470decc6SDave Kleikamp * The primary function for recovering the log contents when mounting a 281470decc6SDave Kleikamp * journaled device. 282470decc6SDave Kleikamp * 283470decc6SDave Kleikamp * Recovery is done in three passes. In the first pass, we look for the 284470decc6SDave Kleikamp * end of the log. In the second, we assemble the list of revoke 285470decc6SDave Kleikamp * blocks. In the third and final pass, we replay any un-revoked blocks 286470decc6SDave Kleikamp * in the log. 287470decc6SDave Kleikamp */ 288f7f4bccbSMingming Cao int jbd2_journal_recover(journal_t *journal) 289470decc6SDave Kleikamp { 29044519fafSHidehiro Kawai int err, err2; 291470decc6SDave Kleikamp journal_superblock_t * sb; 292470decc6SDave Kleikamp 293470decc6SDave Kleikamp struct recovery_info info; 294470decc6SDave Kleikamp 295470decc6SDave Kleikamp memset(&info, 0, sizeof(info)); 296470decc6SDave Kleikamp sb = journal->j_superblock; 297470decc6SDave Kleikamp 298470decc6SDave Kleikamp /* 299470decc6SDave Kleikamp * The journal superblock's s_start field (the current log head) 300470decc6SDave Kleikamp * is always zero if, and only if, the journal was cleanly 301470decc6SDave Kleikamp * unmounted. 302470decc6SDave Kleikamp */ 303470decc6SDave Kleikamp 304470decc6SDave Kleikamp if (!sb->s_start) { 305cb3b3bf2SJan Kara jbd2_debug(1, "No recovery required, last transaction %d\n", 306470decc6SDave Kleikamp be32_to_cpu(sb->s_sequence)); 307470decc6SDave Kleikamp journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; 308470decc6SDave Kleikamp return 0; 309470decc6SDave Kleikamp } 310470decc6SDave Kleikamp 311470decc6SDave Kleikamp err = do_one_pass(journal, &info, PASS_SCAN); 312470decc6SDave Kleikamp if (!err) 313470decc6SDave Kleikamp err = do_one_pass(journal, &info, PASS_REVOKE); 314470decc6SDave Kleikamp if (!err) 315470decc6SDave Kleikamp err = do_one_pass(journal, &info, PASS_REPLAY); 316470decc6SDave Kleikamp 317cb3b3bf2SJan Kara jbd2_debug(1, "JBD2: recovery, exit status %d, " 318470decc6SDave Kleikamp "recovered transactions %u to %u\n", 319470decc6SDave Kleikamp err, info.start_transaction, info.end_transaction); 320cb3b3bf2SJan Kara jbd2_debug(1, "JBD2: Replayed %d and revoked %d/%d blocks\n", 321470decc6SDave Kleikamp info.nr_replays, info.nr_revoke_hits, info.nr_revokes); 322470decc6SDave Kleikamp 323470decc6SDave Kleikamp /* Restart the log at the next transaction ID, thus invalidating 324470decc6SDave Kleikamp * any existing commit records in the log. */ 325470decc6SDave Kleikamp journal->j_transaction_sequence = ++info.end_transaction; 326470decc6SDave Kleikamp 327f7f4bccbSMingming Cao jbd2_journal_clear_revoke(journal); 32844519fafSHidehiro Kawai err2 = sync_blockdev(journal->j_fs_dev); 32944519fafSHidehiro Kawai if (!err) 33044519fafSHidehiro Kawai err = err2; 33179feb521SJan Kara /* Make sure all replayed data is on permanent storage */ 332316e4cfdSTheodore Ts'o if (journal->j_flags & JBD2_BARRIER) { 333c6bf3f0eSChristoph Hellwig err2 = blkdev_issue_flush(journal->j_fs_dev); 334316e4cfdSTheodore Ts'o if (!err) 335316e4cfdSTheodore Ts'o err = err2; 336316e4cfdSTheodore Ts'o } 337470decc6SDave Kleikamp return err; 338470decc6SDave Kleikamp } 339470decc6SDave Kleikamp 340470decc6SDave Kleikamp /** 341f7f4bccbSMingming Cao * jbd2_journal_skip_recovery - Start journal and wipe exiting records 342470decc6SDave Kleikamp * @journal: journal to startup 343470decc6SDave Kleikamp * 344470decc6SDave Kleikamp * Locate any valid recovery information from the journal and set up the 345470decc6SDave Kleikamp * journal structures in memory to ignore it (presumably because the 346470decc6SDave Kleikamp * caller has evidence that it is out of date). 347bd7ced98SMasanari Iida * This function doesn't appear to be exported.. 348470decc6SDave Kleikamp * 349470decc6SDave Kleikamp * We perform one pass over the journal to allow us to tell the user how 350470decc6SDave Kleikamp * much recovery information is being erased, and to let us initialise 351470decc6SDave Kleikamp * the journal transaction sequence numbers to the next unused ID. 352470decc6SDave Kleikamp */ 353f7f4bccbSMingming Cao int jbd2_journal_skip_recovery(journal_t *journal) 354470decc6SDave Kleikamp { 355470decc6SDave Kleikamp int err; 356470decc6SDave Kleikamp 357470decc6SDave Kleikamp struct recovery_info info; 358470decc6SDave Kleikamp 359470decc6SDave Kleikamp memset (&info, 0, sizeof(info)); 360470decc6SDave Kleikamp 361470decc6SDave Kleikamp err = do_one_pass(journal, &info, PASS_SCAN); 362470decc6SDave Kleikamp 363470decc6SDave Kleikamp if (err) { 364f2a44523SEryu Guan printk(KERN_ERR "JBD2: error %d scanning journal\n", err); 365470decc6SDave Kleikamp ++journal->j_transaction_sequence; 366470decc6SDave Kleikamp } else { 367e23291b9SJose R. Santos #ifdef CONFIG_JBD2_DEBUG 3685a0790c2SAndi Kleen int dropped = info.end_transaction - 3695a0790c2SAndi Kleen be32_to_cpu(journal->j_superblock->s_sequence); 370cb3b3bf2SJan Kara jbd2_debug(1, 371f2a44523SEryu Guan "JBD2: ignoring %d transaction%s from the journal.\n", 372470decc6SDave Kleikamp dropped, (dropped == 1) ? "" : "s"); 3739a4f6271STheodore Ts'o #endif 374470decc6SDave Kleikamp journal->j_transaction_sequence = ++info.end_transaction; 375470decc6SDave Kleikamp } 376470decc6SDave Kleikamp 377470decc6SDave Kleikamp journal->j_tail = 0; 378470decc6SDave Kleikamp return err; 379470decc6SDave Kleikamp } 380470decc6SDave Kleikamp 381db9ee220SDarrick J. Wong static inline unsigned long long read_tag_block(journal_t *journal, 382db9ee220SDarrick J. Wong journal_block_tag_t *tag) 383b517bea1SZach Brown { 38418eba7aaSMingming Cao unsigned long long block = be32_to_cpu(tag->t_blocknr); 38556316a0dSDarrick J. Wong if (jbd2_has_feature_64bit(journal)) 386b517bea1SZach Brown block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; 387b517bea1SZach Brown return block; 388b517bea1SZach Brown } 389b517bea1SZach Brown 390818d276cSGirish Shilamkar /* 391818d276cSGirish Shilamkar * calc_chksums calculates the checksums for the blocks described in the 392818d276cSGirish Shilamkar * descriptor block. 393818d276cSGirish Shilamkar */ 394818d276cSGirish Shilamkar static int calc_chksums(journal_t *journal, struct buffer_head *bh, 395818d276cSGirish Shilamkar unsigned long *next_log_block, __u32 *crc32_sum) 396818d276cSGirish Shilamkar { 397818d276cSGirish Shilamkar int i, num_blks, err; 398818d276cSGirish Shilamkar unsigned long io_block; 399818d276cSGirish Shilamkar struct buffer_head *obh; 400818d276cSGirish Shilamkar 401818d276cSGirish Shilamkar num_blks = count_tags(journal, bh); 402818d276cSGirish Shilamkar /* Calculate checksum of the descriptor block. */ 403818d276cSGirish Shilamkar *crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size); 404818d276cSGirish Shilamkar 405818d276cSGirish Shilamkar for (i = 0; i < num_blks; i++) { 406818d276cSGirish Shilamkar io_block = (*next_log_block)++; 407818d276cSGirish Shilamkar wrap(journal, *next_log_block); 408818d276cSGirish Shilamkar err = jread(&obh, journal, io_block); 409818d276cSGirish Shilamkar if (err) { 410f2a44523SEryu Guan printk(KERN_ERR "JBD2: IO error %d recovering block " 411818d276cSGirish Shilamkar "%lu in log\n", err, io_block); 412818d276cSGirish Shilamkar return 1; 413818d276cSGirish Shilamkar } else { 414818d276cSGirish Shilamkar *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data, 415818d276cSGirish Shilamkar obh->b_size); 416818d276cSGirish Shilamkar } 4178ea76900STheodore Ts'o put_bh(obh); 418818d276cSGirish Shilamkar } 419818d276cSGirish Shilamkar return 0; 420818d276cSGirish Shilamkar } 421818d276cSGirish Shilamkar 4221f56c589SDarrick J. Wong static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) 4231f56c589SDarrick J. Wong { 4241f56c589SDarrick J. Wong struct commit_header *h; 42518a6ea1eSDarrick J. Wong __be32 provided; 42618a6ea1eSDarrick J. Wong __u32 calculated; 4271f56c589SDarrick J. Wong 428db9ee220SDarrick J. Wong if (!jbd2_journal_has_csum_v2or3(j)) 4291f56c589SDarrick J. Wong return 1; 4301f56c589SDarrick J. Wong 4311f56c589SDarrick J. Wong h = buf; 4321f56c589SDarrick J. Wong provided = h->h_chksum[0]; 4331f56c589SDarrick J. Wong h->h_chksum[0] = 0; 4341f56c589SDarrick J. Wong calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); 4351f56c589SDarrick J. Wong h->h_chksum[0] = provided; 4361f56c589SDarrick J. Wong 43718a6ea1eSDarrick J. Wong return provided == cpu_to_be32(calculated); 4381f56c589SDarrick J. Wong } 4391f56c589SDarrick J. Wong 440c3900875SDarrick J. Wong static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, 441a20d1cebSTheodore Ts'o journal_block_tag3_t *tag3, 442c3900875SDarrick J. Wong void *buf, __u32 sequence) 443c3900875SDarrick J. Wong { 444eee06c56SDarrick J. Wong __u32 csum32; 44518a6ea1eSDarrick J. Wong __be32 seq; 446c3900875SDarrick J. Wong 447db9ee220SDarrick J. Wong if (!jbd2_journal_has_csum_v2or3(j)) 448c3900875SDarrick J. Wong return 1; 449c3900875SDarrick J. Wong 45018a6ea1eSDarrick J. Wong seq = cpu_to_be32(sequence); 45118a6ea1eSDarrick J. Wong csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); 452eee06c56SDarrick J. Wong csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize); 453c3900875SDarrick J. Wong 45456316a0dSDarrick J. Wong if (jbd2_has_feature_csum3(j)) 455db9ee220SDarrick J. Wong return tag3->t_checksum == cpu_to_be32(csum32); 456db9ee220SDarrick J. Wong else 457eee06c56SDarrick J. Wong return tag->t_checksum == cpu_to_be16(csum32); 458c3900875SDarrick J. Wong } 459c3900875SDarrick J. Wong 460470decc6SDave Kleikamp static int do_one_pass(journal_t *journal, 461470decc6SDave Kleikamp struct recovery_info *info, enum passtype pass) 462470decc6SDave Kleikamp { 463470decc6SDave Kleikamp unsigned int first_commit_ID, next_commit_ID; 464470decc6SDave Kleikamp unsigned long next_log_block; 465470decc6SDave Kleikamp int err, success = 0; 466470decc6SDave Kleikamp journal_superblock_t * sb; 467470decc6SDave Kleikamp journal_header_t * tmp; 468470decc6SDave Kleikamp struct buffer_head * bh; 469470decc6SDave Kleikamp unsigned int sequence; 470470decc6SDave Kleikamp int blocktype; 471b517bea1SZach Brown int tag_bytes = journal_tag_bytes(journal); 472818d276cSGirish Shilamkar __u32 crc32_sum = ~0; /* Transactional Checksums */ 4733caa487fSDarrick J. Wong int descr_csum_size = 0; 474022eaa75SDarrick J. Wong int block_error = 0; 475fc750a3bSchangfengnan bool need_check_commit_time = false; 476fc750a3bSchangfengnan __u64 last_trans_commit_time = 0, commit_time; 477470decc6SDave Kleikamp 478470decc6SDave Kleikamp /* 479470decc6SDave Kleikamp * First thing is to establish what we expect to find in the log 480470decc6SDave Kleikamp * (in terms of transaction IDs), and where (in terms of log 481470decc6SDave Kleikamp * block offsets): query the superblock. 482470decc6SDave Kleikamp */ 483470decc6SDave Kleikamp 484470decc6SDave Kleikamp sb = journal->j_superblock; 485470decc6SDave Kleikamp next_commit_ID = be32_to_cpu(sb->s_sequence); 486470decc6SDave Kleikamp next_log_block = be32_to_cpu(sb->s_start); 487470decc6SDave Kleikamp 488470decc6SDave Kleikamp first_commit_ID = next_commit_ID; 489470decc6SDave Kleikamp if (pass == PASS_SCAN) 490470decc6SDave Kleikamp info->start_transaction = first_commit_ID; 491470decc6SDave Kleikamp 492cb3b3bf2SJan Kara jbd2_debug(1, "Starting recovery pass %d\n", pass); 493470decc6SDave Kleikamp 494470decc6SDave Kleikamp /* 495470decc6SDave Kleikamp * Now we walk through the log, transaction by transaction, 496470decc6SDave Kleikamp * making sure that each transaction has a commit block in the 497470decc6SDave Kleikamp * expected place. Each complete transaction gets replayed back 498470decc6SDave Kleikamp * into the main filesystem. 499470decc6SDave Kleikamp */ 500470decc6SDave Kleikamp 501470decc6SDave Kleikamp while (1) { 502470decc6SDave Kleikamp int flags; 503470decc6SDave Kleikamp char * tagp; 504a20d1cebSTheodore Ts'o journal_block_tag_t tag; 505470decc6SDave Kleikamp struct buffer_head * obh; 506470decc6SDave Kleikamp struct buffer_head * nbh; 507470decc6SDave Kleikamp 508e86e1438SAndi Kleen cond_resched(); 509470decc6SDave Kleikamp 510470decc6SDave Kleikamp /* If we already know where to stop the log traversal, 511470decc6SDave Kleikamp * check right now that we haven't gone past the end of 512470decc6SDave Kleikamp * the log. */ 513470decc6SDave Kleikamp 514470decc6SDave Kleikamp if (pass != PASS_SCAN) 515470decc6SDave Kleikamp if (tid_geq(next_commit_ID, info->end_transaction)) 516470decc6SDave Kleikamp break; 517470decc6SDave Kleikamp 518cb3b3bf2SJan Kara jbd2_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", 5195b849b5fSHarshad Shirwadkar next_commit_ID, next_log_block, 5205b849b5fSHarshad Shirwadkar jbd2_has_feature_fast_commit(journal) ? 5215b849b5fSHarshad Shirwadkar journal->j_fc_last : journal->j_last); 522470decc6SDave Kleikamp 523470decc6SDave Kleikamp /* Skip over each chunk of the transaction looking 524470decc6SDave Kleikamp * either the next descriptor block or the final commit 525470decc6SDave Kleikamp * record. */ 526470decc6SDave Kleikamp 527cb3b3bf2SJan Kara jbd2_debug(3, "JBD2: checking block %ld\n", next_log_block); 528470decc6SDave Kleikamp err = jread(&bh, journal, next_log_block); 529470decc6SDave Kleikamp if (err) 530470decc6SDave Kleikamp goto failed; 531470decc6SDave Kleikamp 532470decc6SDave Kleikamp next_log_block++; 533470decc6SDave Kleikamp wrap(journal, next_log_block); 534470decc6SDave Kleikamp 535470decc6SDave Kleikamp /* What kind of buffer is it? 536470decc6SDave Kleikamp * 537470decc6SDave Kleikamp * If it is a descriptor block, check that it has the 538470decc6SDave Kleikamp * expected sequence number. Otherwise, we're all done 539470decc6SDave Kleikamp * here. */ 540470decc6SDave Kleikamp 541470decc6SDave Kleikamp tmp = (journal_header_t *)bh->b_data; 542470decc6SDave Kleikamp 543f7f4bccbSMingming Cao if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) { 544470decc6SDave Kleikamp brelse(bh); 545470decc6SDave Kleikamp break; 546470decc6SDave Kleikamp } 547470decc6SDave Kleikamp 548470decc6SDave Kleikamp blocktype = be32_to_cpu(tmp->h_blocktype); 549470decc6SDave Kleikamp sequence = be32_to_cpu(tmp->h_sequence); 550cb3b3bf2SJan Kara jbd2_debug(3, "Found magic %d, sequence %d\n", 551470decc6SDave Kleikamp blocktype, sequence); 552470decc6SDave Kleikamp 553470decc6SDave Kleikamp if (sequence != next_commit_ID) { 554470decc6SDave Kleikamp brelse(bh); 555470decc6SDave Kleikamp break; 556470decc6SDave Kleikamp } 557470decc6SDave Kleikamp 558470decc6SDave Kleikamp /* OK, we have a valid descriptor block which matches 559470decc6SDave Kleikamp * all of the sequence number checks. What are we going 560470decc6SDave Kleikamp * to do with it? That depends on the pass... */ 561470decc6SDave Kleikamp 562470decc6SDave Kleikamp switch(blocktype) { 563f7f4bccbSMingming Cao case JBD2_DESCRIPTOR_BLOCK: 5643caa487fSDarrick J. Wong /* Verify checksum first */ 565db9ee220SDarrick J. Wong if (jbd2_journal_has_csum_v2or3(journal)) 5663caa487fSDarrick J. Wong descr_csum_size = 5673caa487fSDarrick J. Wong sizeof(struct jbd2_journal_block_tail); 5683caa487fSDarrick J. Wong if (descr_csum_size > 0 && 5691101cd4dSJan Kara !jbd2_descriptor_block_csum_verify(journal, 5703caa487fSDarrick J. Wong bh->b_data)) { 571fc750a3bSchangfengnan /* 572fc750a3bSchangfengnan * PASS_SCAN can see stale blocks due to lazy 573fc750a3bSchangfengnan * journal init. Don't error out on those yet. 574fc750a3bSchangfengnan */ 575fc750a3bSchangfengnan if (pass != PASS_SCAN) { 576fc750a3bSchangfengnan pr_err("JBD2: Invalid checksum recovering block %lu in log\n", 577b6924225SDarrick J. Wong next_log_block); 5786a797d27SDarrick J. Wong err = -EFSBADCRC; 579064d8389SDarrick J. Wong brelse(bh); 5803caa487fSDarrick J. Wong goto failed; 5813caa487fSDarrick J. Wong } 582fc750a3bSchangfengnan need_check_commit_time = true; 583cb3b3bf2SJan Kara jbd2_debug(1, 584fc750a3bSchangfengnan "invalid descriptor block found in %lu\n", 585fc750a3bSchangfengnan next_log_block); 586fc750a3bSchangfengnan } 5873caa487fSDarrick J. Wong 588470decc6SDave Kleikamp /* If it is a valid descriptor block, replay it 589818d276cSGirish Shilamkar * in pass REPLAY; if journal_checksums enabled, then 590818d276cSGirish Shilamkar * calculate checksums in PASS_SCAN, otherwise, 591818d276cSGirish Shilamkar * just skip over the blocks it describes. */ 592470decc6SDave Kleikamp if (pass != PASS_REPLAY) { 593818d276cSGirish Shilamkar if (pass == PASS_SCAN && 59456316a0dSDarrick J. Wong jbd2_has_feature_checksum(journal) && 595fc750a3bSchangfengnan !need_check_commit_time && 596818d276cSGirish Shilamkar !info->end_transaction) { 597818d276cSGirish Shilamkar if (calc_chksums(journal, bh, 598818d276cSGirish Shilamkar &next_log_block, 599818d276cSGirish Shilamkar &crc32_sum)) { 600818d276cSGirish Shilamkar put_bh(bh); 601818d276cSGirish Shilamkar break; 602818d276cSGirish Shilamkar } 603818d276cSGirish Shilamkar put_bh(bh); 604818d276cSGirish Shilamkar continue; 605818d276cSGirish Shilamkar } 606b517bea1SZach Brown next_log_block += count_tags(journal, bh); 607470decc6SDave Kleikamp wrap(journal, next_log_block); 608818d276cSGirish Shilamkar put_bh(bh); 609470decc6SDave Kleikamp continue; 610470decc6SDave Kleikamp } 611470decc6SDave Kleikamp 612470decc6SDave Kleikamp /* A descriptor block: we can now write all of 613470decc6SDave Kleikamp * the data blocks. Yay, useful work is finally 614470decc6SDave Kleikamp * getting done here! */ 615470decc6SDave Kleikamp 616470decc6SDave Kleikamp tagp = &bh->b_data[sizeof(journal_header_t)]; 617b517bea1SZach Brown while ((tagp - bh->b_data + tag_bytes) 6183caa487fSDarrick J. Wong <= journal->j_blocksize - descr_csum_size) { 619470decc6SDave Kleikamp unsigned long io_block; 620470decc6SDave Kleikamp 621a20d1cebSTheodore Ts'o memcpy(&tag, tagp, sizeof(tag)); 622a20d1cebSTheodore Ts'o flags = be16_to_cpu(tag.t_flags); 623470decc6SDave Kleikamp 624470decc6SDave Kleikamp io_block = next_log_block++; 625470decc6SDave Kleikamp wrap(journal, next_log_block); 626470decc6SDave Kleikamp err = jread(&obh, journal, io_block); 627470decc6SDave Kleikamp if (err) { 628470decc6SDave Kleikamp /* Recover what we can, but 629470decc6SDave Kleikamp * report failure at the end. */ 630470decc6SDave Kleikamp success = err; 631470decc6SDave Kleikamp printk(KERN_ERR 632f2a44523SEryu Guan "JBD2: IO error %d recovering " 633470decc6SDave Kleikamp "block %ld in log\n", 634470decc6SDave Kleikamp err, io_block); 635470decc6SDave Kleikamp } else { 63618eba7aaSMingming Cao unsigned long long blocknr; 637470decc6SDave Kleikamp 638470decc6SDave Kleikamp J_ASSERT(obh != NULL); 639db9ee220SDarrick J. Wong blocknr = read_tag_block(journal, 640a20d1cebSTheodore Ts'o &tag); 641470decc6SDave Kleikamp 642470decc6SDave Kleikamp /* If the block has been 643470decc6SDave Kleikamp * revoked, then we're all done 644470decc6SDave Kleikamp * here. */ 645f7f4bccbSMingming Cao if (jbd2_journal_test_revoke 646470decc6SDave Kleikamp (journal, blocknr, 647470decc6SDave Kleikamp next_commit_ID)) { 648470decc6SDave Kleikamp brelse(obh); 649470decc6SDave Kleikamp ++info->nr_revoke_hits; 650470decc6SDave Kleikamp goto skip_write; 651470decc6SDave Kleikamp } 652470decc6SDave Kleikamp 653c3900875SDarrick J. Wong /* Look for block corruption */ 654c3900875SDarrick J. Wong if (!jbd2_block_tag_csum_verify( 655a20d1cebSTheodore Ts'o journal, &tag, (journal_block_tag3_t *)tagp, 656a20d1cebSTheodore Ts'o obh->b_data, be32_to_cpu(tmp->h_sequence))) { 657c3900875SDarrick J. Wong brelse(obh); 6586a797d27SDarrick J. Wong success = -EFSBADCRC; 659a67c848aSDmitry Monakhov printk(KERN_ERR "JBD2: Invalid " 660c3900875SDarrick J. Wong "checksum recovering " 661ed65b00fSTheodore Ts'o "data block %llu in " 662ed65b00fSTheodore Ts'o "log\n", blocknr); 663022eaa75SDarrick J. Wong block_error = 1; 664022eaa75SDarrick J. Wong goto skip_write; 665c3900875SDarrick J. Wong } 666c3900875SDarrick J. Wong 667470decc6SDave Kleikamp /* Find a buffer for the new 668470decc6SDave Kleikamp * data being restored */ 669470decc6SDave Kleikamp nbh = __getblk(journal->j_fs_dev, 670470decc6SDave Kleikamp blocknr, 671470decc6SDave Kleikamp journal->j_blocksize); 672470decc6SDave Kleikamp if (nbh == NULL) { 673470decc6SDave Kleikamp printk(KERN_ERR 674f2a44523SEryu Guan "JBD2: Out of memory " 675470decc6SDave Kleikamp "during recovery.\n"); 676470decc6SDave Kleikamp err = -ENOMEM; 677470decc6SDave Kleikamp brelse(bh); 678470decc6SDave Kleikamp brelse(obh); 679470decc6SDave Kleikamp goto failed; 680470decc6SDave Kleikamp } 681470decc6SDave Kleikamp 682470decc6SDave Kleikamp lock_buffer(nbh); 683470decc6SDave Kleikamp memcpy(nbh->b_data, obh->b_data, 684470decc6SDave Kleikamp journal->j_blocksize); 685f7f4bccbSMingming Cao if (flags & JBD2_FLAG_ESCAPE) { 686d0025676SDuane Griffin *((__be32 *)nbh->b_data) = 687f7f4bccbSMingming Cao cpu_to_be32(JBD2_MAGIC_NUMBER); 688470decc6SDave Kleikamp } 689470decc6SDave Kleikamp 690470decc6SDave Kleikamp BUFFER_TRACE(nbh, "marking dirty"); 691470decc6SDave Kleikamp set_buffer_uptodate(nbh); 692470decc6SDave Kleikamp mark_buffer_dirty(nbh); 693470decc6SDave Kleikamp BUFFER_TRACE(nbh, "marking uptodate"); 694470decc6SDave Kleikamp ++info->nr_replays; 695470decc6SDave Kleikamp unlock_buffer(nbh); 696470decc6SDave Kleikamp brelse(obh); 697470decc6SDave Kleikamp brelse(nbh); 698470decc6SDave Kleikamp } 699470decc6SDave Kleikamp 700470decc6SDave Kleikamp skip_write: 701b517bea1SZach Brown tagp += tag_bytes; 702f7f4bccbSMingming Cao if (!(flags & JBD2_FLAG_SAME_UUID)) 703470decc6SDave Kleikamp tagp += 16; 704470decc6SDave Kleikamp 705f7f4bccbSMingming Cao if (flags & JBD2_FLAG_LAST_TAG) 706470decc6SDave Kleikamp break; 707470decc6SDave Kleikamp } 708470decc6SDave Kleikamp 709470decc6SDave Kleikamp brelse(bh); 710470decc6SDave Kleikamp continue; 711470decc6SDave Kleikamp 712f7f4bccbSMingming Cao case JBD2_COMMIT_BLOCK: 713818d276cSGirish Shilamkar /* How to differentiate between interrupted commit 714818d276cSGirish Shilamkar * and journal corruption ? 715818d276cSGirish Shilamkar * 716818d276cSGirish Shilamkar * {nth transaction} 717818d276cSGirish Shilamkar * Checksum Verification Failed 718818d276cSGirish Shilamkar * | 719818d276cSGirish Shilamkar * ____________________ 720818d276cSGirish Shilamkar * | | 721818d276cSGirish Shilamkar * async_commit sync_commit 722818d276cSGirish Shilamkar * | | 723818d276cSGirish Shilamkar * | GO TO NEXT "Journal Corruption" 724818d276cSGirish Shilamkar * | TRANSACTION 725818d276cSGirish Shilamkar * | 726818d276cSGirish Shilamkar * {(n+1)th transanction} 727818d276cSGirish Shilamkar * | 728818d276cSGirish Shilamkar * _______|______________ 729818d276cSGirish Shilamkar * | | 730818d276cSGirish Shilamkar * Commit block found Commit block not found 731818d276cSGirish Shilamkar * | | 732818d276cSGirish Shilamkar * "Journal Corruption" | 733818d276cSGirish Shilamkar * _____________|_________ 734818d276cSGirish Shilamkar * | | 735818d276cSGirish Shilamkar * nth trans corrupt OR nth trans 736818d276cSGirish Shilamkar * and (n+1)th interrupted interrupted 737818d276cSGirish Shilamkar * before commit block 738818d276cSGirish Shilamkar * could reach the disk. 739818d276cSGirish Shilamkar * (Cannot find the difference in above 740818d276cSGirish Shilamkar * mentioned conditions. Hence assume 741818d276cSGirish Shilamkar * "Interrupted Commit".) 742818d276cSGirish Shilamkar */ 743fc750a3bSchangfengnan commit_time = be64_to_cpu( 744fc750a3bSchangfengnan ((struct commit_header *)bh->b_data)->h_commit_sec); 745fc750a3bSchangfengnan /* 746fc750a3bSchangfengnan * If need_check_commit_time is set, it means we are in 747fc750a3bSchangfengnan * PASS_SCAN and csum verify failed before. If 748fc750a3bSchangfengnan * commit_time is increasing, it's the same journal, 749fc750a3bSchangfengnan * otherwise it is stale journal block, just end this 750fc750a3bSchangfengnan * recovery. 751fc750a3bSchangfengnan */ 752fc750a3bSchangfengnan if (need_check_commit_time) { 753fc750a3bSchangfengnan if (commit_time >= last_trans_commit_time) { 754fc750a3bSchangfengnan pr_err("JBD2: Invalid checksum found in transaction %u\n", 755fc750a3bSchangfengnan next_commit_ID); 756fc750a3bSchangfengnan err = -EFSBADCRC; 757fc750a3bSchangfengnan brelse(bh); 758fc750a3bSchangfengnan goto failed; 759fc750a3bSchangfengnan } 760fc750a3bSchangfengnan ignore_crc_mismatch: 761fc750a3bSchangfengnan /* 762fc750a3bSchangfengnan * It likely does not belong to same journal, 763fc750a3bSchangfengnan * just end this recovery with success. 764fc750a3bSchangfengnan */ 765cb3b3bf2SJan Kara jbd2_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n", 766fc750a3bSchangfengnan next_commit_ID); 767fc750a3bSchangfengnan brelse(bh); 768fc750a3bSchangfengnan goto done; 769fc750a3bSchangfengnan } 770818d276cSGirish Shilamkar 771fc750a3bSchangfengnan /* 772fc750a3bSchangfengnan * Found an expected commit block: if checksums 773fc750a3bSchangfengnan * are present, verify them in PASS_SCAN; else not 774818d276cSGirish Shilamkar * much to do other than move on to the next sequence 775fc750a3bSchangfengnan * number. 776fc750a3bSchangfengnan */ 777818d276cSGirish Shilamkar if (pass == PASS_SCAN && 77856316a0dSDarrick J. Wong jbd2_has_feature_checksum(journal)) { 779818d276cSGirish Shilamkar struct commit_header *cbh = 780818d276cSGirish Shilamkar (struct commit_header *)bh->b_data; 781818d276cSGirish Shilamkar unsigned found_chksum = 782818d276cSGirish Shilamkar be32_to_cpu(cbh->h_chksum[0]); 783818d276cSGirish Shilamkar 784818d276cSGirish Shilamkar if (info->end_transaction) { 785624080edSTheodore Ts'o journal->j_failed_commit = 786624080edSTheodore Ts'o info->end_transaction; 787818d276cSGirish Shilamkar brelse(bh); 788818d276cSGirish Shilamkar break; 789818d276cSGirish Shilamkar } 790818d276cSGirish Shilamkar 79100a3fff0SShijie Luo /* Neither checksum match nor unused? */ 79200a3fff0SShijie Luo if (!((crc32_sum == found_chksum && 79300a3fff0SShijie Luo cbh->h_chksum_type == 79400a3fff0SShijie Luo JBD2_CRC32_CHKSUM && 795818d276cSGirish Shilamkar cbh->h_chksum_size == 79600a3fff0SShijie Luo JBD2_CRC32_CHKSUM_SIZE) || 79700a3fff0SShijie Luo (cbh->h_chksum_type == 0 && 798818d276cSGirish Shilamkar cbh->h_chksum_size == 0 && 79900a3fff0SShijie Luo found_chksum == 0))) 80000a3fff0SShijie Luo goto chksum_error; 801818d276cSGirish Shilamkar 802818d276cSGirish Shilamkar crc32_sum = ~0; 803818d276cSGirish Shilamkar } 8041f56c589SDarrick J. Wong if (pass == PASS_SCAN && 8051f56c589SDarrick J. Wong !jbd2_commit_block_csum_verify(journal, 8061f56c589SDarrick J. Wong bh->b_data)) { 80700a3fff0SShijie Luo chksum_error: 808fc750a3bSchangfengnan if (commit_time < last_trans_commit_time) 809fc750a3bSchangfengnan goto ignore_crc_mismatch; 8101f56c589SDarrick J. Wong info->end_transaction = next_commit_ID; 8111f56c589SDarrick J. Wong 81256316a0dSDarrick J. Wong if (!jbd2_has_feature_async_commit(journal)) { 8131f56c589SDarrick J. Wong journal->j_failed_commit = 8141f56c589SDarrick J. Wong next_commit_ID; 8151f56c589SDarrick J. Wong brelse(bh); 8161f56c589SDarrick J. Wong break; 8171f56c589SDarrick J. Wong } 8181f56c589SDarrick J. Wong } 819fc750a3bSchangfengnan if (pass == PASS_SCAN) 820fc750a3bSchangfengnan last_trans_commit_time = commit_time; 821470decc6SDave Kleikamp brelse(bh); 822470decc6SDave Kleikamp next_commit_ID++; 823470decc6SDave Kleikamp continue; 824470decc6SDave Kleikamp 825f7f4bccbSMingming Cao case JBD2_REVOKE_BLOCK: 826fc750a3bSchangfengnan /* 827fc750a3bSchangfengnan * Check revoke block crc in pass_scan, if csum verify 828fc750a3bSchangfengnan * failed, check commit block time later. 829fc750a3bSchangfengnan */ 830fc750a3bSchangfengnan if (pass == PASS_SCAN && 831fc750a3bSchangfengnan !jbd2_descriptor_block_csum_verify(journal, 832fc750a3bSchangfengnan bh->b_data)) { 833cb3b3bf2SJan Kara jbd2_debug(1, "JBD2: invalid revoke block found in %lu\n", 834fc750a3bSchangfengnan next_log_block); 835fc750a3bSchangfengnan need_check_commit_time = true; 836fc750a3bSchangfengnan } 837470decc6SDave Kleikamp /* If we aren't in the REVOKE pass, then we can 838470decc6SDave Kleikamp * just skip over this block. */ 839470decc6SDave Kleikamp if (pass != PASS_REVOKE) { 840470decc6SDave Kleikamp brelse(bh); 841470decc6SDave Kleikamp continue; 842470decc6SDave Kleikamp } 843470decc6SDave Kleikamp 844470decc6SDave Kleikamp err = scan_revoke_records(journal, bh, 845470decc6SDave Kleikamp next_commit_ID, info); 846470decc6SDave Kleikamp brelse(bh); 847470decc6SDave Kleikamp if (err) 848470decc6SDave Kleikamp goto failed; 849470decc6SDave Kleikamp continue; 850470decc6SDave Kleikamp 851470decc6SDave Kleikamp default: 852cb3b3bf2SJan Kara jbd2_debug(3, "Unrecognised magic %d, end of scan.\n", 853470decc6SDave Kleikamp blocktype); 854470decc6SDave Kleikamp brelse(bh); 855470decc6SDave Kleikamp goto done; 856470decc6SDave Kleikamp } 857470decc6SDave Kleikamp } 858470decc6SDave Kleikamp 859470decc6SDave Kleikamp done: 860470decc6SDave Kleikamp /* 861470decc6SDave Kleikamp * We broke out of the log scan loop: either we came to the 862470decc6SDave Kleikamp * known end of the log or we found an unexpected block in the 863470decc6SDave Kleikamp * log. If the latter happened, then we know that the "current" 864470decc6SDave Kleikamp * transaction marks the end of the valid log. 865470decc6SDave Kleikamp */ 866470decc6SDave Kleikamp 867818d276cSGirish Shilamkar if (pass == PASS_SCAN) { 868818d276cSGirish Shilamkar if (!info->end_transaction) 869470decc6SDave Kleikamp info->end_transaction = next_commit_ID; 870818d276cSGirish Shilamkar } else { 871470decc6SDave Kleikamp /* It's really bad news if different passes end up at 872470decc6SDave Kleikamp * different places (but possible due to IO errors). */ 873470decc6SDave Kleikamp if (info->end_transaction != next_commit_ID) { 874f2a44523SEryu Guan printk(KERN_ERR "JBD2: recovery pass %d ended at " 875470decc6SDave Kleikamp "transaction %u, expected %u\n", 876470decc6SDave Kleikamp pass, next_commit_ID, info->end_transaction); 877470decc6SDave Kleikamp if (!success) 878470decc6SDave Kleikamp success = -EIO; 879470decc6SDave Kleikamp } 880470decc6SDave Kleikamp } 8815b849b5fSHarshad Shirwadkar 8825b849b5fSHarshad Shirwadkar if (jbd2_has_feature_fast_commit(journal) && pass != PASS_REVOKE) { 8835b849b5fSHarshad Shirwadkar err = fc_do_one_pass(journal, info, pass); 8845b849b5fSHarshad Shirwadkar if (err) 8855b849b5fSHarshad Shirwadkar success = err; 8865b849b5fSHarshad Shirwadkar } 8875b849b5fSHarshad Shirwadkar 888022eaa75SDarrick J. Wong if (block_error && success == 0) 889022eaa75SDarrick J. Wong success = -EIO; 890470decc6SDave Kleikamp return success; 891470decc6SDave Kleikamp 892470decc6SDave Kleikamp failed: 893470decc6SDave Kleikamp return err; 894470decc6SDave Kleikamp } 895470decc6SDave Kleikamp 896470decc6SDave Kleikamp /* Scan a revoke record, marking all blocks mentioned as revoked. */ 897470decc6SDave Kleikamp 898470decc6SDave Kleikamp static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, 899470decc6SDave Kleikamp tid_t sequence, struct recovery_info *info) 900470decc6SDave Kleikamp { 901f7f4bccbSMingming Cao jbd2_journal_revoke_header_t *header; 902470decc6SDave Kleikamp int offset, max; 9034009cc7aSTheodore Ts'o unsigned csum_size = 0; 904e531d0bcSDarrick J. Wong __u32 rcount; 905b517bea1SZach Brown int record_len = 4; 906470decc6SDave Kleikamp 907f7f4bccbSMingming Cao header = (jbd2_journal_revoke_header_t *) bh->b_data; 908f7f4bccbSMingming Cao offset = sizeof(jbd2_journal_revoke_header_t); 909e531d0bcSDarrick J. Wong rcount = be32_to_cpu(header->r_count); 910470decc6SDave Kleikamp 911e531d0bcSDarrick J. Wong if (jbd2_journal_has_csum_v2or3(journal)) 9121101cd4dSJan Kara csum_size = sizeof(struct jbd2_journal_block_tail); 913e531d0bcSDarrick J. Wong if (rcount > journal->j_blocksize - csum_size) 914e531d0bcSDarrick J. Wong return -EINVAL; 915e531d0bcSDarrick J. Wong max = rcount; 916e531d0bcSDarrick J. Wong 91756316a0dSDarrick J. Wong if (jbd2_has_feature_64bit(journal)) 918b517bea1SZach Brown record_len = 8; 919b517bea1SZach Brown 920b517bea1SZach Brown while (offset + record_len <= max) { 92118eba7aaSMingming Cao unsigned long long blocknr; 922470decc6SDave Kleikamp int err; 923470decc6SDave Kleikamp 924b517bea1SZach Brown if (record_len == 4) 925470decc6SDave Kleikamp blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); 926b517bea1SZach Brown else 927b517bea1SZach Brown blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset))); 928b517bea1SZach Brown offset += record_len; 929f7f4bccbSMingming Cao err = jbd2_journal_set_revoke(journal, blocknr, sequence); 930470decc6SDave Kleikamp if (err) 931470decc6SDave Kleikamp return err; 932470decc6SDave Kleikamp ++info->nr_revokes; 933470decc6SDave Kleikamp } 934470decc6SDave Kleikamp return 0; 935470decc6SDave Kleikamp } 936