diff options
author | Tomas Janousek <tomi@nomi.cz> | 2008-06-23 09:12:35 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2008-06-24 05:38:03 -0400 |
commit | e8183c2452041326c95258ecc7865b6fcd91c730 (patch) | |
tree | c5a3e26a11f0b886c27d3af3ac2dd63976b2ff81 | |
parent | e4f3ec063421bdbcb93330e72aa3eeedb6a0d85a (diff) |
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>
-rw-r--r-- | fs/udf/super.c | 57 |
1 files changed, 23 insertions, 34 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c index 7a5f69be6ac2..44cc702f96cc 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -682,38 +682,26 @@ static int udf_vrs(struct super_block *sb, int silent) | |||
682 | /* | 682 | /* |
683 | * Check whether there is an anchor block in the given block | 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, | 685 | static int udf_check_anchor_block(struct super_block *sb, sector_t block) |
686 | bool varconv) | ||
687 | { | 686 | { |
688 | struct buffer_head *bh = NULL; | 687 | struct buffer_head *bh; |
689 | tag *t; | ||
690 | uint16_t ident; | 688 | uint16_t ident; |
691 | uint32_t location; | ||
692 | 689 | ||
693 | if (varconv) { | 690 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && |
694 | if (udf_fixed_to_variable(block) >= | 691 | udf_fixed_to_variable(block) >= |
695 | sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) | 692 | sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) |
696 | return 0; | 693 | return 0; |
697 | bh = sb_bread(sb, udf_fixed_to_variable(block)); | ||
698 | } | ||
699 | else | ||
700 | bh = sb_bread(sb, block); | ||
701 | 694 | ||
695 | bh = udf_read_tagged(sb, block, block, &ident); | ||
702 | if (!bh) | 696 | if (!bh) |
703 | return 0; | 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 | brelse(bh); | 698 | brelse(bh); |
709 | if (ident != TAG_IDENT_AVDP) | 699 | |
710 | return 0; | 700 | return ident == TAG_IDENT_AVDP; |
711 | return location == block; | ||
712 | } | 701 | } |
713 | 702 | ||
714 | /* Search for an anchor volume descriptor pointer */ | 703 | /* Search for an anchor volume descriptor pointer */ |
715 | static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | 704 | static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock) |
716 | sector_t lastblock) | ||
717 | { | 705 | { |
718 | sector_t last[6]; | 706 | sector_t last[6]; |
719 | int i; | 707 | int i; |
@@ -739,7 +727,7 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | |||
739 | sb->s_blocksize_bits) | 727 | sb->s_blocksize_bits) |
740 | continue; | 728 | continue; |
741 | 729 | ||
742 | if (udf_check_anchor_block(sb, last[i], varconv)) { | 730 | if (udf_check_anchor_block(sb, last[i])) { |
743 | sbi->s_anchor[0] = last[i]; | 731 | sbi->s_anchor[0] = last[i]; |
744 | sbi->s_anchor[1] = last[i] - 256; | 732 | sbi->s_anchor[1] = last[i] - 256; |
745 | return last[i]; | 733 | return last[i]; |
@@ -748,17 +736,17 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | |||
748 | if (last[i] < 256) | 736 | if (last[i] < 256) |
749 | continue; | 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 | sbi->s_anchor[1] = last[i] - 256; | 740 | sbi->s_anchor[1] = last[i] - 256; |
753 | return last[i]; | 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 | sbi->s_anchor[0] = sbi->s_session + 256; | 746 | sbi->s_anchor[0] = sbi->s_session + 256; |
759 | return last[0]; | 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 | sbi->s_anchor[0] = sbi->s_session + 512; | 750 | sbi->s_anchor[0] = sbi->s_session + 512; |
763 | return last[0]; | 751 | return last[0]; |
764 | } | 752 | } |
@@ -780,23 +768,24 @@ static void udf_find_anchor(struct super_block *sb) | |||
780 | int i; | 768 | int i; |
781 | struct udf_sb_info *sbi = UDF_SB(sb); | 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 | if (lastblock) | 772 | if (lastblock) |
785 | goto check_anchor; | 773 | goto check_anchor; |
786 | 774 | ||
787 | /* No anchor found? Try VARCONV conversion of block numbers */ | 775 | /* No anchor found? Try VARCONV conversion of block numbers */ |
776 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
788 | /* Firstly, we try to not convert number of the last block */ | 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 | udf_variable_to_fixed(sbi->s_last_block)); | 779 | udf_variable_to_fixed(sbi->s_last_block)); |
791 | if (lastblock) { | 780 | if (lastblock) |
792 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
793 | goto check_anchor; | 781 | goto check_anchor; |
794 | } | ||
795 | 782 | ||
796 | /* Secondly, we try with converted number of the last block */ | 783 | /* Secondly, we try with converted number of the last block */ |
797 | lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); | 784 | lastblock = udf_scan_anchors(sb, sbi->s_last_block); |
798 | if (lastblock) | 785 | if (!lastblock) { |
799 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | 786 | /* VARCONV didn't help. Clear it. */ |
787 | UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); | ||
788 | } | ||
800 | 789 | ||
801 | check_anchor: | 790 | check_anchor: |
802 | /* | 791 | /* |