Commit e8183c2452041326c95258ecc7865b6fcd91c730

Authored by Tomas Janousek
Committed by Jan Kara
1 parent e4f3ec0634

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

... ... @@ -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 /*