Commit 3fbf586c authored by Daniel Taylor's avatar Daniel Taylor Committed by Linus Torvalds

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: default avatarDaniel Taylor <daniel.taylor@wdc.com>
Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <stable@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b5c26f97
...@@ -31,14 +31,17 @@ ...@@ -31,14 +31,17 @@
*/ */
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define SYS_IND(p) (get_unaligned(&p->sys_ind)) #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 START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \ static inline sector_t nr_sects(struct partition *p)
le32_to_cpu(__a); \ {
}) 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) 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) ...@@ -104,13 +107,13 @@ static int aix_magic_present(unsigned char *p, struct block_device *bdev)
static void static void
parse_extended(struct parsed_partitions *state, struct block_device *bdev, 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; struct partition *p;
Sector sect; Sector sect;
unsigned char *data; unsigned char *data;
u32 this_sector, this_size; sector_t this_sector, this_size;
int sector_size = bdev_logical_block_size(bdev) / 512; sector_t sector_size = bdev_logical_block_size(bdev) / 512;
int loopct = 0; /* number of links followed int loopct = 0; /* number of links followed
without finding a data partition */ without finding a data partition */
int i; int i;
...@@ -145,14 +148,14 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, ...@@ -145,14 +148,14 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev,
* First process the data partition(s) * First process the data partition(s)
*/ */
for (i=0; i<4; i++, p++) { for (i=0; i<4; i++, p++) {
u32 offs, size, next; sector_t offs, size, next;
if (!NR_SECTS(p) || is_extended_partition(p)) if (!nr_sects(p) || is_extended_partition(p))
continue; continue;
/* Check the 3rd and 4th entries - /* Check the 3rd and 4th entries -
these sometimes contain random garbage */ these sometimes contain random garbage */
offs = START_SECT(p)*sector_size; offs = start_sect(p)*sector_size;
size = NR_SECTS(p)*sector_size; size = nr_sects(p)*sector_size;
next = this_sector + offs; next = this_sector + offs;
if (i >= 2) { if (i >= 2) {
if (offs + size > this_size) if (offs + size > this_size)
...@@ -179,13 +182,13 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, ...@@ -179,13 +182,13 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev,
*/ */
p -= 4; p -= 4;
for (i=0; i<4; i++, p++) for (i=0; i<4; i++, p++)
if (NR_SECTS(p) && is_extended_partition(p)) if (nr_sects(p) && is_extended_partition(p))
break; break;
if (i == 4) if (i == 4)
goto done; /* nothing left to do */ goto done; /* nothing left to do */
this_sector = first_sector + START_SECT(p) * sector_size; this_sector = first_sector + start_sect(p) * sector_size;
this_size = NR_SECTS(p) * sector_size; this_size = nr_sects(p) * sector_size;
put_dev_sector(sect); put_dev_sector(sect);
} }
done: done:
...@@ -197,7 +200,7 @@ done: ...@@ -197,7 +200,7 @@ done:
static void static void
parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, 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 #ifdef CONFIG_SOLARIS_X86_PARTITION
Sector sect; Sector sect;
...@@ -244,7 +247,7 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, ...@@ -244,7 +247,7 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev,
*/ */
static void static void
parse_bsd(struct parsed_partitions *state, struct block_device *bdev, 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) int max_partitions)
{ {
Sector sect; Sector sect;
...@@ -263,7 +266,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev, ...@@ -263,7 +266,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev,
if (le16_to_cpu(l->d_npartitions) < max_partitions) if (le16_to_cpu(l->d_npartitions) < max_partitions)
max_partitions = le16_to_cpu(l->d_npartitions); max_partitions = le16_to_cpu(l->d_npartitions);
for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { 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) if (state->next == state->limit)
break; break;
...@@ -290,7 +293,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev, ...@@ -290,7 +293,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev,
static void static void
parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, 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 #ifdef CONFIG_BSD_DISKLABEL
parse_bsd(state, bdev, offset, size, origin, parse_bsd(state, bdev, offset, size, origin,
...@@ -300,7 +303,7 @@ parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, ...@@ -300,7 +303,7 @@ parse_freebsd(struct parsed_partitions *state, struct block_device *bdev,
static void static void
parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, 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 #ifdef CONFIG_BSD_DISKLABEL
parse_bsd(state, bdev, offset, size, origin, parse_bsd(state, bdev, offset, size, origin,
...@@ -310,7 +313,7 @@ parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, ...@@ -310,7 +313,7 @@ parse_netbsd(struct parsed_partitions *state, struct block_device *bdev,
static void static void
parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, 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 #ifdef CONFIG_BSD_DISKLABEL
parse_bsd(state, bdev, offset, size, origin, parse_bsd(state, bdev, offset, size, origin,
...@@ -324,7 +327,7 @@ parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, ...@@ -324,7 +327,7 @@ parse_openbsd(struct parsed_partitions *state, struct block_device *bdev,
*/ */
static void static void
parse_unixware(struct parsed_partitions *state, struct block_device *bdev, 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 #ifdef CONFIG_UNIXWARE_DISKLABEL
Sector sect; Sector sect;
...@@ -348,7 +351,8 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev, ...@@ -348,7 +351,8 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev,
if (p->s_label != UNIXWARE_FS_UNUSED) if (p->s_label != UNIXWARE_FS_UNUSED)
put_partition(state, state->next++, put_partition(state, state->next++,
START_SECT(p), NR_SECTS(p)); le32_to_cpu(p->start_sect),
le32_to_cpu(p->nr_sects));
p++; p++;
} }
put_dev_sector(sect); put_dev_sector(sect);
...@@ -363,7 +367,7 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev, ...@@ -363,7 +367,7 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev,
*/ */
static void static void
parse_minix(struct parsed_partitions *state, struct block_device *bdev, 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 #ifdef CONFIG_MINIX_SUBPARTITION
Sector sect; Sector sect;
...@@ -390,7 +394,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev, ...@@ -390,7 +394,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev,
/* add each partition in use */ /* add each partition in use */
if (SYS_IND(p) == MINIX_PARTITION) if (SYS_IND(p) == MINIX_PARTITION)
put_partition(state, state->next++, put_partition(state, state->next++,
START_SECT(p), NR_SECTS(p)); start_sect(p), nr_sects(p));
} }
printk(" >\n"); printk(" >\n");
} }
...@@ -401,7 +405,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev, ...@@ -401,7 +405,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev,
static struct { static struct {
unsigned char id; unsigned char id;
void (*parse)(struct parsed_partitions *, struct block_device *, void (*parse)(struct parsed_partitions *, struct block_device *,
u32, u32, int); sector_t, sector_t, int);
} subtypes[] = { } subtypes[] = {
{FREEBSD_PARTITION, parse_freebsd}, {FREEBSD_PARTITION, parse_freebsd},
{NETBSD_PARTITION, parse_netbsd}, {NETBSD_PARTITION, parse_netbsd},
...@@ -415,7 +419,7 @@ static struct { ...@@ -415,7 +419,7 @@ static struct {
int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) 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; Sector sect;
unsigned char *data; unsigned char *data;
struct partition *p; struct partition *p;
...@@ -483,8 +487,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) ...@@ -483,8 +487,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
state->next = 5; state->next = 5;
for (slot = 1 ; slot <= 4 ; slot++, p++) { for (slot = 1 ; slot <= 4 ; slot++, p++) {
u32 start = START_SECT(p)*sector_size; sector_t start = start_sect(p)*sector_size;
u32 size = NR_SECTS(p)*sector_size; sector_t size = nr_sects(p)*sector_size;
if (!size) if (!size)
continue; continue;
if (is_extended_partition(p)) { if (is_extended_partition(p)) {
...@@ -513,7 +517,7 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) ...@@ -513,7 +517,7 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
unsigned char id = SYS_IND(p); unsigned char id = SYS_IND(p);
int n; int n;
if (!NR_SECTS(p)) if (!nr_sects(p))
continue; continue;
for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) 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) ...@@ -521,8 +525,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
if (!subtypes[n].parse) if (!subtypes[n].parse)
continue; continue;
subtypes[n].parse(state, bdev, START_SECT(p)*sector_size, subtypes[n].parse(state, bdev, start_sect(p)*sector_size,
NR_SECTS(p)*sector_size, slot); nr_sects(p)*sector_size, slot);
} }
put_dev_sector(sect); put_dev_sector(sect);
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment