|
@@ -56,6 +56,7 @@
|
|
#include <linux/seq_file.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/crc-itu-t.h>
|
|
#include <linux/crc-itu-t.h>
|
|
|
|
+#include <linux/log2.h>
|
|
#include <asm/byteorder.h>
|
|
#include <asm/byteorder.h>
|
|
|
|
|
|
#include "udf_sb.h"
|
|
#include "udf_sb.h"
|
|
@@ -1215,16 +1216,65 @@ out_bh:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int udf_load_sparable_map(struct super_block *sb,
|
|
|
|
+ struct udf_part_map *map,
|
|
|
|
+ struct sparablePartitionMap *spm)
|
|
|
|
+{
|
|
|
|
+ uint32_t loc;
|
|
|
|
+ uint16_t ident;
|
|
|
|
+ struct sparingTable *st;
|
|
|
|
+ struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing;
|
|
|
|
+ int i;
|
|
|
|
+ struct buffer_head *bh;
|
|
|
|
+
|
|
|
|
+ map->s_partition_type = UDF_SPARABLE_MAP15;
|
|
|
|
+ sdata->s_packet_len = le16_to_cpu(spm->packetLength);
|
|
|
|
+ if (!is_power_of_2(sdata->s_packet_len)) {
|
|
|
|
+ udf_err(sb, "error loading logical volume descriptor: "
|
|
|
|
+ "Invalid packet length %u\n",
|
|
|
|
+ (unsigned)sdata->s_packet_len);
|
|
|
|
+ return -EIO;
|
|
|
|
+ }
|
|
|
|
+ if (spm->numSparingTables > 4) {
|
|
|
|
+ udf_err(sb, "error loading logical volume descriptor: "
|
|
|
|
+ "Too many sparing tables (%d)\n",
|
|
|
|
+ (int)spm->numSparingTables);
|
|
|
|
+ return -EIO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < spm->numSparingTables; i++) {
|
|
|
|
+ loc = le32_to_cpu(spm->locSparingTable[i]);
|
|
|
|
+ bh = udf_read_tagged(sb, loc, loc, &ident);
|
|
|
|
+ if (!bh)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ st = (struct sparingTable *)bh->b_data;
|
|
|
|
+ if (ident != 0 ||
|
|
|
|
+ strncmp(st->sparingIdent.ident, UDF_ID_SPARING,
|
|
|
|
+ strlen(UDF_ID_SPARING)) ||
|
|
|
|
+ sizeof(*st) + le16_to_cpu(st->reallocationTableLen) >
|
|
|
|
+ sb->s_blocksize) {
|
|
|
|
+ brelse(bh);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sdata->s_spar_map[i] = bh;
|
|
|
|
+ }
|
|
|
|
+ map->s_partition_func = udf_get_pblock_spar15;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int udf_load_logicalvol(struct super_block *sb, sector_t block,
|
|
static int udf_load_logicalvol(struct super_block *sb, sector_t block,
|
|
struct kernel_lb_addr *fileset)
|
|
struct kernel_lb_addr *fileset)
|
|
{
|
|
{
|
|
struct logicalVolDesc *lvd;
|
|
struct logicalVolDesc *lvd;
|
|
- int i, j, offset;
|
|
|
|
|
|
+ int i, offset;
|
|
uint8_t type;
|
|
uint8_t type;
|
|
struct udf_sb_info *sbi = UDF_SB(sb);
|
|
struct udf_sb_info *sbi = UDF_SB(sb);
|
|
struct genericPartitionMap *gpm;
|
|
struct genericPartitionMap *gpm;
|
|
uint16_t ident;
|
|
uint16_t ident;
|
|
struct buffer_head *bh;
|
|
struct buffer_head *bh;
|
|
|
|
+ unsigned int table_len;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
bh = udf_read_tagged(sb, block, block, &ident);
|
|
bh = udf_read_tagged(sb, block, block, &ident);
|
|
@@ -1232,15 +1282,20 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
|
|
return 1;
|
|
return 1;
|
|
BUG_ON(ident != TAG_IDENT_LVD);
|
|
BUG_ON(ident != TAG_IDENT_LVD);
|
|
lvd = (struct logicalVolDesc *)bh->b_data;
|
|
lvd = (struct logicalVolDesc *)bh->b_data;
|
|
-
|
|
|
|
- i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps));
|
|
|
|
- if (i != 0) {
|
|
|
|
- ret = i;
|
|
|
|
|
|
+ table_len = le32_to_cpu(lvd->mapTableLength);
|
|
|
|
+ if (sizeof(*lvd) + table_len > sb->s_blocksize) {
|
|
|
|
+ udf_err(sb, "error loading logical volume descriptor: "
|
|
|
|
+ "Partition table too long (%u > %lu)\n", table_len,
|
|
|
|
+ sb->s_blocksize - sizeof(*lvd));
|
|
goto out_bh;
|
|
goto out_bh;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps));
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out_bh;
|
|
|
|
+
|
|
for (i = 0, offset = 0;
|
|
for (i = 0, offset = 0;
|
|
- i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength);
|
|
|
|
|
|
+ i < sbi->s_partitions && offset < table_len;
|
|
i++, offset += gpm->partitionMapLength) {
|
|
i++, offset += gpm->partitionMapLength) {
|
|
struct udf_part_map *map = &sbi->s_partmaps[i];
|
|
struct udf_part_map *map = &sbi->s_partmaps[i];
|
|
gpm = (struct genericPartitionMap *)
|
|
gpm = (struct genericPartitionMap *)
|
|
@@ -1275,38 +1330,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
|
|
} else if (!strncmp(upm2->partIdent.ident,
|
|
} else if (!strncmp(upm2->partIdent.ident,
|
|
UDF_ID_SPARABLE,
|
|
UDF_ID_SPARABLE,
|
|
strlen(UDF_ID_SPARABLE))) {
|
|
strlen(UDF_ID_SPARABLE))) {
|
|
- uint32_t loc;
|
|
|
|
- struct sparingTable *st;
|
|
|
|
- struct sparablePartitionMap *spm =
|
|
|
|
- (struct sparablePartitionMap *)gpm;
|
|
|
|
-
|
|
|
|
- map->s_partition_type = UDF_SPARABLE_MAP15;
|
|
|
|
- map->s_type_specific.s_sparing.s_packet_len =
|
|
|
|
- le16_to_cpu(spm->packetLength);
|
|
|
|
- for (j = 0; j < spm->numSparingTables; j++) {
|
|
|
|
- struct buffer_head *bh2;
|
|
|
|
-
|
|
|
|
- loc = le32_to_cpu(
|
|
|
|
- spm->locSparingTable[j]);
|
|
|
|
- bh2 = udf_read_tagged(sb, loc, loc,
|
|
|
|
- &ident);
|
|
|
|
- map->s_type_specific.s_sparing.
|
|
|
|
- s_spar_map[j] = bh2;
|
|
|
|
-
|
|
|
|
- if (bh2 == NULL)
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- st = (struct sparingTable *)bh2->b_data;
|
|
|
|
- if (ident != 0 || strncmp(
|
|
|
|
- st->sparingIdent.ident,
|
|
|
|
- UDF_ID_SPARING,
|
|
|
|
- strlen(UDF_ID_SPARING))) {
|
|
|
|
- brelse(bh2);
|
|
|
|
- map->s_type_specific.s_sparing.
|
|
|
|
- s_spar_map[j] = NULL;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- map->s_partition_func = udf_get_pblock_spar15;
|
|
|
|
|
|
+ if (udf_load_sparable_map(sb, map,
|
|
|
|
+ (struct sparablePartitionMap *)gpm) < 0)
|
|
|
|
+ goto out_bh;
|
|
} else if (!strncmp(upm2->partIdent.ident,
|
|
} else if (!strncmp(upm2->partIdent.ident,
|
|
UDF_ID_METADATA,
|
|
UDF_ID_METADATA,
|
|
strlen(UDF_ID_METADATA))) {
|
|
strlen(UDF_ID_METADATA))) {
|