]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/udf/super.c
udf: Cleanup anchor block detection.
[linux-2.6-omap-h63xx.git] / fs / udf / super.c
index 7ec828566df2fb53f772a6c058647f7503102b42..fe0dafebde7143e8a4bd18043a20b78e1b202290 100644 (file)
@@ -678,149 +678,120 @@ static int udf_vrs(struct super_block *sb, int silent)
 }
 
 /*
- * udf_find_anchor
- *
- * PURPOSE
- *     Find an anchor volume descriptor.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to _locked_ superblock.
- *     lastblock               Last block on media.
- *
- * POST-CONDITIONS
- *     <return>                1 if not found, 0 if ok
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
+ * Check whether there is an anchor block in the given block
  */
-static void udf_find_anchor(struct super_block *sb)
+static int udf_check_anchor_block(struct super_block *sb, sector_t block,
+                                       bool varconv)
 {
-       int lastblock;
        struct buffer_head *bh = NULL;
+       tag *t;
        uint16_t ident;
        uint32_t location;
+
+       if (varconv)
+               bh = sb_bread(sb, udf_fixed_to_variable(block));
+       else
+               bh = sb_bread(sb, block);
+
+       if (!bh)
+               return 0;
+
+       t = (tag *)bh->b_data;
+       ident = le16_to_cpu(t->tagIdent);
+       location = le32_to_cpu(t->tagLocation);
+       brelse(bh);
+       if (ident != TAG_IDENT_AVDP)
+               return 0;
+       return location == block;
+}
+
+/* Search for an anchor volume descriptor pointer */
+static sector_t udf_scan_anchors(struct super_block *sb, bool varconv,
+                                       sector_t lastblock)
+{
+       sector_t last[4];
        int i;
-       struct udf_sb_info *sbi;
+       struct udf_sb_info *sbi = UDF_SB(sb);
 
-       sbi = UDF_SB(sb);
-       lastblock = sbi->s_last_block;
+       last[0] = lastblock;
+       last[1] = last[0] - 2;
+       last[2] = last[0] - 150;
+       last[3] = last[0] - 152;
 
-       if (lastblock) {
-               int varlastblock = udf_variable_to_fixed(lastblock);
-               int last[] =  { lastblock, lastblock - 2,
-                               lastblock - 150, lastblock - 152,
-                               varlastblock, varlastblock - 2,
-                               varlastblock - 150, varlastblock - 152 };
-
-               lastblock = 0;
-
-               /* Search for an anchor volume descriptor pointer */
-
-               /*  according to spec, anchor is in either:
-                *     block 256
-                *     lastblock-256
-                *     lastblock
-                *  however, if the disc isn't closed, it could be 512 */
-
-               for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) {
-                       ident = location = 0;
-                       if (last[i] >= 0) {
-                               bh = sb_bread(sb, last[i]);
-                               if (bh) {
-                                       tag *t = (tag *)bh->b_data;
-                                       ident = le16_to_cpu(t->tagIdent);
-                                       location = le32_to_cpu(t->tagLocation);
-                                       brelse(bh);
-                               }
-                       }
+       /*  according to spec, anchor is in either:
+        *     block 256
+        *     lastblock-256
+        *     lastblock
+        *  however, if the disc isn't closed, it could be 512 */
 
-                       if (ident == TAG_IDENT_AVDP) {
-                               if (location == last[i] - sbi->s_session) {
-                                       lastblock = last[i] - sbi->s_session;
-                                       sbi->s_anchor[0] = lastblock;
-                                       sbi->s_anchor[1] = lastblock - 256;
-                               } else if (location ==
-                                               udf_variable_to_fixed(last[i]) -
-                                                       sbi->s_session) {
-                                       UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-                                       lastblock =
-                                               udf_variable_to_fixed(last[i]) -
-                                                       sbi->s_session;
-                                       sbi->s_anchor[0] = lastblock;
-                                       sbi->s_anchor[1] = lastblock - 256 -
-                                                               sbi->s_session;
-                               } else {
-                                       udf_debug("Anchor found at block %d, "
-                                                 "location mismatch %d.\n",
-                                                 last[i], location);
-                               }
-                       } else if (ident == TAG_IDENT_FE ||
-                                       ident == TAG_IDENT_EFE) {
-                               lastblock = last[i];
-                               sbi->s_anchor[3] = 512;
-                       } else {
-                               ident = location = 0;
-                               if (last[i] >= 256) {
-                                       bh = sb_bread(sb, last[i] - 256);
-                                       if (bh) {
-                                               tag *t = (tag *)bh->b_data;
-                                               ident = le16_to_cpu(
-                                                               t->tagIdent);
-                                               location = le32_to_cpu(
-                                                               t->tagLocation);
-                                               brelse(bh);
-                                       }
-                               }
+       for (i = 0; i < ARRAY_SIZE(last); i++) {
+               if (last[i] < 0)
+                       continue;
 
-                               if (ident == TAG_IDENT_AVDP &&
-                                   location == last[i] - 256 -
-                                               sbi->s_session) {
-                                       lastblock = last[i];
-                                       sbi->s_anchor[1] = last[i] - 256;
-                               } else {
-                                       ident = location = 0;
-                                       if (last[i] >= 312 + sbi->s_session) {
-                                               bh = sb_bread(sb,
-                                                               last[i] - 312 -
-                                                               sbi->s_session);
-                                               if (bh) {
-                                                       tag *t = (tag *)
-                                                                bh->b_data;
-                                                       ident = le16_to_cpu(
-                                                               t->tagIdent);
-                                                       location = le32_to_cpu(
-                                                               t->tagLocation);
-                                                       brelse(bh);
-                                               }
-                                       }
+               if (udf_check_anchor_block(sb, last[i], varconv)) {
+                       sbi->s_anchor[0] = last[i];
+                       sbi->s_anchor[1] = last[i] - 256;
+                       return last[i];
+               }
 
-                                       if (ident == TAG_IDENT_AVDP &&
-                                           location == udf_variable_to_fixed(last[i]) - 256) {
-                                               UDF_SET_FLAG(sb,
-                                                            UDF_FLAG_VARCONV);
-                                               lastblock = udf_variable_to_fixed(last[i]);
-                                               sbi->s_anchor[1] = lastblock - 256;
-                                       }
-                               }
-                       }
+               if (last[i] < 256)
+                       continue;
+
+               if (udf_check_anchor_block(sb, last[i] - 256, varconv)) {
+                       sbi->s_anchor[1] = last[i] - 256;
+                       return last[i];
                }
        }
 
-       if (!lastblock) {
-               /* We haven't found the lastblock. check 312 */
-               bh = sb_bread(sb, 312 + sbi->s_session);
-               if (bh) {
-                       tag *t = (tag *)bh->b_data;
-                       ident = le16_to_cpu(t->tagIdent);
-                       location = le32_to_cpu(t->tagLocation);
-                       brelse(bh);
+       if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) {
+               sbi->s_anchor[0] = sbi->s_session + 256;
+               return last[0];
+       }
+       if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) {
+               sbi->s_anchor[0] = sbi->s_session + 512;
+               return last[0];
+       }
+       return 0;
+}
 
-                       if (ident == TAG_IDENT_AVDP && location == 256)
-                               UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-               }
+/*
+ * Find an anchor volume descriptor. The function expects sbi->s_lastblock to
+ * be the last block on the media.
+ *
+ * Return 1 if not found, 0 if ok
+ *
+ */
+static void udf_find_anchor(struct super_block *sb)
+{
+       sector_t lastblock;
+       struct buffer_head *bh = NULL;
+       uint16_t ident;
+       int i;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+
+       lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block);
+       if (lastblock)
+               goto check_anchor;
+
+       /* No anchor found? Try VARCONV conversion of block numbers */
+       /* Firstly, we try to not convert number of the last block */
+       lastblock = udf_scan_anchors(sb, 1,
+                               udf_variable_to_fixed(sbi->s_last_block));
+       if (lastblock) {
+               UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+               goto check_anchor;
        }
 
