From 3fbf586cf7f245392142e5407c2a56f1cff979b6 Mon Sep 17 00:00:00 2001 From: Daniel Taylor Date: Tue, 23 Mar 2010 13:35:50 -0700 Subject: [PATCH] fs/partitions/msdos: add support for large disks In order to use disks larger than 2TiB on Windows XP, it is necessary to use 4096-byte logical sectors in an MBR. Although the kernel storage and functions called from msdos.c used "sector_t" internally, msdos.c still used u32 variables, which results in the ability to handle XP-compatible large disks. This patch changes the internal variables to "sector_t". Daniel said: "In the near future, WD will be releasing products that need this patch". [hirofumi@mail.parknet.co.jp: tweaks and fix] Signed-off-by: Daniel Taylor Signed-off-by: OGAWA Hirofumi Cc: "H. Peter Anvin" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/partitions/msdos.c | 72 +++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 0028d2ef0662..b78385840a55 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -31,14 +31,17 @@ */ #include -#define SYS_IND(p) (get_unaligned(&p->sys_ind)) -#define NR_SECTS(p) ({ __le32 __a = get_unaligned(&p->nr_sects); \ - le32_to_cpu(__a); \ - }) +#define SYS_IND(p) get_unaligned(&p->sys_ind) -#define START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \ - le32_to_cpu(__a); \ - }) +static inline sector_t nr_sects(struct partition *p) +{ + return (sector_t)get_unaligned_le32(&p->nr_sects); +} + +static inline sector_t start_sect(struct partition *p) +{ + return (sector_t)get_unaligned_le32(&p->start_sect); +} static inline int is_extended_partition(struct partition *p) { @@ -104,13 +107,13 @@ static int aix_magic_present(unsigned char *p, struct block_device *bdev) static void parse_extended(struct parsed_partitions *state, struct block_device *bdev, - u32 first_sector, u32 first_size) + sector_t first_sector, sector_t first_size) { struct partition *p; Sector sect; unsigned char *data; - u32 this_sector, this_size; - int sector_size = bdev_logical_block_size(bdev) / 512; + sector_t this_sector, this_size; + sector_t sector_size = bdev_logical_block_size(bdev) / 512; int loopct = 0; /* number of links followed without finding a data partition */ int i; @@ -145,14 +148,14 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, * First process the data partition(s) */ for (i=0; i<4; i++, p++) { - u32 offs, size, next; - if (!NR_SECTS(p) || is_extended_partition(p)) + sector_t offs, size, next; + if (!nr_sects(p) || is_extended_partition(p)) continue; /* Check the 3rd and 4th entries - these sometimes contain random garbage */ - offs = START_SECT(p)*sector_size; - size = NR_SECTS(p)*sector_size; + offs = start_sect(p)*sector_size; + size = nr_sects(p)*sector_size; next = this_sector + offs; if (i >= 2) { if (offs + size > this_size) @@ -179,13 +182,13 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, */ p -= 4; for (i=0; i<4; i++, p++) - if (NR_SECTS(p) && is_extended_partition(p)) + if (nr_sects(p) && is_extended_partition(p)) break; if (i == 4) goto done; /* nothing left to do */ - this_sector = first_sector + START_SECT(p) * sector_size; - this_size = NR_SECTS(p) * sector_size; + this_sector = first_sector + start_sect(p) * sector_size; + this_size = nr_sects(p) * sector_size; put_dev_sector(sect); } done: @@ -197,7 +200,7 @@ done: static void parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_SOLARIS_X86_PARTITION Sector sect; @@ -244,7 +247,7 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, */ static void parse_bsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin, char *flavour, + sector_t offset, sector_t size, int origin, char *flavour, int max_partitions) { Sector sect; @@ -263,7 +266,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev, if (le16_to_cpu(l->d_npartitions) < max_partitions) max_partitions = le16_to_cpu(l->d_npartitions); for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - u32 bsd_start, bsd_size; + sector_t bsd_start, bsd_size; if (state->next == state->limit) break; @@ -290,7 +293,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev, static void parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_BSD_DISKLABEL parse_bsd(state, bdev, offset, size, origin, @@ -300,7 +303,7 @@ parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, static void parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_BSD_DISKLABEL parse_bsd(state, bdev, offset, size, origin, @@ -310,7 +313,7 @@ parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, static void parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_BSD_DISKLABEL parse_bsd(state, bdev, offset, size, origin, @@ -324,7 +327,7 @@ parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, */ static void parse_unixware(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_UNIXWARE_DISKLABEL Sector sect; @@ -348,7 +351,8 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev, if (p->s_label != UNIXWARE_FS_UNUSED) put_partition(state, state->next++, - START_SECT(p), NR_SECTS(p)); + le32_to_cpu(p->start_sect), + le32_to_cpu(p->nr_sects)); p++; } put_dev_sector(sect); @@ -363,7 +367,7 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev, */ static void parse_minix(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_MINIX_SUBPARTITION Sector sect; @@ -390,7 +394,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev, /* add each partition in use */ if (SYS_IND(p) == MINIX_PARTITION) put_partition(state, state->next++, - START_SECT(p), NR_SECTS(p)); + start_sect(p), nr_sects(p)); } printk(" >\n"); } @@ -401,7 +405,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev, static struct { unsigned char id; void (*parse)(struct parsed_partitions *, struct block_device *, - u32, u32, int); + sector_t, sector_t, int); } subtypes[] = { {FREEBSD_PARTITION, parse_freebsd}, {NETBSD_PARTITION, parse_netbsd}, @@ -415,7 +419,7 @@ static struct { int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) { - int sector_size = bdev_logical_block_size(bdev) / 512; + sector_t sector_size = bdev_logical_block_size(bdev) / 512; Sector sect; unsigned char *data; struct partition *p; @@ -483,8 +487,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) state->next = 5; for (slot = 1 ; slot <= 4 ; slot++, p++) { - u32 start = START_SECT(p)*sector_size; - u32 size = NR_SECTS(p)*sector_size; + sector_t start = start_sect(p)*sector_size; + sector_t size = nr_sects(p)*sector_size; if (!size) continue; if (is_extended_partition(p)) { @@ -513,7 +517,7 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) unsigned char id = SYS_IND(p); int n; - if (!NR_SECTS(p)) + if (!nr_sects(p)) continue; for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) @@ -521,8 +525,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) if (!subtypes[n].parse) continue; - subtypes[n].parse(state, bdev, START_SECT(p)*sector_size, - NR_SECTS(p)*sector_size, slot); + subtypes[n].parse(state, bdev, start_sect(p)*sector_size, + nr_sects(p)*sector_size, slot); } put_dev_sector(sect); return 1; -- 2.34.1