aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/udf/super.c239
-rw-r--r--fs/udf/udf_sb.h2
2 files changed, 99 insertions, 142 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 */
697static void udf_find_anchor(struct super_block *sb) 683static 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 */
709static 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 */
764static 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
790check_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);
1240out_bh: 1198out_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 */
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index fb2a6e9f8dac..8308a12e1232 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -100,7 +100,7 @@ struct udf_sb_info {
100 100
101 /* Sector headers */ 101 /* Sector headers */
102 __s32 s_session; 102 __s32 s_session;
103 __u32 s_anchor[4]; 103 __u32 s_anchor[3];
104 __u32 s_last_block; 104 __u32 s_last_block;
105 105
106 struct buffer_head *s_lvid_bh; 106 struct buffer_head *s_lvid_bh;