aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-04-07 09:59:23 -0400
committerJan Kara <jack@suse.cz>2008-04-17 08:23:10 -0400
commit423cf6dc04eb79d441bfda2b127bc4b57134b41d (patch)
treed4b9f7a35dfbdd9a2fbf986bf05c959674e4086a /fs/udf
parent38b74a53e5625b7bbbd08918294b86f1db2f0565 (diff)
udf: Cleanup anchor block detection.
UDF anchor block detection is complicated by several things - there are several places where the anchor point can be, some of them relative to the last recorded block which some devices report wrongly. Moreover some devices on some media seem to have 7 spare blocks sectors for every 32 blocks (at least as far as I understand the old code) so we have to count also with that possibility. This patch splits anchor block detection into several functions so that it is clearer what we actually try to do. We fix several bugs of the type "for such and such media, we fail to check block blah" as a result of the cleanup. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-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;