Commit e8183c2452041326c95258ecc7865b6fcd91c730
Committed by
Jan Kara
1 parent
e4f3ec0634
Exists in
master
and in
7 other branches
udf: Fix regression in UDF anchor block detection
In some cases it could happen that some block passed test in udf_check_anchor_block() even though udf_read_tagged() refused to read it later (e.g. because checksum was not correct). This patch makes udf_check_anchor_block() use udf_read_tagged() so that the checking is stricter. This fixes the regression (certain disks unmountable) caused by commit 423cf6dc04eb79d441bfda2b127bc4b57134b41d. Signed-off-by: Tomas Janousek <tomi@nomi.cz> Signed-off-by: Jan Kara <jack@suse.cz>
Showing 1 changed file with 23 additions and 34 deletions Side-by-side Diff
fs/udf/super.c
... | ... | @@ -682,38 +682,26 @@ |
682 | 682 | /* |
683 | 683 | * Check whether there is an anchor block in the given block |
684 | 684 | */ |
685 | -static int udf_check_anchor_block(struct super_block *sb, sector_t block, | |
686 | - bool varconv) | |
685 | +static int udf_check_anchor_block(struct super_block *sb, sector_t block) | |
687 | 686 | { |
688 | - struct buffer_head *bh = NULL; | |
689 | - tag *t; | |
687 | + struct buffer_head *bh; | |
690 | 688 | uint16_t ident; |
691 | - uint32_t location; | |
692 | 689 | |
693 | - if (varconv) { | |
694 | - if (udf_fixed_to_variable(block) >= | |
695 | - sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) | |
696 | - return 0; | |
697 | - bh = sb_bread(sb, udf_fixed_to_variable(block)); | |
698 | - } | |
699 | - else | |
700 | - bh = sb_bread(sb, block); | |
690 | + if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && | |
691 | + udf_fixed_to_variable(block) >= | |
692 | + sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) | |
693 | + return 0; | |
701 | 694 | |
695 | + bh = udf_read_tagged(sb, block, block, &ident); | |
702 | 696 | if (!bh) |
703 | 697 | return 0; |
704 | - | |
705 | - t = (tag *)bh->b_data; | |
706 | - ident = le16_to_cpu(t->tagIdent); | |
707 | - location = le32_to_cpu(t->tagLocation); | |
708 | 698 | brelse(bh); |
709 | - if (ident != TAG_IDENT_AVDP) | |
710 | - return 0; | |
711 | - return location == block; | |
699 | + | |
700 | + return ident == TAG_IDENT_AVDP; | |
712 | 701 | } |
713 | 702 | |
714 | 703 | /* Search for an anchor volume descriptor pointer */ |
715 | -static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | |
716 | - sector_t lastblock) | |
704 | +static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock) | |
717 | 705 | { |
718 | 706 | sector_t last[6]; |
719 | 707 | int i; |
... | ... | @@ -739,7 +727,7 @@ |
739 | 727 | sb->s_blocksize_bits) |
740 | 728 | continue; |
741 | 729 | |
742 | - if (udf_check_anchor_block(sb, last[i], varconv)) { | |
730 | + if (udf_check_anchor_block(sb, last[i])) { | |
743 | 731 | sbi->s_anchor[0] = last[i]; |
744 | 732 | sbi->s_anchor[1] = last[i] - 256; |
745 | 733 | return last[i]; |
746 | 734 | |
747 | 735 | |
... | ... | @@ -748,17 +736,17 @@ |
748 | 736 | if (last[i] < 256) |
749 | 737 | continue; |
750 | 738 | |
751 | - if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { | |
739 | + if (udf_check_anchor_block(sb, last[i] - 256)) { | |
752 | 740 | sbi->s_anchor[1] = last[i] - 256; |
753 | 741 | return last[i]; |
754 | 742 | } |
755 | 743 | } |
756 | 744 | |
757 | - if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { | |
745 | + if (udf_check_anchor_block(sb, sbi->s_session + 256)) { | |
758 | 746 | sbi->s_anchor[0] = sbi->s_session + 256; |
759 | 747 | return last[0]; |
760 | 748 | } |
761 | - if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { | |
749 | + if (udf_check_anchor_block(sb, sbi->s_session + 512)) { | |
762 | 750 | sbi->s_anchor[0] = sbi->s_session + 512; |
763 | 751 | return last[0]; |
764 | 752 | } |
765 | 753 | |
766 | 754 | |
767 | 755 | |
768 | 756 | |
769 | 757 | |
... | ... | @@ -780,23 +768,24 @@ |
780 | 768 | int i; |
781 | 769 | struct udf_sb_info *sbi = UDF_SB(sb); |
782 | 770 | |
783 | - lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); | |
771 | + lastblock = udf_scan_anchors(sb, sbi->s_last_block); | |
784 | 772 | if (lastblock) |
785 | 773 | goto check_anchor; |
786 | 774 | |
787 | 775 | /* No anchor found? Try VARCONV conversion of block numbers */ |
776 | + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | |
788 | 777 | /* Firstly, we try to not convert number of the last block */ |
789 | - lastblock = udf_scan_anchors(sb, 1, | |
778 | + lastblock = udf_scan_anchors(sb, | |
790 | 779 | udf_variable_to_fixed(sbi->s_last_block)); |
791 | - if (lastblock) { | |
792 | - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | |
780 | + if (lastblock) | |
793 | 781 | goto check_anchor; |
794 | - } | |
795 | 782 | |
796 | 783 | /* Secondly, we try with converted number of the last block */ |
797 | - lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); | |
798 | - if (lastblock) | |
799 | - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | |
784 | + lastblock = udf_scan_anchors(sb, sbi->s_last_block); | |
785 | + if (!lastblock) { | |
786 | + /* VARCONV didn't help. Clear it. */ | |
787 | + UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); | |
788 | + } | |
800 | 789 | |
801 | 790 | check_anchor: |
802 | 791 | /* |