+       /* Secondly, we try with converted number of the last block */
+       lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block);
+       if (lastblock)
+               UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+
+check_anchor:
+       /*
+        * Check located anchors and the anchor block supplied via
+        * mount options
+        */
        for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
                if (!sbi->s_anchor[i])
                        continue;
@@ -830,9 +801,7 @@ static void udf_find_anchor(struct super_block *sb)
                        sbi->s_anchor[i] = 0;
                else {
                        brelse(bh);
-                       if ((ident != TAG_IDENT_AVDP) &&
-                               (i || (ident != TAG_IDENT_FE &&
-                                       ident != TAG_IDENT_EFE)))
+                       if (ident != TAG_IDENT_AVDP)
                                sbi->s_anchor[i] = 0;
                }
        }
@@ -1225,17 +1194,6 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
        if (ret)
                goto out_bh;
 
-       if (!sbi->s_last_block) {
-               sbi->s_last_block = udf_get_last_block(sb);
-               udf_find_anchor(sb);
-               if (!sbi->s_last_block) {
-                       udf_debug("Unable to determine Lastblock (For "
-                                       "Virtual Partition)\n");
-                       ret = 1;
-                       goto out_bh;
-               }
-       }
-
        ret = udf_load_vat(sb, i, type1_idx);
 out_bh:
        /* 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)
        sbi->s_last_block = uopt.lastblock;
        sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
        sbi->s_anchor[2] = uopt.anchor;
-       sbi->s_anchor[3] = 256;
 
        if (udf_check_valid(sb, uopt.novrs, silent)) {
                /* read volume recognition sequences */