jbd2: avoid transaction reuse after reformatting
PATCH v3 1/1 jbd2: avoid transaction reuse after reformatting
From: changfengnan <[email protected]>
When ext4 is formatted with lazy_journal_init=1 and transactions from the previous filesystem are still on disk, it is possible that they are considered during a recovery after a crash. Because the checksum seed has changed, the CRC check will fail, and the journal recovery fails with checksum error although the journal is otherwise perfectly valid. Fix the problem by checking commit block time stamps to determine whether the data in the journal block is just stale or whether it is indeed corrupt.
--- fs/jbd2/recovery.c | 77 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 12 deletions(-)
Ted, Fengnan,
I've fixed up some mangled characters, whitespace, and coding style of Fengnan's v2 submission. I also removed the additional check that commit timestamps never go backwards - that could cause potential trouble e.g. when system time gets moved backwards. Quick smoke test looks fine but Fengnan please verify this patch works for you as well.
Honza
fs/jbd2/recovery.c +65 -12
@@ -428,6 +428,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; +__be64 last_trans_commit_time =0 ;/* * First thing is to establish what we expect to find in the log
@@ -520,12 +522,22 @@ static int do_one_pass(journal_t *journal,if (descr_csum_size >0 && !jbd2_descriptor_block_csum_verify (journal, bh->b_data)) { -printk (KERN_ERR "JBD2: Invalid checksum " -"recovering block %lu in log\n" , - next_log_block); - err = -EFSBADCRC ; -brelse (bh); - goto failed; +/* +* 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
@@ -535,6 +547,7 @@ static int do_one_pass(journal_t *journal,if (pass !=PASS_REPLAY ) {if (pass ==PASS_SCAN &&jbd2_has_feature_checksum (journal) && + !need_check_commit_time && !info->end_transaction) { if (calc_chksums(journal, bh, &next_log_block,
@@ -684,16 +697,20 @@ static int do_one_pass(journal_t *journal,* "Interrupted Commit".) */ -/* 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 &&jbd2_has_feature_checksum (journal)) {struct commit_header *cbh = (struct commit_header *)bh->b_data;unsigned found_chksum =be32_to_cpu (cbh->h_chksum[0 ]); +__be64 commit_time = +be64_to_cpu (cbh->h_commit_sec);if (info->end_transaction) { journal->j_failed_commit =
@@ -702,6 +719,33 @@ static int do_one_pass(journal_t *journal,break ; } +/* +* If need_check_commit_time is set, it means +* csum verify failed before, if commit_time is +* increasing, it's 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; + } +/* +* 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); + err =0 ; +brelse (bh); + goto done; + } +/* Neither checksum match nor unused? */ if (!((crc32_sum == found_chksum && cbh->h_chksum_type ==
@@ -714,6 +758,7 @@ static int do_one_pass(journal_t *journal, goto chksum_error; crc32_sum = ~0 ; + last_trans_commit_time = commit_time; }if (pass ==PASS_SCAN && !jbd2_commit_block_csum_verify(journal,
@@ -733,6 +778,17 @@ static int do_one_pass(journal_t *journal,continue ;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 ) {
@@ -800,9 +856,6 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, offset =sizeof (jbd2_journal_revoke_header_t); rcount =be32_to_cpu (header->r_count); -if (!jbd2_descriptor_block_csum_verify (journal, header)) -return -EFSBADCRC ; -if (jbd2_journal_has_csum_v2or3 (journal)) csum_size =sizeof (struct jbd2_journal_block_tail );if (rcount > journal->j_blocksize - csum_size)
Signature · 1 line
2.16.4
kernel test robot
build botThank you for the patch! Perhaps something to improve:
Hi Jan,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on ext4/dev]
[also build test WARNING on linus/master v5.9-rc8 next-20201002] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Jan-Kara/jbd2-avoid-transaction-reuse-after-reformatting/20201006-183337 base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev config: i386-randconfig-s001-20201005 (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.2-201-g24bdaac6-dirty # https://github.com/0day-ci/linux/commit/ca606dc0beaec78e8b2b6ec2f112b2192534d9e2 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Jan-Kara/jbd2-avoid-transaction-reuse-after-reformatting/20201006-183337 git checkout ca606dc0beaec78e8b2b6ec2f112b2192534d9e2 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386
If you fix the issue, kindly add following tag as appropriate
echo
echo "sparse warnings: (new ones prefixed by >>)" echo
>> fs/jbd2/recovery.c:713:41: sparse: sparse: incorrect type in initializer (different base types) @@ expected restricted __be64 [usertype] commit_time @@ got unsigned long long @@ fs/jbd2/recovery.c:713:41: sparse: expected restricted __be64 [usertype] commit_time >> fs/jbd2/recovery.c:713:41: sparse: got unsigned long long
fs/jbd2/recovery.c:730:45: sparse: sparse: restricted __be64 degrades to integer fs/jbd2/recovery.c:730:60: sparse: sparse: restricted __be64 degrades to integer
vim +713 fs/jbd2/recovery.c
415
416 static int do_one_pass(journal_t *journal,
417 struct recovery_info *info, enum passtype pass)
418 {
419 unsigned int first_commit_ID, next_commit_ID;
420 unsigned long next_log_block;
421 int err, success = 0;
422 journal_superblock_t * sb;
423 journal_header_t * tmp;
424 struct buffer_head * bh;
425 unsigned int sequence;
426 int blocktype;
427 int tag_bytes = journal_tag_bytes(journal);
428 __u32 crc32_sum = ~0; /* Transactional Checksums */
429 int descr_csum_size = 0;
430 int block_error = 0;
431 bool need_check_commit_time = false;
432 __be64 last_trans_commit_time = 0;
433
434 /*
435 * First thing is to establish what we expect to find in the log
436 * (in terms of transaction IDs), and where (in terms of log
437 * block offsets): query the superblock.
438 */
439
440 sb = journal->j_superblock;
441 next_commit_ID = be32_to_cpu(sb->s_sequence);
442 next_log_block = be32_to_cpu(sb->s_start);
443
444 first_commit_ID = next_commit_ID;
445 if (pass == PASS_SCAN)
446 info->start_transaction = first_commit_ID;
447
448 jbd_debug(1, "Starting recovery pass %d\n", pass);
449
450 /*
451 * Now we walk through the log, transaction by transaction,
452 * making sure that each transaction has a commit block in the
453 * expected place. Each complete transaction gets replayed back
454 * into the main filesystem.
455 */
456
457 while (1) {
458 int flags;
459 char * tagp;
460 journal_block_tag_t * tag;
461 struct buffer_head * obh;
462 struct buffer_head * nbh;
463
464 cond_resched();
465
466 /* If we already know where to stop the log traversal,
467 * check right now that we haven't gone past the end of
468 * the log. */
469
470 if (pass != PASS_SCAN)
471 if (tid_geq(next_commit_ID, info->end_transaction))
472 break;
473
474 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
475 next_commit_ID, next_log_block, journal->j_last);
476
477 /* Skip over each chunk of the transaction looking
478 * either the next descriptor block or the final commit
479 * record. */
480
481 jbd_debug(3, "JBD2: checking block %ld\n", next_log_block);
482 err = jread(&bh, journal, next_log_block);
483 if (err)
484 goto failed;
485
486 next_log_block++;
487 wrap(journal, next_log_block);
488
489 /* What kind of buffer is it?
490 *
491 * If it is a descriptor block, check that it has the
492 * expected sequence number. Otherwise, we're all done
493 * here. */
494
495 tmp = (journal_header_t *)bh->b_data;
496
497 if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {
498 brelse(bh);
499 break;
500 }
501
502 blocktype = be32_to_cpu(tmp->h_blocktype);
503 sequence = be32_to_cpu(tmp->h_sequence);
504 jbd_debug(3, "Found magic %d, sequence %d\n",
505 blocktype, sequence);
506
507 if (sequence != next_commit_ID) {
508 brelse(bh);
509 break;
510 }
511
512 /* OK, we have a valid descriptor block which matches
513 * all of the sequence number checks. What are we going
514 * to do with it? That depends on the pass... */
515
516 switch(blocktype) {
517 case JBD2_DESCRIPTOR_BLOCK:
518 /* Verify checksum first */
519 if (jbd2_journal_has_csum_v2or3(journal))
520 descr_csum_size =
521 sizeof(struct jbd2_journal_block_tail);
522 if (descr_csum_size > 0 &&
523 !jbd2_descriptor_block_csum_verify(journal,
524 bh->b_data)) {
525 /*
526 * PASS_SCAN can see stale blocks due to lazy
527 * journal init. Don't error out on those yet.
528 */
529 if (pass != PASS_SCAN) {
530 pr_err("JBD2: Invalid checksum "
531 "recovering block %lu in log\n",
532 next_log_block);
533 err = -EFSBADCRC;
534 brelse(bh);
535 goto failed;
536 }
537 need_check_commit_time = true;
538 jbd_debug(1,
539 "invalid descriptor block found in %lu\n",
540 next_log_block);
541 }
542
543 /* If it is a valid descriptor block, replay it
544 * in pass REPLAY; if journal_checksums enabled, then
545 * calculate checksums in PASS_SCAN, otherwise,
546 * just skip over the blocks it describes. */
547 if (pass != PASS_REPLAY) {
548 if (pass == PASS_SCAN &&
549 jbd2_has_feature_checksum(journal) &&
550 !need_check_commit_time &&
551 !info->end_transaction) {
552 if (calc_chksums(journal, bh,
553 &next_log_block,
554 &crc32_sum)) {
555 put_bh(bh);
556 break;
557 }
558 put_bh(bh);
559 continue;
560 }
561 next_log_block += count_tags(journal, bh);
562 wrap(journal, next_log_block);
563 put_bh(bh);
564 continue;
565 }
566
567 /* A descriptor block: we can now write all of
568 * the data blocks. Yay, useful work is finally
569 * getting done here! */
570
571 tagp = &bh->b_data[sizeof(journal_header_t)];
572 while ((tagp - bh->b_data + tag_bytes)
573 <= journal->j_blocksize - descr_csum_size) {
574 unsigned long io_block;
575
576 tag = (journal_block_tag_t *) tagp;
577 flags = be16_to_cpu(tag->t_flags);
578
579 io_block = next_log_block++;
580 wrap(journal, next_log_block);
581 err = jread(&obh, journal, io_block);
582 if (err) {
583 /* Recover what we can, but
584 * report failure at the end. */
585 success = err;
586 printk(KERN_ERR
587 "JBD2: IO error %d recovering "
588 "block %ld in log\n",
589 err, io_block);
590 } else {
591 unsigned long long blocknr;
592
593 J_ASSERT(obh != NULL);
594 blocknr = read_tag_block(journal,
595 tag);
596
597 /* If the block has been
598 * revoked, then we're all done
599 * here. */
600 if (jbd2_journal_test_revoke
601 (journal, blocknr,
602 next_commit_ID)) {
603 brelse(obh);
604 ++info->nr_revoke_hits;
605 goto skip_write;
606 }
607
608 /* Look for block corruption */
609 if (!jbd2_block_tag_csum_verify(
610 journal, tag, obh->b_data,
611 be32_to_cpu(tmp->h_sequence))) {
612 brelse(obh);
613 success = -EFSBADCRC;
614 printk(KERN_ERR "JBD2: Invalid "
615 "checksum recovering "
616 "data block %llu in "
617 "log\n", blocknr);
618 block_error = 1;
619 goto skip_write;
620 }
621
622 /* Find a buffer for the new
623 * data being restored */
624 nbh = __getblk(journal->j_fs_dev,
625 blocknr,
626 journal->j_blocksize);
627 if (nbh == NULL) {
628 printk(KERN_ERR
629 "JBD2: Out of memory "
630 "during recovery.\n");
631 err = -ENOMEM;
632 brelse(bh);
633 brelse(obh);
634 goto failed;
635 }
636
637 lock_buffer(nbh);
638 memcpy(nbh->b_data, obh->b_data,
639 journal->j_blocksize);
640 if (flags & JBD2_FLAG_ESCAPE) {
641 *((__be32 *)nbh->b_data) =
642 cpu_to_be32(JBD2_MAGIC_NUMBER);
643 }
644
645 BUFFER_TRACE(nbh, "marking dirty");
646 set_buffer_uptodate(nbh);
647 mark_buffer_dirty(nbh);
648 BUFFER_TRACE(nbh, "marking uptodate");
649 ++info->nr_replays;
650 /* ll_rw_block(WRITE, 1, &nbh); */
651 unlock_buffer(nbh);
652 brelse(obh);
653 brelse(nbh);
654 }
655
656 skip_write:
657 tagp += tag_bytes;
658 if (!(flags & JBD2_FLAG_SAME_UUID))
659 tagp += 16;
660
661 if (flags & JBD2_FLAG_LAST_TAG)
662 break;
663 }
664
665 brelse(bh);
666 continue;
667
668 case JBD2_COMMIT_BLOCK:
669 /* How to differentiate between interrupted commit
670 * and journal corruption ?
671 *
672 * {nth transaction}
673 * Checksum Verification Failed
674 * |
675 * ____________________
676 * | |
677 * async_commit sync_commit
678 * | |
679 * | GO TO NEXT "Journal Corruption"
680 * | TRANSACTION
681 * |
682 * {(n+1)th transanction}
683 * |
684 * _______|______________
685 * | |
686 * Commit block found Commit block not found
687 * | |
688 * "Journal Corruption" |
689 * _____________|_________
690 * | |
691 * nth trans corrupt OR nth trans
692 * and (n+1)th interrupted interrupted
693 * before commit block
694 * could reach the disk.
695 * (Cannot find the difference in above
696 * mentioned conditions. Hence assume
697 * "Interrupted Commit".)
698 */
699
700 /*
701 * Found an expected commit block: if checksums
702 * are present, verify them in PASS_SCAN; else not
703 * much to do other than move on to the next sequence
704 * number.
705 */
706 if (pass == PASS_SCAN &&
707 jbd2_has_feature_checksum(journal)) {
708 struct commit_header *cbh =
709 (struct commit_header *)bh->b_data;
710 unsigned found_chksum =
711 be32_to_cpu(cbh->h_chksum[0]);
712 __be64 commit_time =
> 713 be64_to_cpu(cbh->h_commit_sec); 714
715 if (info->end_transaction) {
716 journal->j_failed_commit =
717 info->end_transaction;
718 brelse(bh);
719 break;
720 }
721
722 /*
723 * If need_check_commit_time is set, it means
724 * csum verify failed before, if commit_time is
725 * increasing, it's same journal, otherwise it
726 * is stale journal block, just end this
727 * recovery.
728 */
729 if (need_check_commit_time) {
730 if (commit_time >= last_trans_commit_time) {
731 pr_err("JBD2: Invalid checksum found in transaction %u\n",
732 next_commit_ID);
733 err = -EFSBADCRC;
734 brelse(bh);
735 goto failed;
736 }
737 /*
738 * It likely does not belong to same
739 * journal, just end this recovery with
740 * success.
741 */
742 jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n",
743 next_commit_ID);
744 err = 0;
745 brelse(bh);
746 goto done;
747 }
748
749 /* Neither checksum match nor unused? */
750 if (!((crc32_sum == found_chksum &&
751 cbh->h_chksum_type ==
752 JBD2_CRC32_CHKSUM &&
753 cbh->h_chksum_size ==
754 JBD2_CRC32_CHKSUM_SIZE) ||
755 (cbh->h_chksum_type == 0 &&
756 cbh->h_chksum_size == 0 &&
757 found_chksum == 0)))
758 goto chksum_error;
759
760 crc32_sum = ~0;
761 last_trans_commit_time = commit_time;
762 }
763 if (pass == PASS_SCAN &&
764 !jbd2_commit_block_csum_verify(journal,
765 bh->b_data)) {
766 chksum_error:
767 info->end_transaction = next_commit_ID;
768
769 if (!jbd2_has_feature_async_commit(journal)) {
770 journal->j_failed_commit =
771 next_commit_ID;
772 brelse(bh);
773 break;
774 }
775 }
776 brelse(bh);
777 next_commit_ID++;
778 continue;
779
780 case JBD2_REVOKE_BLOCK:
781 /*
782 * Check revoke block crc in pass_scan, if csum verify
783 * failed, check commit block time later.
784 */
785 if (pass == PASS_SCAN &&
786 !jbd2_descriptor_block_csum_verify(journal,
787 bh->b_data)) {
788 jbd_debug(1, "JBD2: invalid revoke block found in %lu\n",
789 next_log_block);
790 need_check_commit_time = true;
791 }
792 /* If we aren't in the REVOKE pass, then we can
793 * just skip over this block. */
794 if (pass != PASS_REVOKE) {
795 brelse(bh);
796 continue;
797 }
798
799 err = scan_revoke_records(journal, bh,
800 next_commit_ID, info);
801 brelse(bh);
802 if (err)
803 goto failed;
804 continue;
805
806 default:
807 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
808 blocktype);
809 brelse(bh);
810 goto done;
811 }
812 }
813
814 done:
815 /*
816 * We broke out of the log scan loop: either we came to the
817 * known end of the log or we found an unexpected block in the
818 * log. If the latter happened, then we know that the "current"
819 * transaction marks the end of the valid log.
820 */
821
822 if (pass == PASS_SCAN) {
823 if (!info->end_transaction)
824 info->end_transaction = next_commit_ID;
825 } else {
826 /* It's really bad news if different passes end up at
827 * different places (but possible due to IO errors). */
828 if (info->end_transaction != next_commit_ID) {
829 printk(KERN_ERR "JBD2: recovery pass %d ended at "
830 "transaction %u, expected %u\n",
831 pass, next_commit_ID, info->end_transaction);
832 if (!success)
833 success = -EIO;
834 }
835 }
836 if (block_error && success == 0)
837 success = -EIO;
838 return success;
839
840 failed:
841 return err;
842 }
843
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Quoted 9 lines · kernel test robot
Hi Jan,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on ext4/dev]
[also build test WARNING on linus/master v5.9-rc8 next-20201002] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
Thanks for report! I'll send v4 with sparse warning fixed up (it isn't a functional problem but it is good to have it fixed).
Honza
Quoted 462 lines
url: https://github.com/0day-ci/linux/commits/Jan-Kara/jbd2-avoid-transaction-reuse-after-reformatting/20201006-183337 base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev config: i386-randconfig-s001-20201005 (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.2-201-g24bdaac6-dirty # https://github.com/0day-ci/linux/commit/ca606dc0beaec78e8b2b6ec2f112b2192534d9e2 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Jan-Kara/jbd2-avoid-transaction-reuse-after-reformatting/20201006-183337 git checkout ca606dc0beaec78e8b2b6ec2f112b2192534d9e2 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386If you fix the issue, kindly add following tag as appropriate
Reported-by kernel test robot <[email protected]>echo
echo "sparse warnings: (new ones prefixed by >>)" echoQuoted 1 line
Quoted 1 line
fs/jbd2/recovery.c:713:41: sparse: sparse: incorrect type in initializer (different base types) @@ expected restricted__be64[usertype]commit_time@@ got unsigned long long @@
fs/jbd2/recovery.c:713:41: sparse: expected restricted__be64[usertype]commit_timeQuoted 1 line
Quoted 1 line
fs/jbd2/recovery.c:713:41: sparse: got unsigned long long
fs/jbd2/recovery.c:730:45: sparse: sparse: restricted__be64degrades to integerfs/jbd2/recovery.c:730:60: sparse: sparse: restricted__be64degrades to integervim +713
fs/jbd2/recovery.c415 416 static int do_one_pass(journal_t *journal, 417 struct recovery_info *info, enum passtype pass) 418 { 419 unsigned int first_commit_ID, next_commit_ID; 420 unsigned long next_log_block; 421 int err, success = 0; 422 journal_superblock_t * sb; 423 journal_header_t * tmp; 424 struct buffer_head * bh; 425 unsigned int sequence; 426 int blocktype; 427 int tag_bytes = journal_tag_bytes(journal); 428 __u32 crc32_sum = ~0; /* Transactional Checksums */ 429 int descr_csum_size = 0; 430 int block_error = 0; 431 bool need_check_commit_time = false; 432 __be64 last_trans_commit_time = 0; 433 434 /* 435 * First thing is to establish what we expect to find in the log 436 * (in terms of transaction IDs), and where (in terms of log 437 * block offsets): query the superblock. 438 */ 439 440 sb = journal->j_superblock; 441 next_commit_ID = be32_to_cpu(sb->s_sequence); 442 next_log_block = be32_to_cpu(sb->s_start); 443 444 first_commit_ID = next_commit_ID; 445 if (pass == PASS_SCAN) 446 info->start_transaction = first_commit_ID; 447 448 jbd_debug(1, "Starting recovery pass %d\n", pass); 449 450 /* 451 * Now we walk through the log, transaction by transaction, 452 * making sure that each transaction has a commit block in the 453 * expected place. Each complete transaction gets replayed back 454 * into the main filesystem. 455 */ 456 457 while (1) { 458 int flags; 459 char * tagp; 460 journal_block_tag_t * tag; 461 struct buffer_head * obh; 462 struct buffer_head * nbh; 463 464 cond_resched(); 465 466 /* If we already know where to stop the log traversal, 467 * check right now that we haven't gone past the end of 468 * the log. */ 469 470 if (pass != PASS_SCAN) 471 if (tid_geq(next_commit_ID, info->end_transaction)) 472 break; 473 474 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", 475 next_commit_ID, next_log_block, journal->j_last); 476 477 /* Skip over each chunk of the transaction looking 478 * either the next descriptor block or the final commit 479 * record. */ 480 481 jbd_debug(3, "JBD2: checking block %ld\n", next_log_block); 482 err = jread(&bh, journal, next_log_block); 483 if (err) 484 goto failed; 485 486 next_log_block++; 487 wrap(journal, next_log_block); 488 489 /* What kind of buffer is it? 490 * 491 * If it is a descriptor block, check that it has the 492 * expected sequence number. Otherwise, we're all done 493 * here. */ 494 495 tmp = (journal_header_t *)bh->b_data; 496 497 if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) { 498 brelse(bh); 499 break; 500 } 501 502 blocktype = be32_to_cpu(tmp->h_blocktype); 503 sequence = be32_to_cpu(tmp->h_sequence); 504 jbd_debug(3, "Found magic %d, sequence %d\n", 505 blocktype, sequence); 506 507 if (sequence != next_commit_ID) { 508 brelse(bh); 509 break; 510 } 511 512 /* OK, we have a valid descriptor block which matches 513 * all of the sequence number checks. What are we going 514 * to do with it? That depends on the pass... */ 515 516 switch(blocktype) { 517 case JBD2_DESCRIPTOR_BLOCK: 518 /* Verify checksum first */ 519 if (jbd2_journal_has_csum_v2or3(journal)) 520 descr_csum_size = 521 sizeof(struct jbd2_journal_block_tail); 522 if (descr_csum_size > 0 && 523 !jbd2_descriptor_block_csum_verify(journal, 524 bh->b_data)) { 525 /* 526 * PASS_SCAN can see stale blocks due to lazy 527 * journal init. Don't error out on those yet. 528 */ 529 if (pass != PASS_SCAN) { 530 pr_err("JBD2: Invalid checksum " 531 "recovering block %lu in log\n", 532 next_log_block); 533 err = -EFSBADCRC; 534 brelse(bh); 535 goto failed; 536 } 537 need_check_commit_time = true; 538 jbd_debug(1, 539 "invalid descriptor block found in %lu\n", 540 next_log_block); 541 } 542 543 /* If it is a valid descriptor block, replay it 544 * in pass REPLAY; if journal_checksums enabled, then 545 * calculate checksums in PASS_SCAN, otherwise, 546 * just skip over the blocks it describes. */ 547 if (pass != PASS_REPLAY) { 548 if (pass == PASS_SCAN && 549 jbd2_has_feature_checksum(journal) && 550 !need_check_commit_time && 551 !info->end_transaction) { 552 if (calc_chksums(journal, bh, 553 &next_log_block, 554 &crc32_sum)) { 555 put_bh(bh); 556 break; 557 } 558 put_bh(bh); 559 continue; 560 } 561 next_log_block += count_tags(journal, bh); 562 wrap(journal, next_log_block); 563 put_bh(bh); 564 continue; 565 } 566 567 /* A descriptor block: we can now write all of 568 * the data blocks. Yay, useful work is finally 569 * getting done here! */ 570 571 tagp = &bh->b_data[sizeof(journal_header_t)]; 572 while ((tagp - bh->b_data + tag_bytes) 573 <= journal->j_blocksize - descr_csum_size) { 574 unsigned long io_block; 575 576 tag = (journal_block_tag_t *) tagp; 577 flags = be16_to_cpu(tag->t_flags); 578 579 io_block = next_log_block++; 580 wrap(journal, next_log_block); 581 err = jread(&obh, journal, io_block); 582 if (err) { 583 /* Recover what we can, but 584 * report failure at the end. */ 585 success = err; 586 printk(KERN_ERR 587 "JBD2: IO error %d recovering " 588 "block %ld in log\n", 589 err, io_block); 590 } else { 591 unsigned long long blocknr; 592 593 J_ASSERT(obh != NULL); 594 blocknr = read_tag_block(journal, 595 tag); 596 597 /* If the block has been 598 * revoked, then we're all done 599 * here. */ 600 if (jbd2_journal_test_revoke 601 (journal, blocknr, 602 next_commit_ID)) { 603 brelse(obh); 604 ++info->nr_revoke_hits; 605 goto skip_write; 606 } 607 608 /* Look for block corruption */ 609 if (!jbd2_block_tag_csum_verify( 610 journal, tag, obh->b_data, 611 be32_to_cpu(tmp->h_sequence))) { 612 brelse(obh); 613 success = -EFSBADCRC; 614 printk(KERN_ERR "JBD2: Invalid " 615 "checksum recovering " 616 "data block %llu in " 617 "log\n", blocknr); 618 block_error = 1; 619 goto skip_write; 620 } 621 622 /* Find a buffer for the new 623 * data being restored */ 624 nbh = __getblk(journal->j_fs_dev, 625 blocknr, 626 journal->j_blocksize); 627 if (nbh == NULL) { 628 printk(KERN_ERR 629 "JBD2: Out of memory " 630 "during recovery.\n"); 631 err = -ENOMEM; 632 brelse(bh); 633 brelse(obh); 634 goto failed; 635 } 636 637 lock_buffer(nbh); 638 memcpy(nbh->b_data, obh->b_data, 639 journal->j_blocksize); 640 if (flags & JBD2_FLAG_ESCAPE) { 641 *((__be32 *)nbh->b_data) = 642 cpu_to_be32(JBD2_MAGIC_NUMBER); 643 } 644 645 BUFFER_TRACE(nbh, "marking dirty"); 646 set_buffer_uptodate(nbh); 647 mark_buffer_dirty(nbh); 648 BUFFER_TRACE(nbh, "marking uptodate"); 649 ++info->nr_replays; 650 /* ll_rw_block(WRITE, 1, &nbh); */ 651 unlock_buffer(nbh); 652 brelse(obh); 653 brelse(nbh); 654 } 655 656 skip_write: 657 tagp += tag_bytes; 658 if (!(flags & JBD2_FLAG_SAME_UUID)) 659 tagp += 16; 660 661 if (flags & JBD2_FLAG_LAST_TAG) 662 break; 663 } 664 665 brelse(bh); 666 continue; 667 668 case JBD2_COMMIT_BLOCK: 669 /* How to differentiate between interrupted commit 670 * and journal corruption ? 671 * 672 * {nth transaction} 673 * Checksum Verification Failed 674 * | 675 * ____________________ 676 * | | 677 * async_commit sync_commit 678 * | | 679 * | GO TO NEXT "Journal Corruption" 680 * | TRANSACTION 681 * | 682 * {(n+1)th transanction} 683 * | 684 * _______|______________ 685 * | | 686 * Commit block found Commit block not found 687 * | | 688 * "Journal Corruption" | 689 * _____________|_________ 690 * | | 691 * nth trans corrupt OR nth trans 692 * and (n+1)th interrupted interrupted 693 * before commit block 694 * could reach the disk. 695 * (Cannot find the difference in above 696 * mentioned conditions. Hence assume 697 * "Interrupted Commit".) 698 */ 699 700 /* 701 * Found an expected commit block: if checksums 702 * are present, verify them in PASS_SCAN; else not 703 * much to do other than move on to the next sequence 704 * number. 705 */ 706 if (pass == PASS_SCAN && 707 jbd2_has_feature_checksum(journal)) { 708 struct commit_header *cbh = 709 (struct commit_header *)bh->b_data; 710 unsigned found_chksum = 711 be32_to_cpu(cbh->h_chksum[0]); 712 __be64 commit_time =Quoted 1 line
713
be64_to_cpu(cbh->h_commit_sec);714
715 if (info->end_transaction) { 716 journal->j_failed_commit = 717 info->end_transaction; 718 brelse(bh); 719 break; 720 } 721 722 /* 723 * If need_check_commit_time is set, it means 724 * csum verify failed before, if commit_time is 725 * increasing, it's same journal, otherwise it 726 * is stale journal block, just end this 727 * recovery. 728 */ 729 if (need_check_commit_time) { 730 if (commit_time >= last_trans_commit_time) { 731 pr_err("JBD2: Invalid checksum found in transaction %u\n", 732 next_commit_ID); 733 err = -EFSBADCRC; 734 brelse(bh); 735 goto failed; 736 } 737 /* 738 * It likely does not belong to same 739 * journal, just end this recovery with 740 * success. 741 */ 742 jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n", 743 next_commit_ID); 744 err = 0; 745 brelse(bh); 746 goto done; 747 } 748 749 /* Neither checksum match nor unused? */ 750 if (!((crc32_sum == found_chksum && 751 cbh->h_chksum_type == 752 JBD2_CRC32_CHKSUM && 753 cbh->h_chksum_size == 754 JBD2_CRC32_CHKSUM_SIZE) || 755 (cbh->h_chksum_type == 0 && 756 cbh->h_chksum_size == 0 && 757 found_chksum == 0))) 758 goto chksum_error; 759 760 crc32_sum = ~0; 761 last_trans_commit_time = commit_time; 762 } 763 if (pass == PASS_SCAN && 764 !jbd2_commit_block_csum_verify(journal, 765 bh->b_data)) { 766 chksum_error: 767 info->end_transaction = next_commit_ID; 768 769 if (!jbd2_has_feature_async_commit(journal)) { 770 journal->j_failed_commit = 771 next_commit_ID; 772 brelse(bh); 773 break; 774 } 775 } 776 brelse(bh); 777 next_commit_ID++; 778 continue; 779 780 case JBD2_REVOKE_BLOCK: 781 /* 782 * Check revoke block crc in pass_scan, if csum verify 783 * failed, check commit block time later. 784 */ 785 if (pass == PASS_SCAN && 786 !jbd2_descriptor_block_csum_verify(journal, 787 bh->b_data)) { 788 jbd_debug(1, "JBD2: invalid revoke block found in %lu\n", 789 next_log_block); 790 need_check_commit_time = true; 791 } 792 /* If we aren't in the REVOKE pass, then we can 793 * just skip over this block. */ 794 if (pass != PASS_REVOKE) { 795 brelse(bh); 796 continue; 797 } 798 799 err = scan_revoke_records(journal, bh, 800 next_commit_ID, info); 801 brelse(bh); 802 if (err) 803 goto failed; 804 continue; 805 806 default: 807 jbd_debug(3, "Unrecognised magic %d, end of scan.\n", 808 blocktype); 809 brelse(bh); 810 goto done; 811 } 812 } 813 814 done: 815 /* 816 * We broke out of the log scan loop: either we came to the 817 * known end of the log or we found an unexpected block in the 818 * log. If the latter happened, then we know that the "current" 819 * transaction marks the end of the valid log. 820 */ 821 822 if (pass == PASS_SCAN) { 823 if (!info->end_transaction) 824 info->end_transaction = next_commit_ID; 825 } else { 826 /* It's really bad news if different passes end up at 827 * different places (but possible due to IO errors). */ 828 if (info->end_transaction != next_commit_ID) { 829 printk(KERN_ERR "JBD2: recovery pass %d ended at " 830 "transaction %u, expected %u\n", 831 pass, next_commit_ID, info->end_transaction); 832 if (!success) 833 success = -EIO; 834 } 835 } 836 if (block_error && success == 0) 837 success = -EIO; 838 return success; 839 840 failed: 841 return err; 842 } 843---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
kernel test robot
build botThank you for the patch! Perhaps something to improve:
Hi Jan,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on ext4/dev]
[also build test WARNING on linus/master v5.9-rc8 next-20201002] [cannot apply to tytso-fscrypt/master]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Jan-Kara/jbd2-avoid-transaction-reuse-after-reformatting/20201006-183337 base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev config: s390-randconfig-s032-20201005 (attached as .config) compiler: s390-linux-gcc (GCC) 9.3.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.2-201-g24bdaac6-dirty
# https://github.com/0day-ci/linux/commit/ca606dc0beaec78e8b2b6ec2f112b2192534d9e2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Jan-Kara/jbd2-avoid-transaction-reuse-after-reformatting/20201006-183337 git checkout ca606dc0beaec78e8b2b6ec2f112b2192534d9e2
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=s390
If you fix the issue, kindly add following tag as appropriate
echo
echo "sparse warnings: (new ones prefixed by >>)" echo
>> fs/jbd2/recovery.c:713:41: sparse: sparse: incorrect type in initializer (different base types) @@ expected restricted __be64 [usertype] commit_time @@ got unsigned long long [usertype] @@ >> fs/jbd2/recovery.c:713:41: sparse: expected restricted __be64 [usertype] commit_time >> fs/jbd2/recovery.c:713:41: sparse: got unsigned long long [usertype] >> fs/jbd2/recovery.c:730:45: sparse: sparse: restricted __be64 degrades to integer
fs/jbd2/recovery.c:730:60: sparse: sparse: restricted __be64 degrades to integer
vim +713 fs/jbd2/recovery.c
415
416 static int do_one_pass(journal_t *journal,
417 struct recovery_info *info, enum passtype pass)
418 {
419 unsigned int first_commit_ID, next_commit_ID;
420 unsigned long next_log_block;
421 int err, success = 0;
422 journal_superblock_t * sb;
423 journal_header_t * tmp;
424 struct buffer_head * bh;
425 unsigned int sequence;
426 int blocktype;
427 int tag_bytes = journal_tag_bytes(journal);
428 __u32 crc32_sum = ~0; /* Transactional Checksums */
429 int descr_csum_size = 0;
430 int block_error = 0;
431 bool need_check_commit_time = false;
432 __be64 last_trans_commit_time = 0;
433
434 /*
435 * First thing is to establish what we expect to find in the log
436 * (in terms of transaction IDs), and where (in terms of log
437 * block offsets): query the superblock.
438 */
439
440 sb = journal->j_superblock;
441 next_commit_ID = be32_to_cpu(sb->s_sequence);
442 next_log_block = be32_to_cpu(sb->s_start);
443
444 first_commit_ID = next_commit_ID;
445 if (pass == PASS_SCAN)
446 info->start_transaction = first_commit_ID;
447
448 jbd_debug(1, "Starting recovery pass %d\n", pass);
449
450 /*
451 * Now we walk through the log, transaction by transaction,
452 * making sure that each transaction has a commit block in the
453 * expected place. Each complete transaction gets replayed back
454 * into the main filesystem.
455 */
456
457 while (1) {
458 int flags;
459 char * tagp;
460 journal_block_tag_t * tag;
461 struct buffer_head * obh;
462 struct buffer_head * nbh;
463
464 cond_resched();
465
466 /* If we already know where to stop the log traversal,
467 * check right now that we haven't gone past the end of
468 * the log. */
469
470 if (pass != PASS_SCAN)
471 if (tid_geq(next_commit_ID, info->end_transaction))
472 break;
473
474 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
475 next_commit_ID, next_log_block, journal->j_last);
476
477 /* Skip over each chunk of the transaction looking
478 * either the next descriptor block or the final commit
479 * record. */
480
481 jbd_debug(3, "JBD2: checking block %ld\n", next_log_block);
482 err = jread(&bh, journal, next_log_block);
483 if (err)
484 goto failed;
485
486 next_log_block++;
487 wrap(journal, next_log_block);
488
489 /* What kind of buffer is it?
490 *
491 * If it is a descriptor block, check that it has the
492 * expected sequence number. Otherwise, we're all done
493 * here. */
494
495 tmp = (journal_header_t *)bh->b_data;
496
497 if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {
498 brelse(bh);
499 break;
500 }
501
502 blocktype = be32_to_cpu(tmp->h_blocktype);
503 sequence = be32_to_cpu(tmp->h_sequence);
504 jbd_debug(3, "Found magic %d, sequence %d\n",
505 blocktype, sequence);
506
507 if (sequence != next_commit_ID) {
508 brelse(bh);
509 break;
510 }
511
512 /* OK, we have a valid descriptor block which matches
513 * all of the sequence number checks. What are we going
514 * to do with it? That depends on the pass... */
515
516 switch(blocktype) {
517 case JBD2_DESCRIPTOR_BLOCK:
518 /* Verify checksum first */
519 if (jbd2_journal_has_csum_v2or3(journal))
520 descr_csum_size =
521 sizeof(struct jbd2_journal_block_tail);
522 if (descr_csum_size > 0 &&
523 !jbd2_descriptor_block_csum_verify(journal,
524 bh->b_data)) {
525 /*
526 * PASS_SCAN can see stale blocks due to lazy
527 * journal init. Don't error out on those yet.
528 */
529 if (pass != PASS_SCAN) {
530 pr_err("JBD2: Invalid checksum "
531 "recovering block %lu in log\n",
532 next_log_block);
533 err = -EFSBADCRC;
534 brelse(bh);
535 goto failed;
536 }
537 need_check_commit_time = true;
538 jbd_debug(1,
539 "invalid descriptor block found in %lu\n",
540 next_log_block);
541 }
542
543 /* If it is a valid descriptor block, replay it
544 * in pass REPLAY; if journal_checksums enabled, then
545 * calculate checksums in PASS_SCAN, otherwise,
546 * just skip over the blocks it describes. */
547 if (pass != PASS_REPLAY) {
548 if (pass == PASS_SCAN &&
549 jbd2_has_feature_checksum(journal) &&
550 !need_check_commit_time &&
551 !info->end_transaction) {
552 if (calc_chksums(journal, bh,
553 &next_log_block,
554 &crc32_sum)) {
555 put_bh(bh);
556 break;
557 }
558 put_bh(bh);
559 continue;
560 }
561 next_log_block += count_tags(journal, bh);
562 wrap(journal, next_log_block);
563 put_bh(bh);
564 continue;
565 }
566
567 /* A descriptor block: we can now write all of
568 * the data blocks. Yay, useful work is finally
569 * getting done here! */
570
571 tagp = &bh->b_data[sizeof(journal_header_t)];
572 while ((tagp - bh->b_data + tag_bytes)
573 <= journal->j_blocksize - descr_csum_size) {
574 unsigned long io_block;
575
576 tag = (journal_block_tag_t *) tagp;
577 flags = be16_to_cpu(tag->t_flags);
578
579 io_block = next_log_block++;
580 wrap(journal, next_log_block);
581 err = jread(&obh, journal, io_block);
582 if (err) {
583 /* Recover what we can, but
584 * report failure at the end. */
585 success = err;
586 printk(KERN_ERR
587 "JBD2: IO error %d recovering "
588 "block %ld in log\n",
589 err, io_block);
590 } else {
591 unsigned long long blocknr;
592
593 J_ASSERT(obh != NULL);
594 blocknr = read_tag_block(journal,
595 tag);
596
597 /* If the block has been
598 * revoked, then we're all done
599 * here. */
600 if (jbd2_journal_test_revoke
601 (journal, blocknr,
602 next_commit_ID)) {
603 brelse(obh);
604 ++info->nr_revoke_hits;
605 goto skip_write;
606 }
607
608 /* Look for block corruption */
609 if (!jbd2_block_tag_csum_verify(
610 journal, tag, obh->b_data,
611 be32_to_cpu(tmp->h_sequence))) {
612 brelse(obh);
613 success = -EFSBADCRC;
614 printk(KERN_ERR "JBD2: Invalid "
615 "checksum recovering "
616 "data block %llu in "
617 "log\n", blocknr);
618 block_error = 1;
619 goto skip_write;
620 }
621
622 /* Find a buffer for the new
623 * data being restored */
624 nbh = __getblk(journal->j_fs_dev,
625 blocknr,
626 journal->j_blocksize);
627 if (nbh == NULL) {
628 printk(KERN_ERR
629 "JBD2: Out of memory "
630 "during recovery.\n");
631 err = -ENOMEM;
632 brelse(bh);
633 brelse(obh);
634 goto failed;
635 }
636
637 lock_buffer(nbh);
638 memcpy(nbh->b_data, obh->b_data,
639 journal->j_blocksize);
640 if (flags & JBD2_FLAG_ESCAPE) {
641 *((__be32 *)nbh->b_data) =
642 cpu_to_be32(JBD2_MAGIC_NUMBER);
643 }
644
645 BUFFER_TRACE(nbh, "marking dirty");
646 set_buffer_uptodate(nbh);
647 mark_buffer_dirty(nbh);
648 BUFFER_TRACE(nbh, "marking uptodate");
649 ++info->nr_replays;
650 /* ll_rw_block(WRITE, 1, &nbh); */
651 unlock_buffer(nbh);
652 brelse(obh);
653 brelse(nbh);
654 }
655
656 skip_write:
657 tagp += tag_bytes;
658 if (!(flags & JBD2_FLAG_SAME_UUID))
659 tagp += 16;
660
661 if (flags & JBD2_FLAG_LAST_TAG)
662 break;
663 }
664
665 brelse(bh);
666 continue;
667
668 case JBD2_COMMIT_BLOCK:
669 /* How to differentiate between interrupted commit
670 * and journal corruption ?
671 *
672 * {nth transaction}
673 * Checksum Verification Failed
674 * |
675 * ____________________
676 * | |
677 * async_commit sync_commit
678 * | |
679 * | GO TO NEXT "Journal Corruption"
680 * | TRANSACTION
681 * |
682 * {(n+1)th transanction}
683 * |
684 * _______|______________
685 * | |
686 * Commit block found Commit block not found
687 * | |
688 * "Journal Corruption" |
689 * _____________|_________
690 * | |
691 * nth trans corrupt OR nth trans
692 * and (n+1)th interrupted interrupted
693 * before commit block
694 * could reach the disk.
695 * (Cannot find the difference in above
696 * mentioned conditions. Hence assume
697 * "Interrupted Commit".)
698 */
699
700 /*
701 * Found an expected commit block: if checksums
702 * are present, verify them in PASS_SCAN; else not
703 * much to do other than move on to the next sequence
704 * number.
705 */
706 if (pass == PASS_SCAN &&
707 jbd2_has_feature_checksum(journal)) {
708 struct commit_header *cbh =
709 (struct commit_header *)bh->b_data;
710 unsigned found_chksum =
711 be32_to_cpu(cbh->h_chksum[0]);
712 __be64 commit_time =
> 713 be64_to_cpu(cbh->h_commit_sec);
714
715 if (info->end_transaction) {
716 journal->j_failed_commit =
717 info->end_transaction;
718 brelse(bh);
719 break;
720 }
721
722 /*
723 * If need_check_commit_time is set, it means
724 * csum verify failed before, if commit_time is
725 * increasing, it's same journal, otherwise it
726 * is stale journal block, just end this
727 * recovery.
728 */
729 if (need_check_commit_time) {
> 730 if (commit_time >= last_trans_commit_time) { 731 pr_err("JBD2: Invalid checksum found in transaction %u\n",
732 next_commit_ID);
733 err = -EFSBADCRC;
734 brelse(bh);
735 goto failed;
736 }
737 /*
738 * It likely does not belong to same
739 * journal, just end this recovery with
740 * success.
741 */
742 jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n",
743 next_commit_ID);
744 err = 0;
745 brelse(bh);
746 goto done;
747 }
748
749 /* Neither checksum match nor unused? */
750 if (!((crc32_sum == found_chksum &&
751 cbh->h_chksum_type ==
752 JBD2_CRC32_CHKSUM &&
753 cbh->h_chksum_size ==
754 JBD2_CRC32_CHKSUM_SIZE) ||
755 (cbh->h_chksum_type == 0 &&
756 cbh->h_chksum_size == 0 &&
757 found_chksum == 0)))
758 goto chksum_error;
759
760 crc32_sum = ~0;
761 last_trans_commit_time = commit_time;
762 }
763 if (pass == PASS_SCAN &&
764 !jbd2_commit_block_csum_verify(journal,
765 bh->b_data)) {
766 chksum_error:
767 info->end_transaction = next_commit_ID;
768
769 if (!jbd2_has_feature_async_commit(journal)) {
770 journal->j_failed_commit =
771 next_commit_ID;
772 brelse(bh);
773 break;
774 }
775 }
776 brelse(bh);
777 next_commit_ID++;
778 continue;
779
780 case JBD2_REVOKE_BLOCK:
781 /*
782 * Check revoke block crc in pass_scan, if csum verify
783 * failed, check commit block time later.
784 */
785 if (pass == PASS_SCAN &&
786 !jbd2_descriptor_block_csum_verify(journal,
787 bh->b_data)) {
788 jbd_debug(1, "JBD2: invalid revoke block found in %lu\n",
789 next_log_block);
790 need_check_commit_time = true;
791 }
792 /* If we aren't in the REVOKE pass, then we can
793 * just skip over this block. */
794 if (pass != PASS_REVOKE) {
795 brelse(bh);
796 continue;
797 }
798
799 err = scan_revoke_records(journal, bh,
800 next_commit_ID, info);
801 brelse(bh);
802 if (err)
803 goto failed;
804 continue;
805
806 default:
807 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
808 blocktype);
809 brelse(bh);
810 goto done;
811 }
812 }
813
814 done:
815 /*
816 * We broke out of the log scan loop: either we came to the
817 * known end of the log or we found an unexpected block in the
818 * log. If the latter happened, then we know that the "current"
819 * transaction marks the end of the valid log.
820 */
821
822 if (pass == PASS_SCAN) {
823 if (!info->end_transaction)
824 info->end_transaction = next_commit_ID;
825 } else {
826 /* It's really bad news if different passes end up at
827 * different places (but possible due to IO errors). */
828 if (info->end_transaction != next_commit_ID) {
829 printk(KERN_ERR "JBD2: recovery pass %d ended at "
830 "transaction %u, expected %u\n",
831 pass, next_commit_ID, info->end_transaction);
832 if (!success)
833 success = -EIO;
834 }
835 }
836 if (block_error && success == 0)
837 success = -EIO;
838 return success;
839
840 failed:
841 return err;
842 }
843
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org