diff options
Diffstat (limited to 'fs/udf/partition.c')
| -rw-r--r-- | fs/udf/partition.c | 67 |
1 files changed, 63 insertions, 4 deletions
diff --git a/fs/udf/partition.c b/fs/udf/partition.c index fc533345ab89..63610f026ae1 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | 24 | ||
| 25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
| 26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
| 27 | #include <linux/udf_fs.h> | ||
| 28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 29 | #include <linux/buffer_head.h> | 28 | #include <linux/buffer_head.h> |
| 30 | 29 | ||
| @@ -55,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, | |||
| 55 | struct udf_sb_info *sbi = UDF_SB(sb); | 54 | struct udf_sb_info *sbi = UDF_SB(sb); |
| 56 | struct udf_part_map *map; | 55 | struct udf_part_map *map; |
| 57 | struct udf_virtual_data *vdata; | 56 | struct udf_virtual_data *vdata; |
| 58 | struct udf_inode_info *iinfo; | 57 | struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode); |
| 59 | 58 | ||
| 60 | map = &sbi->s_partmaps[partition]; | 59 | map = &sbi->s_partmaps[partition]; |
| 61 | vdata = &map->s_type_specific.s_virtual; | 60 | vdata = &map->s_type_specific.s_virtual; |
| 62 | index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); | ||
| 63 | 61 | ||
| 64 | if (block > vdata->s_num_entries) { | 62 | if (block > vdata->s_num_entries) { |
| 65 | udf_debug("Trying to access block beyond end of VAT " | 63 | udf_debug("Trying to access block beyond end of VAT " |
| @@ -67,6 +65,12 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, | |||
| 67 | return 0xFFFFFFFF; | 65 | return 0xFFFFFFFF; |
| 68 | } | 66 | } |
| 69 | 67 | ||
| 68 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | ||
| 69 | loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data + | ||
| 70 | vdata->s_start_offset))[block]); | ||
| 71 | goto translate; | ||
| 72 | } | ||
| 73 | index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); | ||
| 70 | if (block >= index) { | 74 | if (block >= index) { |
| 71 | block -= index; | 75 | block -= index; |
| 72 | newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); | 76 | newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); |
| @@ -89,7 +93,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, | |||
| 89 | 93 | ||
| 90 | brelse(bh); | 94 | brelse(bh); |
| 91 | 95 | ||
| 92 | iinfo = UDF_I(sbi->s_vat_inode); | 96 | translate: |
| 93 | if (iinfo->i_location.partitionReferenceNum == partition) { | 97 | if (iinfo->i_location.partitionReferenceNum == partition) { |
| 94 | udf_debug("recursive call to udf_get_pblock!\n"); | 98 | udf_debug("recursive call to udf_get_pblock!\n"); |
| 95 | return 0xFFFFFFFF; | 99 | return 0xFFFFFFFF; |
| @@ -263,3 +267,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) | |||
| 263 | 267 | ||
| 264 | return 0; | 268 | return 0; |
| 265 | } | 269 | } |
| 270 | |||
| 271 | static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, | ||
| 272 | uint16_t partition, uint32_t offset) | ||
| 273 | { | ||
| 274 | struct super_block *sb = inode->i_sb; | ||
| 275 | struct udf_part_map *map; | ||
| 276 | kernel_lb_addr eloc; | ||
| 277 | uint32_t elen; | ||
| 278 | sector_t ext_offset; | ||
| 279 | struct extent_position epos = {}; | ||
| 280 | uint32_t phyblock; | ||
| 281 | |||
| 282 | if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != | ||
| 283 | (EXT_RECORDED_ALLOCATED >> 30)) | ||
| 284 | phyblock = 0xFFFFFFFF; | ||
| 285 | else { | ||
| 286 | map = &UDF_SB(sb)->s_partmaps[partition]; | ||
| 287 | /* map to sparable/physical partition desc */ | ||
| 288 | phyblock = udf_get_pblock(sb, eloc.logicalBlockNum, | ||
| 289 | map->s_partition_num, ext_offset + offset); | ||
| 290 | } | ||
| 291 | |||
| 292 | brelse(epos.bh); | ||
| 293 | return phyblock; | ||
| 294 | } | ||
| 295 | |||
| 296 | uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block, | ||
| 297 | uint16_t partition, uint32_t offset) | ||
| 298 | { | ||
| 299 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
| 300 | struct udf_part_map *map; | ||
| 301 | struct udf_meta_data *mdata; | ||
| 302 | uint32_t retblk; | ||
| 303 | struct inode *inode; | ||
| 304 | |||
| 305 | udf_debug("READING from METADATA\n"); | ||
| 306 | |||
| 307 | map = &sbi->s_partmaps[partition]; | ||
| 308 | mdata = &map->s_type_specific.s_metadata; | ||
| 309 | inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe; | ||
| 310 | |||
| 311 | /* We shouldn't mount such media... */ | ||
| 312 | BUG_ON(!inode); | ||
| 313 | retblk = udf_try_read_meta(inode, block, partition, offset); | ||
| 314 | if (retblk == 0xFFFFFFFF) { | ||
| 315 | udf_warning(sb, __func__, "error reading from METADATA, " | ||
| 316 | "trying to read from MIRROR"); | ||
| 317 | inode = mdata->s_mirror_fe; | ||
| 318 | if (!inode) | ||
| 319 | return 0xFFFFFFFF; | ||
| 320 | retblk = udf_try_read_meta(inode, block, partition, offset); | ||
| 321 | } | ||
| 322 | |||
| 323 | return retblk; | ||
| 324 | } | ||
