diff options
-rw-r--r-- | fs/partitions/sun.c | 62 | ||||
-rw-r--r-- | fs/partitions/sun.h | 1 |
2 files changed, 46 insertions, 17 deletions
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index 123f8b46c8ba..794118da4ef3 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -19,34 +19,47 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) Sector sect; struct sun_disklabel { unsigned char info[128]; /* Informative text string */ - unsigned char spare0[14]; - struct sun_info { - unsigned char spare1; - unsigned char id; - unsigned char spare2; - unsigned char flags; - } infos[8]; - unsigned char spare[246]; /* Boot information etc. */ + struct sun_vtoc { + __be32 version; /* Layout version */ + char volume[8]; /* Volume name */ + __be16 nparts; /* Number of partitions */ + struct sun_info { /* Partition hdrs, sec 2 */ + __be16 id; + __be16 flags; + } infos[8]; + __be16 padding; /* Alignment padding */ + __be32 bootinfo[3]; /* Info needed by mboot */ + __be32 sanity; /* To verify vtoc sanity */ + __be32 reserved[10]; /* Free space */ + __be32 timestamp[8]; /* Partition timestamp */ + } vtoc; + __be32 write_reinstruct; /* sectors to skip, writes */ + __be32 read_reinstruct; /* sectors to skip, reads */ + unsigned char spare[148]; /* Padding */ __be16 rspeed; /* Disk rotational speed */ __be16 pcylcount; /* Physical cylinder count */ __be16 sparecyl; /* extra sects per cylinder */ - unsigned char spare2[4]; /* More magic... */ + __be16 obs1; /* gap1 */ + __be16 obs2; /* gap2 */ __be16 ilfact; /* Interleave factor */ __be16 ncyl; /* Data cylinder count */ __be16 nacyl; /* Alt. cylinder count */ __be16 ntrks; /* Tracks per cylinder */ __be16 nsect; /* Sectors per track */ - unsigned char spare3[4]; /* Even more magic... */ + __be16 obs3; /* bhead - Label head offset */ + __be16 obs4; /* ppart - Physical Partition */ struct sun_partition { __be32 start_cylinder; __be32 num_sectors; } partitions[8]; __be16 magic; /* Magic number */ __be16 csum; /* Label xor'd checksum */ - } * label; + } * label; struct sun_partition *p; unsigned long spc; char b[BDEVNAME_SIZE]; + int use_vtoc; + int nparts; label = (struct sun_disklabel *)read_dev_sector(bdev, 0, §); if (!label) @@ -70,9 +83,22 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) return 0; } - /* All Sun disks have 8 partition entries */ + /* Check to see if we can use the VTOC table */ + use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) && + (be32_to_cpu(label->vtoc.version) == 1) && + (be16_to_cpu(label->vtoc.nparts) <= 8)); + + /* Use 8 partition entries if not specified in validated VTOC */ + nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8; + + /* + * So that old Linux-Sun partitions continue to work, + * alow the VTOC to be used under the additional condition ... + */ + use_vtoc = use_vtoc || !(label->vtoc.sanity | + label->vtoc.version | label->vtoc.nparts); spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect); - for (i = 0; i < 8; i++, p++) { + for (i = 0; i < nparts; i++, p++) { unsigned long st_sector; unsigned int num_sectors; @@ -81,10 +107,12 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) if (num_sectors) { put_partition(state, slot, st_sector, num_sectors); state->parts[slot].flags = 0; - if (label->infos[i].id == LINUX_RAID_PARTITION) - state->parts[slot].flags |= ADDPART_FLAG_RAID; - if (label->infos[i].id == SUN_WHOLE_DISK) - state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; + if (use_vtoc) { + if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION) + state->parts[slot].flags |= ADDPART_FLAG_RAID; + else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK) + state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; + } } slot++; } diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h index b1b19fda7b22..7f864d1f86d4 100644 --- a/fs/partitions/sun.h +++ b/fs/partitions/sun.h @@ -3,5 +3,6 @@ */ #define SUN_LABEL_MAGIC 0xDABE +#define SUN_VTOC_SANITY 0x600DDEEE int sun_partition(struct parsed_partitions *state, struct block_device *bdev); |