aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
authorTomas Janousek <tomi@nomi.cz>2008-06-23 09:12:35 -0400
committerJan Kara <jack@suse.cz>2008-06-24 05:38:03 -0400
commite8183c2452041326c95258ecc7865b6fcd91c730 (patch)
treec5a3e26a11f0b886c27d3af3ac2dd63976b2ff81 /fs/udf
parente4f3ec063421bdbcb93330e72aa3eeedb6a0d85a (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>
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/super.c57
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 */
685static int udf_check_anchor_block(struct super_block *sb, sector_t block, 685static 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 */
715static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, 704static 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
801check_anchor: 790check_anchor:
802 /* 791 /*