udf: Try harder when looking for VAT inode
authorJan Kara <jack@suse.cz>
Mon, 30 Nov 2009 18:47:55 +0000 (19:47 +0100)
committerJan Kara <jack@suse.cz>
Mon, 14 Dec 2009 20:40:04 +0000 (21:40 +0100)
Some disks do not contain VAT inode in the last recorded block as required
by the standard but a few blocks earlier (or the number of recorded blocks
is wrong). So look for the VAT inode a bit before the end of the media.

Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/super.c

index 9d1b8c2e6c45bcc3d5428ef2095f718b970a139f..1e4543cbcd276decb1b43942e999b9f2f851b145 100644 (file)
@@ -1078,21 +1078,39 @@ static int udf_fill_partdesc_info(struct super_block *sb,
        return 0;
 }
 
-static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
+static void udf_find_vat_block(struct super_block *sb, int p_index,
+                              int type1_index, sector_t start_block)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct udf_part_map *map = &sbi->s_partmaps[p_index];
+       sector_t vat_block;
        struct kernel_lb_addr ino;
+
+       /*
+        * VAT file entry is in the last recorded block. Some broken disks have
+        * it a few blocks before so try a bit harder...
+        */
+       ino.partitionReferenceNum = type1_index;
+       for (vat_block = start_block;
+            vat_block >= map->s_partition_root &&
+            vat_block >= start_block - 3 &&
+            !sbi->s_vat_inode; vat_block--) {
+               ino.logicalBlockNum = vat_block - map->s_partition_root;
+               sbi->s_vat_inode = udf_iget(sb, &ino);
+       }
+}
+
+static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map = &sbi->s_partmaps[p_index];
        struct buffer_head *bh = NULL;
        struct udf_inode_info *vati;
        uint32_t pos;
        struct virtualAllocationTable20 *vat20;
        sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
 
-       /* VAT file entry is in the last recorded block */
-       ino.partitionReferenceNum = type1_index;
-       ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root;
-       sbi->s_vat_inode = udf_iget(sb, &ino);
+       udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block);
        if (!sbi->s_vat_inode &&
            sbi->s_last_block != blocks - 1) {
                printk(KERN_NOTICE "UDF-fs: Failed to read VAT inode from the"
@@ -1100,9 +1118,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
                       "block of the device (%lu).\n",
                       (unsigned long)sbi->s_last_block,
                       (unsigned long)blocks - 1);
-               ino.partitionReferenceNum = type1_index;
-               ino.logicalBlockNum = blocks - 1 - map->s_partition_root;
-               sbi->s_vat_inode = udf_iget(sb, &ino);
+               udf_find_vat_block(sb, p_index, type1_index, blocks - 1);
        }
        if (!sbi->s_vat_inode)
                return 1;