| .. | .. |
|---|
| 35 | 35 | int nr_revoke_hits; |
|---|
| 36 | 36 | }; |
|---|
| 37 | 37 | |
|---|
| 38 | | -enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY}; |
|---|
| 39 | 38 | static int do_one_pass(journal_t *journal, |
|---|
| 40 | 39 | struct recovery_info *info, enum passtype pass); |
|---|
| 41 | 40 | static int scan_revoke_records(journal_t *, struct buffer_head *, |
|---|
| .. | .. |
|---|
| 75 | 74 | |
|---|
| 76 | 75 | /* Do up to 128K of readahead */ |
|---|
| 77 | 76 | max = start + (128 * 1024 / journal->j_blocksize); |
|---|
| 78 | | - if (max > journal->j_maxlen) |
|---|
| 79 | | - max = journal->j_maxlen; |
|---|
| 77 | + if (max > journal->j_total_len) |
|---|
| 78 | + max = journal->j_total_len; |
|---|
| 80 | 79 | |
|---|
| 81 | 80 | /* Do the readahead itself. We'll submit MAXBUF buffer_heads at |
|---|
| 82 | 81 | * a time to the block device IO layer. */ |
|---|
| .. | .. |
|---|
| 135 | 134 | |
|---|
| 136 | 135 | *bhp = NULL; |
|---|
| 137 | 136 | |
|---|
| 138 | | - if (offset >= journal->j_maxlen) { |
|---|
| 137 | + if (offset >= journal->j_total_len) { |
|---|
| 139 | 138 | printk(KERN_ERR "JBD2: corrupted journal superblock\n"); |
|---|
| 140 | 139 | return -EFSCORRUPTED; |
|---|
| 141 | 140 | } |
|---|
| .. | .. |
|---|
| 225 | 224 | /* Make sure we wrap around the log correctly! */ |
|---|
| 226 | 225 | #define wrap(journal, var) \ |
|---|
| 227 | 226 | do { \ |
|---|
| 228 | | - if (var >= (journal)->j_last) \ |
|---|
| 229 | | - var -= ((journal)->j_last - (journal)->j_first); \ |
|---|
| 227 | + unsigned long _wrap_last = \ |
|---|
| 228 | + jbd2_has_feature_fast_commit(journal) ? \ |
|---|
| 229 | + (journal)->j_fc_last : (journal)->j_last; \ |
|---|
| 230 | + \ |
|---|
| 231 | + if (var >= _wrap_last) \ |
|---|
| 232 | + var -= (_wrap_last - (journal)->j_first); \ |
|---|
| 230 | 233 | } while (0) |
|---|
| 234 | + |
|---|
| 235 | +static int fc_do_one_pass(journal_t *journal, |
|---|
| 236 | + struct recovery_info *info, enum passtype pass) |
|---|
| 237 | +{ |
|---|
| 238 | + unsigned int expected_commit_id = info->end_transaction; |
|---|
| 239 | + unsigned long next_fc_block; |
|---|
| 240 | + struct buffer_head *bh; |
|---|
| 241 | + int err = 0; |
|---|
| 242 | + |
|---|
| 243 | + next_fc_block = journal->j_fc_first; |
|---|
| 244 | + if (!journal->j_fc_replay_callback) |
|---|
| 245 | + return 0; |
|---|
| 246 | + |
|---|
| 247 | + while (next_fc_block <= journal->j_fc_last) { |
|---|
| 248 | + jbd_debug(3, "Fast commit replay: next block %ld\n", |
|---|
| 249 | + next_fc_block); |
|---|
| 250 | + err = jread(&bh, journal, next_fc_block); |
|---|
| 251 | + if (err) { |
|---|
| 252 | + jbd_debug(3, "Fast commit replay: read error\n"); |
|---|
| 253 | + break; |
|---|
| 254 | + } |
|---|
| 255 | + |
|---|
| 256 | + err = journal->j_fc_replay_callback(journal, bh, pass, |
|---|
| 257 | + next_fc_block - journal->j_fc_first, |
|---|
| 258 | + expected_commit_id); |
|---|
| 259 | + brelse(bh); |
|---|
| 260 | + next_fc_block++; |
|---|
| 261 | + if (err < 0 || err == JBD2_FC_REPLAY_STOP) |
|---|
| 262 | + break; |
|---|
| 263 | + err = 0; |
|---|
| 264 | + } |
|---|
| 265 | + |
|---|
| 266 | + if (err) |
|---|
| 267 | + jbd_debug(3, "Fast commit replay failed, err = %d\n", err); |
|---|
| 268 | + |
|---|
| 269 | + return err; |
|---|
| 270 | +} |
|---|
| 231 | 271 | |
|---|
| 232 | 272 | /** |
|---|
| 233 | 273 | * jbd2_journal_recover - recovers a on-disk journal |
|---|
| .. | .. |
|---|
| 286 | 326 | err = err2; |
|---|
| 287 | 327 | /* Make sure all replayed data is on permanent storage */ |
|---|
| 288 | 328 | if (journal->j_flags & JBD2_BARRIER) { |
|---|
| 289 | | - err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); |
|---|
| 329 | + err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL); |
|---|
| 290 | 330 | if (!err) |
|---|
| 291 | 331 | err = err2; |
|---|
| 292 | 332 | } |
|---|
| .. | .. |
|---|
| 428 | 468 | __u32 crc32_sum = ~0; /* Transactional Checksums */ |
|---|
| 429 | 469 | int descr_csum_size = 0; |
|---|
| 430 | 470 | int block_error = 0; |
|---|
| 471 | + bool need_check_commit_time = false; |
|---|
| 472 | + __u64 last_trans_commit_time = 0, commit_time; |
|---|
| 431 | 473 | |
|---|
| 432 | 474 | /* |
|---|
| 433 | 475 | * First thing is to establish what we expect to find in the log |
|---|
| .. | .. |
|---|
| 470 | 512 | break; |
|---|
| 471 | 513 | |
|---|
| 472 | 514 | jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", |
|---|
| 473 | | - next_commit_ID, next_log_block, journal->j_last); |
|---|
| 515 | + next_commit_ID, next_log_block, |
|---|
| 516 | + jbd2_has_feature_fast_commit(journal) ? |
|---|
| 517 | + journal->j_fc_last : journal->j_last); |
|---|
| 474 | 518 | |
|---|
| 475 | 519 | /* Skip over each chunk of the transaction looking |
|---|
| 476 | 520 | * either the next descriptor block or the final commit |
|---|
| .. | .. |
|---|
| 520 | 564 | if (descr_csum_size > 0 && |
|---|
| 521 | 565 | !jbd2_descriptor_block_csum_verify(journal, |
|---|
| 522 | 566 | bh->b_data)) { |
|---|
| 523 | | - printk(KERN_ERR "JBD2: Invalid checksum " |
|---|
| 524 | | - "recovering block %lu in log\n", |
|---|
| 525 | | - next_log_block); |
|---|
| 526 | | - err = -EFSBADCRC; |
|---|
| 527 | | - brelse(bh); |
|---|
| 528 | | - goto failed; |
|---|
| 567 | + /* |
|---|
| 568 | + * PASS_SCAN can see stale blocks due to lazy |
|---|
| 569 | + * journal init. Don't error out on those yet. |
|---|
| 570 | + */ |
|---|
| 571 | + if (pass != PASS_SCAN) { |
|---|
| 572 | + pr_err("JBD2: Invalid checksum recovering block %lu in log\n", |
|---|
| 573 | + next_log_block); |
|---|
| 574 | + err = -EFSBADCRC; |
|---|
| 575 | + brelse(bh); |
|---|
| 576 | + goto failed; |
|---|
| 577 | + } |
|---|
| 578 | + need_check_commit_time = true; |
|---|
| 579 | + jbd_debug(1, |
|---|
| 580 | + "invalid descriptor block found in %lu\n", |
|---|
| 581 | + next_log_block); |
|---|
| 529 | 582 | } |
|---|
| 530 | 583 | |
|---|
| 531 | 584 | /* If it is a valid descriptor block, replay it |
|---|
| .. | .. |
|---|
| 535 | 588 | if (pass != PASS_REPLAY) { |
|---|
| 536 | 589 | if (pass == PASS_SCAN && |
|---|
| 537 | 590 | jbd2_has_feature_checksum(journal) && |
|---|
| 591 | + !need_check_commit_time && |
|---|
| 538 | 592 | !info->end_transaction) { |
|---|
| 539 | 593 | if (calc_chksums(journal, bh, |
|---|
| 540 | 594 | &next_log_block, |
|---|
| .. | .. |
|---|
| 683 | 737 | * mentioned conditions. Hence assume |
|---|
| 684 | 738 | * "Interrupted Commit".) |
|---|
| 685 | 739 | */ |
|---|
| 740 | + commit_time = be64_to_cpu( |
|---|
| 741 | + ((struct commit_header *)bh->b_data)->h_commit_sec); |
|---|
| 742 | + /* |
|---|
| 743 | + * If need_check_commit_time is set, it means we are in |
|---|
| 744 | + * PASS_SCAN and csum verify failed before. If |
|---|
| 745 | + * commit_time is increasing, it's the same journal, |
|---|
| 746 | + * otherwise it is stale journal block, just end this |
|---|
| 747 | + * recovery. |
|---|
| 748 | + */ |
|---|
| 749 | + if (need_check_commit_time) { |
|---|
| 750 | + if (commit_time >= last_trans_commit_time) { |
|---|
| 751 | + pr_err("JBD2: Invalid checksum found in transaction %u\n", |
|---|
| 752 | + next_commit_ID); |
|---|
| 753 | + err = -EFSBADCRC; |
|---|
| 754 | + brelse(bh); |
|---|
| 755 | + goto failed; |
|---|
| 756 | + } |
|---|
| 757 | + ignore_crc_mismatch: |
|---|
| 758 | + /* |
|---|
| 759 | + * It likely does not belong to same journal, |
|---|
| 760 | + * just end this recovery with success. |
|---|
| 761 | + */ |
|---|
| 762 | + jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n", |
|---|
| 763 | + next_commit_ID); |
|---|
| 764 | + err = 0; |
|---|
| 765 | + brelse(bh); |
|---|
| 766 | + goto done; |
|---|
| 767 | + } |
|---|
| 686 | 768 | |
|---|
| 687 | | - /* Found an expected commit block: if checksums |
|---|
| 688 | | - * are present verify them in PASS_SCAN; else not |
|---|
| 769 | + /* |
|---|
| 770 | + * Found an expected commit block: if checksums |
|---|
| 771 | + * are present, verify them in PASS_SCAN; else not |
|---|
| 689 | 772 | * much to do other than move on to the next sequence |
|---|
| 690 | | - * number. */ |
|---|
| 773 | + * number. |
|---|
| 774 | + */ |
|---|
| 691 | 775 | if (pass == PASS_SCAN && |
|---|
| 692 | 776 | jbd2_has_feature_checksum(journal)) { |
|---|
| 693 | | - int chksum_err, chksum_seen; |
|---|
| 694 | 777 | struct commit_header *cbh = |
|---|
| 695 | 778 | (struct commit_header *)bh->b_data; |
|---|
| 696 | 779 | unsigned found_chksum = |
|---|
| 697 | 780 | be32_to_cpu(cbh->h_chksum[0]); |
|---|
| 698 | | - |
|---|
| 699 | | - chksum_err = chksum_seen = 0; |
|---|
| 700 | 781 | |
|---|
| 701 | 782 | if (info->end_transaction) { |
|---|
| 702 | 783 | journal->j_failed_commit = |
|---|
| .. | .. |
|---|
| 705 | 786 | break; |
|---|
| 706 | 787 | } |
|---|
| 707 | 788 | |
|---|
| 708 | | - if (crc32_sum == found_chksum && |
|---|
| 709 | | - cbh->h_chksum_type == JBD2_CRC32_CHKSUM && |
|---|
| 710 | | - cbh->h_chksum_size == |
|---|
| 711 | | - JBD2_CRC32_CHKSUM_SIZE) |
|---|
| 712 | | - chksum_seen = 1; |
|---|
| 713 | | - else if (!(cbh->h_chksum_type == 0 && |
|---|
| 714 | | - cbh->h_chksum_size == 0 && |
|---|
| 715 | | - found_chksum == 0 && |
|---|
| 716 | | - !chksum_seen)) |
|---|
| 717 | | - /* |
|---|
| 718 | | - * If fs is mounted using an old kernel and then |
|---|
| 719 | | - * kernel with journal_chksum is used then we |
|---|
| 720 | | - * get a situation where the journal flag has |
|---|
| 721 | | - * checksum flag set but checksums are not |
|---|
| 722 | | - * present i.e chksum = 0, in the individual |
|---|
| 723 | | - * commit blocks. |
|---|
| 724 | | - * Hence to avoid checksum failures, in this |
|---|
| 725 | | - * situation, this extra check is added. |
|---|
| 726 | | - */ |
|---|
| 727 | | - chksum_err = 1; |
|---|
| 789 | + /* Neither checksum match nor unused? */ |
|---|
| 790 | + if (!((crc32_sum == found_chksum && |
|---|
| 791 | + cbh->h_chksum_type == |
|---|
| 792 | + JBD2_CRC32_CHKSUM && |
|---|
| 793 | + cbh->h_chksum_size == |
|---|
| 794 | + JBD2_CRC32_CHKSUM_SIZE) || |
|---|
| 795 | + (cbh->h_chksum_type == 0 && |
|---|
| 796 | + cbh->h_chksum_size == 0 && |
|---|
| 797 | + found_chksum == 0))) |
|---|
| 798 | + goto chksum_error; |
|---|
| 728 | 799 | |
|---|
| 729 | | - if (chksum_err) { |
|---|
| 730 | | - info->end_transaction = next_commit_ID; |
|---|
| 731 | | - |
|---|
| 732 | | - if (!jbd2_has_feature_async_commit(journal)) { |
|---|
| 733 | | - journal->j_failed_commit = |
|---|
| 734 | | - next_commit_ID; |
|---|
| 735 | | - brelse(bh); |
|---|
| 736 | | - break; |
|---|
| 737 | | - } |
|---|
| 738 | | - } |
|---|
| 739 | 800 | crc32_sum = ~0; |
|---|
| 740 | 801 | } |
|---|
| 741 | 802 | if (pass == PASS_SCAN && |
|---|
| 742 | 803 | !jbd2_commit_block_csum_verify(journal, |
|---|
| 743 | 804 | bh->b_data)) { |
|---|
| 805 | + chksum_error: |
|---|
| 806 | + if (commit_time < last_trans_commit_time) |
|---|
| 807 | + goto ignore_crc_mismatch; |
|---|
| 744 | 808 | info->end_transaction = next_commit_ID; |
|---|
| 745 | 809 | |
|---|
| 746 | 810 | if (!jbd2_has_feature_async_commit(journal)) { |
|---|
| .. | .. |
|---|
| 750 | 814 | break; |
|---|
| 751 | 815 | } |
|---|
| 752 | 816 | } |
|---|
| 817 | + if (pass == PASS_SCAN) |
|---|
| 818 | + last_trans_commit_time = commit_time; |
|---|
| 753 | 819 | brelse(bh); |
|---|
| 754 | 820 | next_commit_ID++; |
|---|
| 755 | 821 | continue; |
|---|
| 756 | 822 | |
|---|
| 757 | 823 | case JBD2_REVOKE_BLOCK: |
|---|
| 824 | + /* |
|---|
| 825 | + * Check revoke block crc in pass_scan, if csum verify |
|---|
| 826 | + * failed, check commit block time later. |
|---|
| 827 | + */ |
|---|
| 828 | + if (pass == PASS_SCAN && |
|---|
| 829 | + !jbd2_descriptor_block_csum_verify(journal, |
|---|
| 830 | + bh->b_data)) { |
|---|
| 831 | + jbd_debug(1, "JBD2: invalid revoke block found in %lu\n", |
|---|
| 832 | + next_log_block); |
|---|
| 833 | + need_check_commit_time = true; |
|---|
| 834 | + } |
|---|
| 758 | 835 | /* If we aren't in the REVOKE pass, then we can |
|---|
| 759 | 836 | * just skip over this block. */ |
|---|
| 760 | 837 | if (pass != PASS_REVOKE) { |
|---|
| .. | .. |
|---|
| 799 | 876 | success = -EIO; |
|---|
| 800 | 877 | } |
|---|
| 801 | 878 | } |
|---|
| 879 | + |
|---|
| 880 | + if (jbd2_has_feature_fast_commit(journal) && pass != PASS_REVOKE) { |
|---|
| 881 | + err = fc_do_one_pass(journal, info, pass); |
|---|
| 882 | + if (err) |
|---|
| 883 | + success = err; |
|---|
| 884 | + } |
|---|
| 885 | + |
|---|
| 802 | 886 | if (block_error && success == 0) |
|---|
| 803 | 887 | success = -EIO; |
|---|
| 804 | 888 | return success; |
|---|
| .. | .. |
|---|
| 821 | 905 | header = (jbd2_journal_revoke_header_t *) bh->b_data; |
|---|
| 822 | 906 | offset = sizeof(jbd2_journal_revoke_header_t); |
|---|
| 823 | 907 | rcount = be32_to_cpu(header->r_count); |
|---|
| 824 | | - |
|---|
| 825 | | - if (!jbd2_descriptor_block_csum_verify(journal, header)) |
|---|
| 826 | | - return -EFSBADCRC; |
|---|
| 827 | 908 | |
|---|
| 828 | 909 | if (jbd2_journal_has_csum_v2or3(journal)) |
|---|
| 829 | 910 | csum_size = sizeof(struct jbd2_journal_block_tail); |
|---|