diff options
Diffstat (limited to 'fs/udf/super.c')
-rw-r--r-- | fs/udf/super.c | 239 |
1 files changed, 98 insertions, 141 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c index 7ec828566df2..fe0dafebde71 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -678,149 +678,120 @@ static int udf_vrs(struct super_block *sb, int silent) | |||
678 | } | 678 | } |
679 | 679 | ||
680 | /* | 680 | /* |
681 | * udf_find_anchor | 681 | * Check whether there is an anchor block in the given block |
682 | * | ||
683 | * PURPOSE | ||
684 | * Find an anchor volume descriptor. | ||
685 | * | ||
686 | * PRE-CONDITIONS | ||
687 | * sb Pointer to _locked_ superblock. | ||
688 | * lastblock Last block on media. | ||
689 | * | ||
690 | * POST-CONDITIONS | ||
691 | * <return> 1 if not found, 0 if ok | ||
692 | * | ||
693 | * HISTORY | ||
694 | * July 1, 1997 - Andrew E. Mileski | ||
695 | * Written, tested, and released. | ||
696 | */ | 682 | */ |
697 | static void udf_find_anchor(struct super_block *sb) | 683 | static int udf_check_anchor_block(struct super_block *sb, sector_t block, |
684 | bool varconv) | ||
698 | { | 685 | { |
699 | int lastblock; | ||
700 | struct buffer_head *bh = NULL; | 686 | struct buffer_head *bh = NULL; |
687 | tag *t; | ||
701 | uint16_t ident; | 688 | uint16_t ident; |
702 | uint32_t location; | 689 | uint32_t location; |
690 | |||
691 | if (varconv) | ||
692 | bh = sb_bread(sb, udf_fixed_to_variable(block)); | ||
693 | else | ||
694 | bh = sb_bread(sb, block); | ||
695 | |||
696 | if (!bh) | ||
697 | return 0; | ||
698 | |||
699 | t = (tag *)bh->b_data; | ||
700 | ident = le16_to_cpu(t->tagIdent); | ||
701 | location = le32_to_cpu(t->tagLocation); | ||
702 | brelse(bh); | ||
703 | if (ident != TAG_IDENT_AVDP) | ||
704 | return 0; | ||
705 | return location == block; | ||
706 | } | ||
707 | |||
708 | /* Search for an anchor volume descriptor pointer */ | ||
709 | static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | ||
710 | sector_t lastblock) | ||
711 | { | ||
712 | sector_t last[4]; | ||
703 | int i; | 713 | int i; |
704 | struct udf_sb_info *sbi; | 714 | struct udf_sb_info *sbi = UDF_SB(sb); |
705 | 715 | ||
706 | sbi = UDF_SB(sb); | 716 | last[0] = lastblock; |
707 | lastblock = sbi->s_last_block; | 717 | last[1] = last[0] - 2; |
718 | last[2] = last[0] - 150; | ||
719 | last[3] = last[0] - 152; | ||
708 | 720 | ||
709 | if (lastblock) { | 721 | /* according to spec, anchor is in either: |
710 | int varlastblock = udf_variable_to_fixed(lastblock); | 722 | * block 256 |
711 | int last[] = { lastblock, lastblock - 2, | 723 | * lastblock-256 |
712 | lastblock - 150, lastblock - 152, | 724 | * lastblock |
713 | varlastblock, varlastblock - 2, | 725 | * however, if the disc isn't closed, it could be 512 */ |
714 | varlastblock - 150, varlastblock - 152 }; | ||
715 | |||
716 | lastblock = 0; | ||
717 | |||
718 | /* Search for an anchor volume descriptor pointer */ | ||
719 | |||
720 | /* according to spec, anchor is in either: | ||
721 | * block 256 | ||
722 | * lastblock-256 | ||
723 | * lastblock | ||
724 | * however, if the disc isn't closed, it could be 512 */ | ||
725 | |||
726 | for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { | ||
727 | ident = location = 0; | ||
728 | if (last[i] >= 0) { | ||
729 | bh = sb_bread(sb, last[i]); | ||
730 | if (bh) { | ||
731 | tag *t = (tag *)bh->b_data; | ||
732 | ident = le16_to_cpu(t->tagIdent); | ||
733 | location = le32_to_cpu(t->tagLocation); | ||
734 | brelse(bh); | ||
735 | } | ||
736 | } | ||
737 | 726 | ||
738 | if (ident == TAG_IDENT_AVDP) { | 727 | for (i = 0; i < ARRAY_SIZE(last); i++) { |
739 | if (location == last[i] - sbi->s_session) { | 728 | if (last[i] < 0) |
740 | lastblock = last[i] - sbi->s_session; | 729 | continue; |
741 | sbi->s_anchor[0] = lastblock; | ||
742 | sbi->s_anchor[1] = lastblock - 256; | ||
743 | } else if (location == | ||
744 | udf_variable_to_fixed(last[i]) - | ||
745 | sbi->s_session) { | ||
746 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
747 | lastblock = | ||
748 | udf_variable_to_fixed(last[i]) - | ||
749 | sbi->s_session; | ||
750 | sbi->s_anchor[0] = lastblock; | ||
751 | sbi->s_anchor[1] = lastblock - 256 - | ||
752 | sbi->s_session; | ||
753 | } else { | ||
754 | udf_debug("Anchor found at block %d, " | ||
755 | "location mismatch %d.\n", | ||
756 | last[i], location); | ||
757 | } | ||
758 | } else if (ident == TAG_IDENT_FE || | ||
759 | ident == TAG_IDENT_EFE) { | ||
760 | lastblock = last[i]; | ||
761 | sbi->s_anchor[3] = 512; | ||
762 | } else { | ||
763 | ident = location = 0; | ||
764 | if (last[i] >= 256) { | ||
765 | bh = sb_bread(sb, last[i] - 256); | ||
766 | if (bh) { | ||
767 | tag *t = (tag *)bh->b_data; | ||
768 | ident = le16_to_cpu( | ||
769 | t->tagIdent); | ||
770 | location = le32_to_cpu( | ||
771 | t->tagLocation); | ||
772 | brelse(bh); | ||
773 | } | ||
774 | } | ||
775 | 730 | ||
776 | if (ident == TAG_IDENT_AVDP && | 731 | if (udf_check_anchor_block(sb, last[i], varconv)) { |
777 | location == last[i] - 256 - | 732 | sbi->s_anchor[0] = last[i]; |
778 | sbi->s_session) { | 733 | sbi->s_anchor[1] = last[i] - 256; |
779 | lastblock = last[i]; | 734 | return last[i]; |
780 | sbi->s_anchor[1] = last[i] - 256; | 735 | } |
781 | } else { | ||
782 | ident = location = 0; | ||
783 | if (last[i] >= 312 + sbi->s_session) { | ||
784 | bh = sb_bread(sb, | ||
785 | last[i] - 312 - | ||
786 | sbi->s_session); | ||
787 | if (bh) { | ||
788 | tag *t = (tag *) | ||
789 | bh->b_data; | ||
790 | ident = le16_to_cpu( | ||
791 | t->tagIdent); | ||
792 | location = le32_to_cpu( | ||
793 | t->tagLocation); | ||
794 | brelse(bh); | ||
795 | } | ||
796 | } | ||
797 | 736 | ||
798 | if (ident == TAG_IDENT_AVDP && | 737 | if (last[i] < 256) |
799 | location == udf_variable_to_fixed(last[i]) - 256) { | 738 | continue; |
800 | UDF_SET_FLAG(sb, | 739 | |
801 | UDF_FLAG_VARCONV); | 740 | if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { |
802 | lastblock = udf_variable_to_fixed(last[i]); | 741 | sbi->s_anchor[1] = last[i] - 256; |
803 | sbi->s_anchor[1] = lastblock - 256; | 742 | return last[i]; |
804 | } | ||
805 | } | ||
806 | } | ||
807 | } | 743 | } |
808 | } | 744 | } |
809 | 745 | ||
810 | if (!lastblock) { | 746 | if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { |
811 | /* We haven't found the lastblock. check 312 */ | 747 | sbi->s_anchor[0] = sbi->s_session + 256; |
812 | bh = sb_bread(sb, 312 + sbi->s_session); | 748 | return last[0]; |
813 | if (bh) { | 749 | } |
814 | tag *t = (tag *)bh->b_data; | 750 | if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { |
815 | ident = le16_to_cpu(t->tagIdent); | 751 | sbi->s_anchor[0] = sbi->s_session + 512; |
816 | location = le32_to_cpu(t->tagLocation); | 752 | return last[0]; |
817 | brelse(bh); | 753 | } |
754 | return 0; | ||
755 | } | ||
818 | 756 | ||
819 | if (ident == TAG_IDENT_AVDP && location == 256) | 757 | /* |
820 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | 758 | * Find an anchor volume descriptor. The function expects sbi->s_lastblock to |
821 | } | 759 | * be the last block on the media. |
760 | * | ||
761 | * Return 1 if not found, 0 if ok | ||
762 | * | ||
763 | */ | ||
764 | static void udf_find_anchor(struct super_block *sb) | ||
765 | { | ||
766 | sector_t lastblock; | ||
767 | struct buffer_head *bh = NULL; | ||
768 | uint16_t ident; | ||
769 | int i; | ||
770 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
771 | |||
772 | lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); | ||
773 | if (lastblock) | ||
774 | goto check_anchor; | ||
775 | |||
776 | /* No anchor found? Try VARCONV conversion of block numbers */ | ||
777 | /* Firstly, we try to not convert number of the last block */ | ||
778 | lastblock = udf_scan_anchors(sb, 1, | ||
779 | udf_variable_to_fixed(sbi->s_last_block)); | ||
780 | if (lastblock) { | ||
781 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
782 | goto check_anchor; | ||
822 | } | 783 | } |
823 | 784 | ||
785 | /* Secondly, we try with converted number of the last block */ | ||
786 | lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); | ||
787 | if (lastblock) | ||
788 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
789 | |||
790 | check_anchor: | ||
791 | /* | ||
792 | * Check located anchors and the anchor block supplied via | ||
793 | * mount options | ||
794 | */ | ||
824 | for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { | 795 | for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { |
825 | if (!sbi->s_anchor[i]) | 796 | if (!sbi->s_anchor[i]) |
826 | continue; | 797 | continue; |
@@ -830,9 +801,7 @@ static void udf_find_anchor(struct super_block *sb) | |||
830 | sbi->s_anchor[i] = 0; | 801 | sbi->s_anchor[i] = 0; |
831 | else { | 802 | else { |
832 | brelse(bh); | 803 | brelse(bh); |
833 | if ((ident != TAG_IDENT_AVDP) && | 804 | if (ident != TAG_IDENT_AVDP) |
834 | (i || (ident != TAG_IDENT_FE && | ||
835 | ident != TAG_IDENT_EFE))) | ||
836 | sbi->s_anchor[i] = 0; | 805 | sbi->s_anchor[i] = 0; |
837 | } | 806 | } |
838 | } | 807 | } |
@@ -1225,17 +1194,6 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) | |||
1225 | if (ret) | 1194 | if (ret) |
1226 | goto out_bh; | 1195 | goto out_bh; |
1227 | 1196 | ||
1228 | if (!sbi->s_last_block) { | ||
1229 | sbi->s_last_block = udf_get_last_block(sb); | ||
1230 | udf_find_anchor(sb); | ||
1231 | if (!sbi->s_last_block) { | ||
1232 | udf_debug("Unable to determine Lastblock (For " | ||
1233 | "Virtual Partition)\n"); | ||
1234 | ret = 1; | ||
1235 | goto out_bh; | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | ret = udf_load_vat(sb, i, type1_idx); | 1197 | ret = udf_load_vat(sb, i, type1_idx); |
1240 | out_bh: | 1198 | out_bh: |
1241 | /* In case loading failed, we handle cleanup in udf_fill_super */ | 1199 | /* In case loading failed, we handle cleanup in udf_fill_super */ |
@@ -1778,7 +1736,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) | |||
1778 | sbi->s_last_block = uopt.lastblock; | 1736 | sbi->s_last_block = uopt.lastblock; |
1779 | sbi->s_anchor[0] = sbi->s_anchor[1] = 0; | 1737 | sbi->s_anchor[0] = sbi->s_anchor[1] = 0; |
1780 | sbi->s_anchor[2] = uopt.anchor; | 1738 | sbi->s_anchor[2] = uopt.anchor; |
1781 | sbi->s_anchor[3] = 256; | ||
1782 | 1739 | ||
1783 | if (udf_check_valid(sb, uopt.novrs, silent)) { | 1740 | if (udf_check_valid(sb, uopt.novrs, silent)) { |
1784 | /* read volume recognition sequences */ | 1741 | /* read volume recognition sequences */ |