move fs/partitions to block/
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
251
block/partitions/Kconfig
Normal file
251
block/partitions/Kconfig
Normal file
@@ -0,0 +1,251 @@
|
||||
#
|
||||
# Partition configuration
|
||||
#
|
||||
config PARTITION_ADVANCED
|
||||
bool "Advanced partition selection"
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned under an operating system running on a different
|
||||
architecture than your Linux system.
|
||||
|
||||
Note that the answer to this question won't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about foreign partitioning schemes.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config ACORN_PARTITION
|
||||
bool "Acorn partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
help
|
||||
Support hard disks partitioned under Acorn operating systems.
|
||||
|
||||
config ACORN_PARTITION_CUMANA
|
||||
bool "Cumana partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using the Cumana interface on Acorn machines.
|
||||
|
||||
config ACORN_PARTITION_EESOX
|
||||
bool "EESOX partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
|
||||
config ACORN_PARTITION_ICS
|
||||
bool "ICS partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using the ICS interface on Acorn machines.
|
||||
|
||||
config ACORN_PARTITION_ADFS
|
||||
bool "Native filecore partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
The Acorn Disc Filing System is the standard file system of the
|
||||
RiscOS operating system which runs on Acorn's ARM-based Risc PC
|
||||
systems and the Acorn Archimedes range of machines. If you say
|
||||
`Y' here, Linux will support disk partitions created under ADFS.
|
||||
|
||||
config ACORN_PARTITION_POWERTEC
|
||||
bool "PowerTec partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Support reading partition tables created on Acorn machines using
|
||||
the PowerTec SCSI drive.
|
||||
|
||||
config ACORN_PARTITION_RISCIX
|
||||
bool "RISCiX partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Once upon a time, there was a native Unix port for the Acorn series
|
||||
of machines called RISCiX. If you say 'Y' here, Linux will be able
|
||||
to read disks partitioned under RISCiX.
|
||||
|
||||
config OSF_PARTITION
|
||||
bool "Alpha OSF partition support" if PARTITION_ADVANCED
|
||||
default y if ALPHA
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned on an Alpha machine.
|
||||
|
||||
config AMIGA_PARTITION
|
||||
bool "Amiga partition table support" if PARTITION_ADVANCED
|
||||
default y if (AMIGA || AFFS_FS=y)
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned under AmigaOS.
|
||||
|
||||
config ATARI_PARTITION
|
||||
bool "Atari partition table support" if PARTITION_ADVANCED
|
||||
default y if ATARI
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned under the Atari OS.
|
||||
|
||||
config IBM_PARTITION
|
||||
bool "IBM disk label and partition support"
|
||||
depends on PARTITION_ADVANCED && S390
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by IBM DASD disks operating under CMS.
|
||||
Otherwise, say N.
|
||||
|
||||
config MAC_PARTITION
|
||||
bool "Macintosh partition map support" if PARTITION_ADVANCED
|
||||
default y if (MAC || PPC_PMAC)
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned on a Macintosh.
|
||||
|
||||
config MSDOS_PARTITION
|
||||
bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED
|
||||
default y
|
||||
help
|
||||
Say Y here.
|
||||
|
||||
config BSD_DISKLABEL
|
||||
bool "BSD disklabel (FreeBSD partition tables) support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
help
|
||||
FreeBSD uses its own hard disk partition scheme on your PC. It
|
||||
requires only one entry in the primary partition table of your disk
|
||||
and manages it similarly to DOS extended partitions, putting in its
|
||||
first sector a new partition table in BSD disklabel format. Saying Y
|
||||
here allows you to read these disklabels and further mount FreeBSD
|
||||
partitions from within Linux if you have also said Y to "UFS
|
||||
file system support", above. If you don't know what all this is
|
||||
about, say N.
|
||||
|
||||
config MINIX_SUBPARTITION
|
||||
bool "Minix subpartition support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
help
|
||||
Minix 2.0.0/2.0.2 subpartition table support for Linux.
|
||||
Say Y here if you want to mount and use Minix 2.0.0/2.0.2
|
||||
subpartitions.
|
||||
|
||||
config SOLARIS_X86_PARTITION
|
||||
bool "Solaris (x86) partition table support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
help
|
||||
Like most systems, Solaris x86 uses its own hard disk partition
|
||||
table format, incompatible with all others. Saying Y here allows you
|
||||
to read these partition tables and further mount Solaris x86
|
||||
partitions from within Linux if you have also said Y to "UFS
|
||||
file system support", above.
|
||||
|
||||
config UNIXWARE_DISKLABEL
|
||||
bool "Unixware slices support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
---help---
|
||||
Like some systems, UnixWare uses its own slice table inside a
|
||||
partition (VTOC - Virtual Table of Contents). Its format is
|
||||
incompatible with all other OSes. Saying Y here allows you to read
|
||||
VTOC and further mount UnixWare partitions read-only from within
|
||||
Linux if you have also said Y to "UFS file system support" or
|
||||
"System V and Coherent file system support", above.
|
||||
|
||||
This is mainly used to carry data from a UnixWare box to your
|
||||
Linux box via a removable medium like magneto-optical, ZIP or
|
||||
removable IDE drives. Note, however, that a good portable way to
|
||||
transport files and directories between unixes (and even other
|
||||
operating systems) is given by the tar program ("man tar" or
|
||||
preferably "info tar").
|
||||
|
||||
If you don't know what all this is about, say N.
|
||||
|
||||
config LDM_PARTITION
|
||||
bool "Windows Logical Disk Manager (Dynamic Disk) support"
|
||||
depends on PARTITION_ADVANCED
|
||||
---help---
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using Windows 2000's/XP's or Vista's Logical Disk
|
||||
Manager. They are also known as "Dynamic Disks".
|
||||
|
||||
Note this driver only supports Dynamic Disks with a protective MBR
|
||||
label, i.e. DOS partition table. It does not support GPT labelled
|
||||
Dynamic Disks yet as can be created with Vista.
|
||||
|
||||
Windows 2000 introduced the concept of Dynamic Disks to get around
|
||||
the limitations of the PC's partitioning scheme. The Logical Disk
|
||||
Manager allows the user to repartition a disk and create spanned,
|
||||
mirrored, striped or RAID volumes, all without the need for
|
||||
rebooting.
|
||||
|
||||
Normal partitions are now called Basic Disks under Windows 2000, XP,
|
||||
and Vista.
|
||||
|
||||
For a fuller description read <file:Documentation/ldm.txt>.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config LDM_DEBUG
|
||||
bool "Windows LDM extra logging"
|
||||
depends on LDM_PARTITION
|
||||
help
|
||||
Say Y here if you would like LDM to log verbosely. This could be
|
||||
helpful if the driver doesn't work as expected and you'd like to
|
||||
report a bug.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SGI_PARTITION
|
||||
bool "SGI partition support" if PARTITION_ADVANCED
|
||||
default y if DEFAULT_SGI_PARTITION
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by SGI machines.
|
||||
|
||||
config ULTRIX_PARTITION
|
||||
bool "Ultrix partition table support" if PARTITION_ADVANCED
|
||||
default y if MACH_DECSTATION
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by DEC (now Compaq) Ultrix machines.
|
||||
Otherwise, say N.
|
||||
|
||||
config SUN_PARTITION
|
||||
bool "Sun partition tables support" if PARTITION_ADVANCED
|
||||
default y if (SPARC || SUN3 || SUN3X)
|
||||
---help---
|
||||
Like most systems, SunOS uses its own hard disk partition table
|
||||
format, incompatible with all others. Saying Y here allows you to
|
||||
read these partition tables and further mount SunOS partitions from
|
||||
within Linux if you have also said Y to "UFS file system support",
|
||||
above. This is mainly used to carry data from a SPARC under SunOS to
|
||||
your Linux box via a removable medium like magneto-optical or ZIP
|
||||
drives; note however that a good portable way to transport files and
|
||||
directories between unixes (and even other operating systems) is
|
||||
given by the tar program ("man tar" or preferably "info tar"). If
|
||||
you don't know what all this is about, say N.
|
||||
|
||||
config KARMA_PARTITION
|
||||
bool "Karma Partition support"
|
||||
depends on PARTITION_ADVANCED
|
||||
help
|
||||
Say Y here if you would like to mount the Rio Karma MP3 player, as it
|
||||
uses a proprietary partition table.
|
||||
|
||||
config EFI_PARTITION
|
||||
bool "EFI GUID Partition support"
|
||||
depends on PARTITION_ADVANCED
|
||||
select CRC32
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using EFI GPT.
|
||||
|
||||
config SYSV68_PARTITION
|
||||
bool "SYSV68 partition table support" if PARTITION_ADVANCED
|
||||
default y if VME
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by Motorola Delta machines (using
|
||||
sysv68).
|
||||
Otherwise, say N.
|
||||
20
block/partitions/Makefile
Normal file
20
block/partitions/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_BLOCK) := check.o
|
||||
|
||||
obj-$(CONFIG_ACORN_PARTITION) += acorn.o
|
||||
obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
|
||||
obj-$(CONFIG_ATARI_PARTITION) += atari.o
|
||||
obj-$(CONFIG_MAC_PARTITION) += mac.o
|
||||
obj-$(CONFIG_LDM_PARTITION) += ldm.o
|
||||
obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
|
||||
obj-$(CONFIG_OSF_PARTITION) += osf.o
|
||||
obj-$(CONFIG_SGI_PARTITION) += sgi.o
|
||||
obj-$(CONFIG_SUN_PARTITION) += sun.o
|
||||
obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
|
||||
obj-$(CONFIG_IBM_PARTITION) += ibm.o
|
||||
obj-$(CONFIG_EFI_PARTITION) += efi.o
|
||||
obj-$(CONFIG_KARMA_PARTITION) += karma.o
|
||||
obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
|
||||
556
block/partitions/acorn.c
Normal file
556
block/partitions/acorn.c
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* linux/fs/partitions/acorn.c
|
||||
*
|
||||
* Copyright (c) 1996-2000 Russell King.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Scan ADFS partitions on hard disk drives. Unfortunately, there
|
||||
* isn't a standard for partitioning drives on Acorn machines, so
|
||||
* every single manufacturer of SCSI and IDE cards created their own
|
||||
* method.
|
||||
*/
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/adfs_fs.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "acorn.h"
|
||||
|
||||
/*
|
||||
* Partition types. (Oh for reusability)
|
||||
*/
|
||||
#define PARTITION_RISCIX_MFM 1
|
||||
#define PARTITION_RISCIX_SCSI 2
|
||||
#define PARTITION_LINUX 9
|
||||
|
||||
#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
|
||||
defined(CONFIG_ACORN_PARTITION_ADFS)
|
||||
static struct adfs_discrecord *
|
||||
adfs_partition(struct parsed_partitions *state, char *name, char *data,
|
||||
unsigned long first_sector, int slot)
|
||||
{
|
||||
struct adfs_discrecord *dr;
|
||||
unsigned int nr_sects;
|
||||
|
||||
if (adfs_checkbblk(data))
|
||||
return NULL;
|
||||
|
||||
dr = (struct adfs_discrecord *)(data + 0x1c0);
|
||||
|
||||
if (dr->disc_size == 0 && dr->disc_size_high == 0)
|
||||
return NULL;
|
||||
|
||||
nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
|
||||
(le32_to_cpu(dr->disc_size) >> 9);
|
||||
|
||||
if (name) {
|
||||
strlcat(state->pp_buf, " [", PAGE_SIZE);
|
||||
strlcat(state->pp_buf, name, PAGE_SIZE);
|
||||
strlcat(state->pp_buf, "]", PAGE_SIZE);
|
||||
}
|
||||
put_partition(state, slot, first_sector, nr_sects);
|
||||
return dr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
|
||||
struct riscix_part {
|
||||
__le32 start;
|
||||
__le32 length;
|
||||
__le32 one;
|
||||
char name[16];
|
||||
};
|
||||
|
||||
struct riscix_record {
|
||||
__le32 magic;
|
||||
#define RISCIX_MAGIC cpu_to_le32(0x4a657320)
|
||||
__le32 date;
|
||||
struct riscix_part part[8];
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
|
||||
defined(CONFIG_ACORN_PARTITION_ADFS)
|
||||
static int riscix_partition(struct parsed_partitions *state,
|
||||
unsigned long first_sect, int slot,
|
||||
unsigned long nr_sects)
|
||||
{
|
||||
Sector sect;
|
||||
struct riscix_record *rr;
|
||||
|
||||
rr = read_part_sector(state, first_sect, §);
|
||||
if (!rr)
|
||||
return -1;
|
||||
|
||||
strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
|
||||
|
||||
|
||||
if (rr->magic == RISCIX_MAGIC) {
|
||||
unsigned long size = nr_sects > 2 ? 2 : nr_sects;
|
||||
int part;
|
||||
|
||||
strlcat(state->pp_buf, " <", PAGE_SIZE);
|
||||
|
||||
put_partition(state, slot++, first_sect, size);
|
||||
for (part = 0; part < 8; part++) {
|
||||
if (rr->part[part].one &&
|
||||
memcmp(rr->part[part].name, "All\0", 4)) {
|
||||
put_partition(state, slot++,
|
||||
le32_to_cpu(rr->part[part].start),
|
||||
le32_to_cpu(rr->part[part].length));
|
||||
strlcat(state->pp_buf, "(", PAGE_SIZE);
|
||||
strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
|
||||
strlcat(state->pp_buf, ")", PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
} else {
|
||||
put_partition(state, slot++, first_sect, nr_sects);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LINUX_NATIVE_MAGIC 0xdeafa1de
|
||||
#define LINUX_SWAP_MAGIC 0xdeafab1e
|
||||
|
||||
struct linux_part {
|
||||
__le32 magic;
|
||||
__le32 start_sect;
|
||||
__le32 nr_sects;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
|
||||
defined(CONFIG_ACORN_PARTITION_ADFS)
|
||||
static int linux_partition(struct parsed_partitions *state,
|
||||
unsigned long first_sect, int slot,
|
||||
unsigned long nr_sects)
|
||||
{
|
||||
Sector sect;
|
||||
struct linux_part *linuxp;
|
||||
unsigned long size = nr_sects > 2 ? 2 : nr_sects;
|
||||
|
||||
strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
|
||||
|
||||
put_partition(state, slot++, first_sect, size);
|
||||
|
||||
linuxp = read_part_sector(state, first_sect, §);
|
||||
if (!linuxp)
|
||||
return -1;
|
||||
|
||||
strlcat(state->pp_buf, " <", PAGE_SIZE);
|
||||
while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
|
||||
linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
put_partition(state, slot++, first_sect +
|
||||
le32_to_cpu(linuxp->start_sect),
|
||||
le32_to_cpu(linuxp->nr_sects));
|
||||
linuxp ++;
|
||||
}
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
|
||||
put_dev_sector(sect);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_CUMANA
|
||||
int adfspart_check_CUMANA(struct parsed_partitions *state)
|
||||
{
|
||||
unsigned long first_sector = 0;
|
||||
unsigned int start_blk = 0;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
char *name = "CUMANA/ADFS";
|
||||
int first = 1;
|
||||
int slot = 1;
|
||||
|
||||
/*
|
||||
* Try Cumana style partitions - sector 6 contains ADFS boot block
|
||||
* with pointer to next 'drive'.
|
||||
*
|
||||
* There are unknowns in this code - is the 'cylinder number' of the
|
||||
* next partition relative to the start of this one - I'm assuming
|
||||
* it is.
|
||||
*
|
||||
* Also, which ID did Cumana use?
|
||||
*
|
||||
* This is totally unfinished, and will require more work to get it
|
||||
* going. Hence it is totally untested.
|
||||
*/
|
||||
do {
|
||||
struct adfs_discrecord *dr;
|
||||
unsigned int nr_sects;
|
||||
|
||||
data = read_part_sector(state, start_blk * 2 + 6, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
dr = adfs_partition(state, name, data, first_sector, slot++);
|
||||
if (!dr)
|
||||
break;
|
||||
|
||||
name = NULL;
|
||||
|
||||
nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
|
||||
(dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
|
||||
dr->secspertrack;
|
||||
|
||||
if (!nr_sects)
|
||||
break;
|
||||
|
||||
first = 0;
|
||||
first_sector += nr_sects;
|
||||
start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
|
||||
nr_sects = 0; /* hmm - should be partition size */
|
||||
|
||||
switch (data[0x1fc] & 15) {
|
||||
case 0: /* No partition / ADFS? */
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
case PARTITION_RISCIX_SCSI:
|
||||
/* RISCiX - we don't know how to find the next one. */
|
||||
slot = riscix_partition(state, first_sector, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PARTITION_LINUX:
|
||||
slot = linux_partition(state, first_sector, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
if (slot == -1)
|
||||
return -1;
|
||||
} while (1);
|
||||
put_dev_sector(sect);
|
||||
return first ? 0 : 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_ADFS
|
||||
/*
|
||||
* Purpose: allocate ADFS partitions.
|
||||
*
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
*
|
||||
* Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
|
||||
*
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition on first drive.
|
||||
* hda2 = non-ADFS partition.
|
||||
*/
|
||||
int adfspart_check_ADFS(struct parsed_partitions *state)
|
||||
{
|
||||
unsigned long start_sect, nr_sects, sectscyl, heads;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct adfs_discrecord *dr;
|
||||
unsigned char id;
|
||||
int slot = 1;
|
||||
|
||||
data = read_part_sector(state, 6, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
dr = adfs_partition(state, "ADFS", data, 0, slot++);
|
||||
if (!dr) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
heads = dr->heads + ((dr->lowsector >> 6) & 1);
|
||||
sectscyl = dr->secspertrack * heads;
|
||||
start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
|
||||
id = data[0x1fc] & 15;
|
||||
put_dev_sector(sect);
|
||||
|
||||
/*
|
||||
* Work out start of non-adfs partition.
|
||||
*/
|
||||
nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect;
|
||||
|
||||
if (start_sect) {
|
||||
switch (id) {
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
case PARTITION_RISCIX_SCSI:
|
||||
case PARTITION_RISCIX_MFM:
|
||||
slot = riscix_partition(state, start_sect, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PARTITION_LINUX:
|
||||
slot = linux_partition(state, start_sect, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_ICS
|
||||
|
||||
struct ics_part {
|
||||
__le32 start;
|
||||
__le32 size;
|
||||
};
|
||||
|
||||
static int adfspart_check_ICSLinux(struct parsed_partitions *state,
|
||||
unsigned long block)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data = read_part_sector(state, block, §);
|
||||
int result = 0;
|
||||
|
||||
if (data) {
|
||||
if (memcmp(data, "LinuxPart", 9) == 0)
|
||||
result = 1;
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a valid ICS partition using the checksum.
|
||||
*/
|
||||
static inline int valid_ics_sector(const unsigned char *data)
|
||||
{
|
||||
unsigned long sum;
|
||||
int i;
|
||||
|
||||
for (i = 0, sum = 0x50617274; i < 508; i++)
|
||||
sum += data[i];
|
||||
|
||||
sum -= le32_to_cpu(*(__le32 *)(&data[508]));
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Purpose: allocate ICS partitions.
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
* Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition 0 on first drive.
|
||||
* hda2 = ADFS partition 1 on first drive.
|
||||
* ..etc..
|
||||
*/
|
||||
int adfspart_check_ICS(struct parsed_partitions *state)
|
||||
{
|
||||
const unsigned char *data;
|
||||
const struct ics_part *p;
|
||||
int slot;
|
||||
Sector sect;
|
||||
|
||||
/*
|
||||
* Try ICS style partitions - sector 0 contains partition info.
|
||||
*/
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (!valid_ics_sector(data)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
|
||||
|
||||
for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
|
||||
u32 start = le32_to_cpu(p->start);
|
||||
s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
|
||||
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Negative sizes tell the RISC OS ICS driver to ignore
|
||||
* this partition - in effect it says that this does not
|
||||
* contain an ADFS filesystem.
|
||||
*/
|
||||
if (size < 0) {
|
||||
size = -size;
|
||||
|
||||
/*
|
||||
* Our own extension - We use the first sector
|
||||
* of the partition to identify what type this
|
||||
* partition is. We must not make this visible
|
||||
* to the filesystem.
|
||||
*/
|
||||
if (size > 1 && adfspart_check_ICSLinux(state, start)) {
|
||||
start += 1;
|
||||
size -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
put_partition(state, slot++, start, size);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
|
||||
struct ptec_part {
|
||||
__le32 unused1;
|
||||
__le32 unused2;
|
||||
__le32 start;
|
||||
__le32 size;
|
||||
__le32 unused5;
|
||||
char type[8];
|
||||
};
|
||||
|
||||
static inline int valid_ptec_sector(const unsigned char *data)
|
||||
{
|
||||
unsigned char checksum = 0x2a;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If it looks like a PC/BIOS partition, then it
|
||||
* probably isn't PowerTec.
|
||||
*/
|
||||
if (data[510] == 0x55 && data[511] == 0xaa)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 511; i++)
|
||||
checksum += data[i];
|
||||
|
||||
return checksum == data[511];
|
||||
}
|
||||
|
||||
/*
|
||||
* Purpose: allocate ICS partitions.
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
* Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition 0 on first drive.
|
||||
* hda2 = ADFS partition 1 on first drive.
|
||||
* ..etc..
|
||||
*/
|
||||
int adfspart_check_POWERTEC(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
const unsigned char *data;
|
||||
const struct ptec_part *p;
|
||||
int slot = 1;
|
||||
int i;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (!valid_ptec_sector(data)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
|
||||
|
||||
for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
|
||||
u32 start = le32_to_cpu(p->start);
|
||||
u32 size = le32_to_cpu(p->size);
|
||||
|
||||
if (size)
|
||||
put_partition(state, slot++, start, size);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_EESOX
|
||||
struct eesox_part {
|
||||
char magic[6];
|
||||
char name[10];
|
||||
__le32 start;
|
||||
__le32 unused6;
|
||||
__le32 unused7;
|
||||
__le32 unused8;
|
||||
};
|
||||
|
||||
/*
|
||||
* Guess who created this format?
|
||||
*/
|
||||
static const char eesox_name[] = {
|
||||
'N', 'e', 'i', 'l', ' ',
|
||||
'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
|
||||
};
|
||||
|
||||
/*
|
||||
* EESOX SCSI partition format.
|
||||
*
|
||||
* This is a goddamned awful partition format. We don't seem to store
|
||||
* the size of the partition in this table, only the start addresses.
|
||||
*
|
||||
* There are two possibilities where the size comes from:
|
||||
* 1. The individual ADFS boot block entries that are placed on the disk.
|
||||
* 2. The start address of the next entry.
|
||||
*/
|
||||
int adfspart_check_EESOX(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
const unsigned char *data;
|
||||
unsigned char buffer[256];
|
||||
struct eesox_part *p;
|
||||
sector_t start = 0;
|
||||
int i, slot = 1;
|
||||
|
||||
data = read_part_sector(state, 7, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* "Decrypt" the partition table. God knows why...
|
||||
*/
|
||||
for (i = 0; i < 256; i++)
|
||||
buffer[i] = data[i] ^ eesox_name[i & 15];
|
||||
|
||||
put_dev_sector(sect);
|
||||
|
||||
for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
|
||||
sector_t next;
|
||||
|
||||
if (memcmp(p->magic, "Eesox", 6))
|
||||
break;
|
||||
|
||||
next = le32_to_cpu(p->start);
|
||||
if (i)
|
||||
put_partition(state, slot++, start, next - start);
|
||||
start = next;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
sector_t size;
|
||||
|
||||
size = get_capacity(state->bdev->bd_disk);
|
||||
put_partition(state, slot++, start, size - start);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
}
|
||||
|
||||
return i ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
14
block/partitions/acorn.h
Normal file
14
block/partitions/acorn.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* linux/fs/partitions/acorn.h
|
||||
*
|
||||
* Copyright (C) 1996-2001 Russell King.
|
||||
*
|
||||
* I _hate_ this partitioning mess - why can't we have one defined
|
||||
* format, and everyone stick to it?
|
||||
*/
|
||||
|
||||
int adfspart_check_CUMANA(struct parsed_partitions *state);
|
||||
int adfspart_check_ADFS(struct parsed_partitions *state);
|
||||
int adfspart_check_ICS(struct parsed_partitions *state);
|
||||
int adfspart_check_POWERTEC(struct parsed_partitions *state);
|
||||
int adfspart_check_EESOX(struct parsed_partitions *state);
|
||||
139
block/partitions/amiga.c
Normal file
139
block/partitions/amiga.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* fs/partitions/amiga.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/affs_hardblocks.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "amiga.h"
|
||||
|
||||
static __inline__ u32
|
||||
checksum_block(__be32 *m, int size)
|
||||
{
|
||||
u32 sum = 0;
|
||||
|
||||
while (size--)
|
||||
sum += be32_to_cpu(*m++);
|
||||
return sum;
|
||||
}
|
||||
|
||||
int amiga_partition(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct RigidDiskBlock *rdb;
|
||||
struct PartitionBlock *pb;
|
||||
int start_sect, nr_sects, blk, part, res = 0;
|
||||
int blksize = 1; /* Multiplier for disk block size */
|
||||
int slot = 1;
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
for (blk = 0; ; blk++, put_dev_sector(sect)) {
|
||||
if (blk == RDB_ALLOCATION_LIMIT)
|
||||
goto rdb_done;
|
||||
data = read_part_sector(state, blk, §);
|
||||
if (!data) {
|
||||
if (warn_no_part)
|
||||
printk("Dev %s: unable to read RDB block %d\n",
|
||||
bdevname(state->bdev, b), blk);
|
||||
res = -1;
|
||||
goto rdb_done;
|
||||
}
|
||||
if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
|
||||
continue;
|
||||
|
||||
rdb = (struct RigidDiskBlock *)data;
|
||||
if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
|
||||
break;
|
||||
/* Try again with 0xdc..0xdf zeroed, Windows might have
|
||||
* trashed it.
|
||||
*/
|
||||
*(__be32 *)(data+0xdc) = 0;
|
||||
if (checksum_block((__be32 *)data,
|
||||
be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
|
||||
printk("Warning: Trashed word at 0xd0 in block %d "
|
||||
"ignored in checksum calculation\n",blk);
|
||||
break;
|
||||
}
|
||||
|
||||
printk("Dev %s: RDB in block %d has bad checksum\n",
|
||||
bdevname(state->bdev, b), blk);
|
||||
}
|
||||
|
||||
/* blksize is blocks per 512 byte standard block */
|
||||
blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512;
|
||||
|
||||
{
|
||||
char tmp[7 + 10 + 1 + 1];
|
||||
|
||||
/* Be more informative */
|
||||
snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
blk = be32_to_cpu(rdb->rdb_PartitionList);
|
||||
put_dev_sector(sect);
|
||||
for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
|
||||
blk *= blksize; /* Read in terms partition table understands */
|
||||
data = read_part_sector(state, blk, §);
|
||||
if (!data) {
|
||||
if (warn_no_part)
|
||||
printk("Dev %s: unable to read partition block %d\n",
|
||||
bdevname(state->bdev, b), blk);
|
||||
res = -1;
|
||||
goto rdb_done;
|
||||
}
|
||||
pb = (struct PartitionBlock *)data;
|
||||
blk = be32_to_cpu(pb->pb_Next);
|
||||
if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
|
||||
continue;
|
||||
if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
|
||||
continue;
|
||||
|
||||
/* Tell Kernel about it */
|
||||
|
||||
nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
|
||||
be32_to_cpu(pb->pb_Environment[9])) *
|
||||
be32_to_cpu(pb->pb_Environment[3]) *
|
||||
be32_to_cpu(pb->pb_Environment[5]) *
|
||||
blksize;
|
||||
if (!nr_sects)
|
||||
continue;
|
||||
start_sect = be32_to_cpu(pb->pb_Environment[9]) *
|
||||
be32_to_cpu(pb->pb_Environment[3]) *
|
||||
be32_to_cpu(pb->pb_Environment[5]) *
|
||||
blksize;
|
||||
put_partition(state,slot++,start_sect,nr_sects);
|
||||
{
|
||||
/* Be even more informative to aid mounting */
|
||||
char dostype[4];
|
||||
char tmp[42];
|
||||
|
||||
__be32 *dt = (__be32 *)dostype;
|
||||
*dt = pb->pb_Environment[16];
|
||||
if (dostype[3] < ' ')
|
||||
snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)",
|
||||
dostype[0], dostype[1],
|
||||
dostype[2], dostype[3] + '@' );
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), " (%c%c%c%c)",
|
||||
dostype[0], dostype[1],
|
||||
dostype[2], dostype[3]);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
snprintf(tmp, sizeof(tmp), "(res %d spb %d)",
|
||||
be32_to_cpu(pb->pb_Environment[6]),
|
||||
be32_to_cpu(pb->pb_Environment[4]));
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
res = 1;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
rdb_done:
|
||||
return res;
|
||||
}
|
||||
6
block/partitions/amiga.h
Normal file
6
block/partitions/amiga.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* fs/partitions/amiga.h
|
||||
*/
|
||||
|
||||
int amiga_partition(struct parsed_partitions *state);
|
||||
|
||||
149
block/partitions/atari.c
Normal file
149
block/partitions/atari.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* fs/partitions/atari.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include "check.h"
|
||||
#include "atari.h"
|
||||
|
||||
/* ++guenther: this should be settable by the user ("make config")?.
|
||||
*/
|
||||
#define ICD_PARTS
|
||||
|
||||
/* check if a partition entry looks valid -- Atari format is assumed if at
|
||||
least one of the primary entries is ok this way */
|
||||
#define VALID_PARTITION(pi,hdsiz) \
|
||||
(((pi)->flg & 1) && \
|
||||
isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
|
||||
be32_to_cpu((pi)->st) <= (hdsiz) && \
|
||||
be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
|
||||
|
||||
static inline int OK_id(char *s)
|
||||
{
|
||||
return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 ||
|
||||
memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 ||
|
||||
memcmp (s, "RAW", 3) == 0 ;
|
||||
}
|
||||
|
||||
int atari_partition(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
struct rootsector *rs;
|
||||
struct partition_info *pi;
|
||||
u32 extensect;
|
||||
u32 hd_size;
|
||||
int slot;
|
||||
#ifdef ICD_PARTS
|
||||
int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
|
||||
#endif
|
||||
|
||||
rs = read_part_sector(state, 0, §);
|
||||
if (!rs)
|
||||
return -1;
|
||||
|
||||
/* Verify this is an Atari rootsector: */
|
||||
hd_size = state->bdev->bd_inode->i_size >> 9;
|
||||
if (!VALID_PARTITION(&rs->part[0], hd_size) &&
|
||||
!VALID_PARTITION(&rs->part[1], hd_size) &&
|
||||
!VALID_PARTITION(&rs->part[2], hd_size) &&
|
||||
!VALID_PARTITION(&rs->part[3], hd_size)) {
|
||||
/*
|
||||
* if there's no valid primary partition, assume that no Atari
|
||||
* format partition table (there's no reliable magic or the like
|
||||
* :-()
|
||||
*/
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pi = &rs->part[0];
|
||||
strlcat(state->pp_buf, " AHDI", PAGE_SIZE);
|
||||
for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) {
|
||||
struct rootsector *xrs;
|
||||
Sector sect2;
|
||||
ulong partsect;
|
||||
|
||||
if ( !(pi->flg & 1) )
|
||||
continue;
|
||||
/* active partition */
|
||||
if (memcmp (pi->id, "XGM", 3) != 0) {
|
||||
/* we don't care about other id's */
|
||||
put_partition (state, slot, be32_to_cpu(pi->st),
|
||||
be32_to_cpu(pi->siz));
|
||||
continue;
|
||||
}
|
||||
/* extension partition */
|
||||
#ifdef ICD_PARTS
|
||||
part_fmt = 1;
|
||||
#endif
|
||||
strlcat(state->pp_buf, " XGM<", PAGE_SIZE);
|
||||
partsect = extensect = be32_to_cpu(pi->st);
|
||||
while (1) {
|
||||
xrs = read_part_sector(state, partsect, §2);
|
||||
if (!xrs) {
|
||||
printk (" block %ld read failed\n", partsect);
|
||||
put_dev_sector(sect);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ++roman: sanity check: bit 0 of flg field must be set */
|
||||
if (!(xrs->part[0].flg & 1)) {
|
||||
printk( "\nFirst sub-partition in extended partition is not valid!\n" );
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
|
||||
put_partition(state, slot,
|
||||
partsect + be32_to_cpu(xrs->part[0].st),
|
||||
be32_to_cpu(xrs->part[0].siz));
|
||||
|
||||
if (!(xrs->part[1].flg & 1)) {
|
||||
/* end of linked partition list */
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
|
||||
printk("\nID of extended partition is not XGM!\n");
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
|
||||
partsect = be32_to_cpu(xrs->part[1].st) + extensect;
|
||||
put_dev_sector(sect2);
|
||||
if (++slot == state->limit) {
|
||||
printk( "\nMaximum number of partitions reached!\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
}
|
||||
#ifdef ICD_PARTS
|
||||
if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */
|
||||
pi = &rs->icdpart[0];
|
||||
/* sanity check: no ICD format if first partition invalid */
|
||||
if (OK_id(pi->id)) {
|
||||
strlcat(state->pp_buf, " ICD<", PAGE_SIZE);
|
||||
for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) {
|
||||
/* accept only GEM,BGM,RAW,LNX,SWP partitions */
|
||||
if (!((pi->flg & 1) && OK_id(pi->id)))
|
||||
continue;
|
||||
part_fmt = 2;
|
||||
put_partition (state, slot,
|
||||
be32_to_cpu(pi->st),
|
||||
be32_to_cpu(pi->siz));
|
||||
}
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
put_dev_sector(sect);
|
||||
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
34
block/partitions/atari.h
Normal file
34
block/partitions/atari.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* fs/partitions/atari.h
|
||||
* Moved by Russell King from:
|
||||
*
|
||||
* linux/include/linux/atari_rootsec.h
|
||||
* definitions for Atari Rootsector layout
|
||||
* by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
|
||||
*
|
||||
* modified for ICD/Supra partitioning scheme restricted to at most 12
|
||||
* partitions
|
||||
* by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
|
||||
*/
|
||||
|
||||
struct partition_info
|
||||
{
|
||||
u8 flg; /* bit 0: active; bit 7: bootable */
|
||||
char id[3]; /* "GEM", "BGM", "XGM", or other */
|
||||
__be32 st; /* start of partition */
|
||||
__be32 siz; /* length of partition */
|
||||
};
|
||||
|
||||
struct rootsector
|
||||
{
|
||||
char unused[0x156]; /* room for boot code */
|
||||
struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
|
||||
char unused2[0xc];
|
||||
u32 hd_siz; /* size of disk in blocks */
|
||||
struct partition_info part[4];
|
||||
u32 bsl_st; /* start of bad sector list */
|
||||
u32 bsl_cnt; /* length of bad sector list */
|
||||
u16 checksum; /* checksum for bootable disks */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
int atari_partition(struct parsed_partitions *state);
|
||||
687
block/partitions/check.c
Normal file
687
block/partitions/check.c
Normal file
@@ -0,0 +1,687 @@
|
||||
/*
|
||||
* fs/partitions/check.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*
|
||||
* We now have independent partition support from the
|
||||
* block drivers, which allows all the partition code to
|
||||
* be grouped in one location, and it to be mostly self
|
||||
* contained.
|
||||
*
|
||||
* Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/blktrace_api.h>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
#include "acorn.h"
|
||||
#include "amiga.h"
|
||||
#include "atari.h"
|
||||
#include "ldm.h"
|
||||
#include "mac.h"
|
||||
#include "msdos.h"
|
||||
#include "osf.h"
|
||||
#include "sgi.h"
|
||||
#include "sun.h"
|
||||
#include "ibm.h"
|
||||
#include "ultrix.h"
|
||||
#include "efi.h"
|
||||
#include "karma.h"
|
||||
#include "sysv68.h"
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_MD
|
||||
extern void md_autodetect_dev(dev_t dev);
|
||||
#endif
|
||||
|
||||
int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
|
||||
|
||||
static int (*check_part[])(struct parsed_partitions *) = {
|
||||
/*
|
||||
* Probe partition formats with tables at disk address 0
|
||||
* that also have an ADFS boot block at 0xdc0.
|
||||
*/
|
||||
#ifdef CONFIG_ACORN_PARTITION_ICS
|
||||
adfspart_check_ICS,
|
||||
#endif
|
||||
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
|
||||
adfspart_check_POWERTEC,
|
||||
#endif
|
||||
#ifdef CONFIG_ACORN_PARTITION_EESOX
|
||||
adfspart_check_EESOX,
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now move on to formats that only have partition info at
|
||||
* disk address 0xdc0. Since these may also have stale
|
||||
* PC/BIOS partition tables, they need to come before
|
||||
* the msdos entry.
|
||||
*/
|
||||
#ifdef CONFIG_ACORN_PARTITION_CUMANA
|
||||
adfspart_check_CUMANA,
|
||||
#endif
|
||||
#ifdef CONFIG_ACORN_PARTITION_ADFS
|
||||
adfspart_check_ADFS,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFI_PARTITION
|
||||
efi_partition, /* this must come before msdos */
|
||||
#endif
|
||||
#ifdef CONFIG_SGI_PARTITION
|
||||
sgi_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_LDM_PARTITION
|
||||
ldm_partition, /* this must come before msdos */
|
||||
#endif
|
||||
#ifdef CONFIG_MSDOS_PARTITION
|
||||
msdos_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_OSF_PARTITION
|
||||
osf_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_SUN_PARTITION
|
||||
sun_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_AMIGA_PARTITION
|
||||
amiga_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_ATARI_PARTITION
|
||||
atari_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_MAC_PARTITION
|
||||
mac_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_ULTRIX_PARTITION
|
||||
ultrix_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_IBM_PARTITION
|
||||
ibm_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_KARMA_PARTITION
|
||||
karma_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_SYSV68_PARTITION
|
||||
sysv68_partition,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* disk_name() is used by partition check code and the genhd driver.
|
||||
* It formats the devicename of the indicated disk into
|
||||
* the supplied buffer (of size at least 32), and returns
|
||||
* a pointer to that same buffer (for convenience).
|
||||
*/
|
||||
|
||||
char *disk_name(struct gendisk *hd, int partno, char *buf)
|
||||
{
|
||||
if (!partno)
|
||||
snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
|
||||
else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
|
||||
snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
|
||||
else
|
||||
snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *bdevname(struct block_device *bdev, char *buf)
|
||||
{
|
||||
return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(bdevname);
|
||||
|
||||
/*
|
||||
* There's very little reason to use this, you should really
|
||||
* have a struct block_device just about everywhere and use
|
||||
* bdevname() instead.
|
||||
*/
|
||||
const char *__bdevname(dev_t dev, char *buffer)
|
||||
{
|
||||
scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)",
|
||||
MAJOR(dev), MINOR(dev));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(__bdevname);
|
||||
|
||||
static struct parsed_partitions *
|
||||
check_partition(struct gendisk *hd, struct block_device *bdev)
|
||||
{
|
||||
struct parsed_partitions *state;
|
||||
int i, res, err;
|
||||
|
||||
state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!state->pp_buf) {
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
state->pp_buf[0] = '\0';
|
||||
|
||||
state->bdev = bdev;
|
||||
disk_name(hd, 0, state->name);
|
||||
snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
|
||||
if (isdigit(state->name[strlen(state->name)-1]))
|
||||
sprintf(state->name, "p");
|
||||
|
||||
state->limit = disk_max_parts(hd);
|
||||
i = res = err = 0;
|
||||
while (!res && check_part[i]) {
|
||||
memset(&state->parts, 0, sizeof(state->parts));
|
||||
res = check_part[i++](state);
|
||||
if (res < 0) {
|
||||
/* We have hit an I/O error which we don't report now.
|
||||
* But record it, and let the others do their job.
|
||||
*/
|
||||
err = res;
|
||||
res = 0;
|
||||
}
|
||||
|
||||
}
|
||||
if (res > 0) {
|
||||
printk(KERN_INFO "%s", state->pp_buf);
|
||||
|
||||
free_page((unsigned long)state->pp_buf);
|
||||
return state;
|
||||
}
|
||||
if (state->access_beyond_eod)
|
||||
err = -ENOSPC;
|
||||
if (err)
|
||||
/* The partition is unrecognized. So report I/O errors if there were any */
|
||||
res = err;
|
||||
if (!res)
|
||||
strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE);
|
||||
else if (warn_no_part)
|
||||
strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE);
|
||||
|
||||
printk(KERN_INFO "%s", state->pp_buf);
|
||||
|
||||
free_page((unsigned long)state->pp_buf);
|
||||
kfree(state);
|
||||
return ERR_PTR(res);
|
||||
}
|
||||
|
||||
static ssize_t part_partition_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", p->partno);
|
||||
}
|
||||
|
||||
static ssize_t part_start_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
|
||||
return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
|
||||
}
|
||||
|
||||
ssize_t part_size_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
|
||||
}
|
||||
|
||||
static ssize_t part_ro_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
return sprintf(buf, "%d\n", p->policy ? 1 : 0);
|
||||
}
|
||||
|
||||
static ssize_t part_alignment_offset_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
|
||||
}
|
||||
|
||||
static ssize_t part_discard_alignment_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
return sprintf(buf, "%u\n", p->discard_alignment);
|
||||
}
|
||||
|
||||
ssize_t part_stat_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
int cpu;
|
||||
|
||||
cpu = part_stat_lock();
|
||||
part_round_stats(cpu, p);
|
||||
part_stat_unlock();
|
||||
return sprintf(buf,
|
||||
"%8lu %8lu %8llu %8u "
|
||||
"%8lu %8lu %8llu %8u "
|
||||
"%8u %8u %8u"
|
||||
"\n",
|
||||
part_stat_read(p, ios[READ]),
|
||||
part_stat_read(p, merges[READ]),
|
||||
(unsigned long long)part_stat_read(p, sectors[READ]),
|
||||
jiffies_to_msecs(part_stat_read(p, ticks[READ])),
|
||||
part_stat_read(p, ios[WRITE]),
|
||||
part_stat_read(p, merges[WRITE]),
|
||||
(unsigned long long)part_stat_read(p, sectors[WRITE]),
|
||||
jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
|
||||
part_in_flight(p),
|
||||
jiffies_to_msecs(part_stat_read(p, io_ticks)),
|
||||
jiffies_to_msecs(part_stat_read(p, time_in_queue)));
|
||||
}
|
||||
|
||||
ssize_t part_inflight_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
|
||||
return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]),
|
||||
atomic_read(&p->in_flight[1]));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
||||
ssize_t part_fail_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", p->make_it_fail);
|
||||
}
|
||||
|
||||
ssize_t part_fail_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
int i;
|
||||
|
||||
if (count > 0 && sscanf(buf, "%d", &i) > 0)
|
||||
p->make_it_fail = (i == 0) ? 0 : 1;
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
|
||||
static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
|
||||
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
|
||||
static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL);
|
||||
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
|
||||
static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
|
||||
NULL);
|
||||
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
|
||||
static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
|
||||
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
||||
static struct device_attribute dev_attr_fail =
|
||||
__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
|
||||
#endif
|
||||
|
||||
static struct attribute *part_attrs[] = {
|
||||
&dev_attr_partition.attr,
|
||||
&dev_attr_start.attr,
|
||||
&dev_attr_size.attr,
|
||||
&dev_attr_ro.attr,
|
||||
&dev_attr_alignment_offset.attr,
|
||||
&dev_attr_discard_alignment.attr,
|
||||
&dev_attr_stat.attr,
|
||||
&dev_attr_inflight.attr,
|
||||
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
||||
&dev_attr_fail.attr,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group part_attr_group = {
|
||||
.attrs = part_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *part_attr_groups[] = {
|
||||
&part_attr_group,
|
||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||
&blk_trace_attr_group,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static void part_release(struct device *dev)
|
||||
{
|
||||
struct hd_struct *p = dev_to_part(dev);
|
||||
free_part_stats(p);
|
||||
free_part_info(p);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
struct device_type part_type = {
|
||||
.name = "partition",
|
||||
.groups = part_attr_groups,
|
||||
.release = part_release,
|
||||
};
|
||||
|
||||
static void delete_partition_rcu_cb(struct rcu_head *head)
|
||||
{
|
||||
struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
|
||||
|
||||
part->start_sect = 0;
|
||||
part->nr_sects = 0;
|
||||
part_stat_set_all(part, 0);
|
||||
put_device(part_to_dev(part));
|
||||
}
|
||||
|
||||
void __delete_partition(struct hd_struct *part)
|
||||
{
|
||||
call_rcu(&part->rcu_head, delete_partition_rcu_cb);
|
||||
}
|
||||
|
||||
void delete_partition(struct gendisk *disk, int partno)
|
||||
{
|
||||
struct disk_part_tbl *ptbl = disk->part_tbl;
|
||||
struct hd_struct *part;
|
||||
|
||||
if (partno >= ptbl->len)
|
||||
return;
|
||||
|
||||
part = ptbl->part[partno];
|
||||
if (!part)
|
||||
return;
|
||||
|
||||
blk_free_devt(part_devt(part));
|
||||
rcu_assign_pointer(ptbl->part[partno], NULL);
|
||||
rcu_assign_pointer(ptbl->last_lookup, NULL);
|
||||
kobject_put(part->holder_dir);
|
||||
device_del(part_to_dev(part));
|
||||
|
||||
hd_struct_put(part);
|
||||
}
|
||||
|
||||
static ssize_t whole_disk_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
|
||||
whole_disk_show, NULL);
|
||||
|
||||
struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
||||
sector_t start, sector_t len, int flags,
|
||||
struct partition_meta_info *info)
|
||||
{
|
||||
struct hd_struct *p;
|
||||
dev_t devt = MKDEV(0, 0);
|
||||
struct device *ddev = disk_to_dev(disk);
|
||||
struct device *pdev;
|
||||
struct disk_part_tbl *ptbl;
|
||||
const char *dname;
|
||||
int err;
|
||||
|
||||
err = disk_expand_part_tbl(disk, partno);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
ptbl = disk->part_tbl;
|
||||
|
||||
if (ptbl->part[partno])
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
if (!init_part_stats(p)) {
|
||||
err = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
pdev = part_to_dev(p);
|
||||
|
||||
p->start_sect = start;
|
||||
p->alignment_offset =
|
||||
queue_limit_alignment_offset(&disk->queue->limits, start);
|
||||
p->discard_alignment =
|
||||
queue_limit_discard_alignment(&disk->queue->limits, start);
|
||||
p->nr_sects = len;
|
||||
p->partno = partno;
|
||||
p->policy = get_disk_ro(disk);
|
||||
|
||||
if (info) {
|
||||
struct partition_meta_info *pinfo = alloc_part_info(disk);
|
||||
if (!pinfo)
|
||||
goto out_free_stats;
|
||||
memcpy(pinfo, info, sizeof(*info));
|
||||
p->info = pinfo;
|
||||
}
|
||||
|
||||
dname = dev_name(ddev);
|
||||
if (isdigit(dname[strlen(dname) - 1]))
|
||||
dev_set_name(pdev, "%sp%d", dname, partno);
|
||||
else
|
||||
dev_set_name(pdev, "%s%d", dname, partno);
|
||||
|
||||
device_initialize(pdev);
|
||||
pdev->class = &block_class;
|
||||
pdev->type = &part_type;
|
||||
pdev->parent = ddev;
|
||||
|
||||
err = blk_alloc_devt(p, &devt);
|
||||
if (err)
|
||||
goto out_free_info;
|
||||
pdev->devt = devt;
|
||||
|
||||
/* delay uevent until 'holders' subdir is created */
|
||||
dev_set_uevent_suppress(pdev, 1);
|
||||
err = device_add(pdev);
|
||||
if (err)
|
||||
goto out_put;
|
||||
|
||||
err = -ENOMEM;
|
||||
p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
|
||||
if (!p->holder_dir)
|
||||
goto out_del;
|
||||
|
||||
dev_set_uevent_suppress(pdev, 0);
|
||||
if (flags & ADDPART_FLAG_WHOLEDISK) {
|
||||
err = device_create_file(pdev, &dev_attr_whole_disk);
|
||||
if (err)
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
/* everything is up and running, commence */
|
||||
rcu_assign_pointer(ptbl->part[partno], p);
|
||||
|
||||
/* suppress uevent if the disk suppresses it */
|
||||
if (!dev_get_uevent_suppress(ddev))
|
||||
kobject_uevent(&pdev->kobj, KOBJ_ADD);
|
||||
|
||||
hd_ref_init(p);
|
||||
return p;
|
||||
|
||||
out_free_info:
|
||||
free_part_info(p);
|
||||
out_free_stats:
|
||||
free_part_stats(p);
|
||||
out_free:
|
||||
kfree(p);
|
||||
return ERR_PTR(err);
|
||||
out_del:
|
||||
kobject_put(p->holder_dir);
|
||||
device_del(pdev);
|
||||
out_put:
|
||||
put_device(pdev);
|
||||
blk_free_devt(devt);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static bool disk_unlock_native_capacity(struct gendisk *disk)
|
||||
{
|
||||
const struct block_device_operations *bdops = disk->fops;
|
||||
|
||||
if (bdops->unlock_native_capacity &&
|
||||
!(disk->flags & GENHD_FL_NATIVE_CAPACITY)) {
|
||||
printk(KERN_CONT "enabling native capacity\n");
|
||||
bdops->unlock_native_capacity(disk);
|
||||
disk->flags |= GENHD_FL_NATIVE_CAPACITY;
|
||||
return true;
|
||||
} else {
|
||||
printk(KERN_CONT "truncated\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
|
||||
{
|
||||
struct parsed_partitions *state = NULL;
|
||||
struct disk_part_iter piter;
|
||||
struct hd_struct *part;
|
||||
int p, highest, res;
|
||||
rescan:
|
||||
if (state && !IS_ERR(state)) {
|
||||
kfree(state);
|
||||
state = NULL;
|
||||
}
|
||||
|
||||
if (bdev->bd_part_count)
|
||||
return -EBUSY;
|
||||
res = invalidate_partition(disk, 0);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
|
||||
while ((part = disk_part_iter_next(&piter)))
|
||||
delete_partition(disk, part->partno);
|
||||
disk_part_iter_exit(&piter);
|
||||
|
||||
if (disk->fops->revalidate_disk)
|
||||
disk->fops->revalidate_disk(disk);
|
||||
check_disk_size_change(disk, bdev);
|
||||
bdev->bd_invalidated = 0;
|
||||
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
|
||||
return 0;
|
||||
if (IS_ERR(state)) {
|
||||
/*
|
||||
* I/O error reading the partition table. If any
|
||||
* partition code tried to read beyond EOD, retry
|
||||
* after unlocking native capacity.
|
||||
*/
|
||||
if (PTR_ERR(state) == -ENOSPC) {
|
||||
printk(KERN_WARNING "%s: partition table beyond EOD, ",
|
||||
disk->disk_name);
|
||||
if (disk_unlock_native_capacity(disk))
|
||||
goto rescan;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
/*
|
||||
* If any partition code tried to read beyond EOD, try
|
||||
* unlocking native capacity even if partition table is
|
||||
* successfully read as we could be missing some partitions.
|
||||
*/
|
||||
if (state->access_beyond_eod) {
|
||||
printk(KERN_WARNING
|
||||
"%s: partition table partially beyond EOD, ",
|
||||
disk->disk_name);
|
||||
if (disk_unlock_native_capacity(disk))
|
||||
goto rescan;
|
||||
}
|
||||
|
||||
/* tell userspace that the media / partition table may have changed */
|
||||
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
|
||||
|
||||
/* Detect the highest partition number and preallocate
|
||||
* disk->part_tbl. This is an optimization and not strictly
|
||||
* necessary.
|
||||
*/
|
||||
for (p = 1, highest = 0; p < state->limit; p++)
|
||||
if (state->parts[p].size)
|
||||
highest = p;
|
||||
|
||||
disk_expand_part_tbl(disk, highest);
|
||||
|
||||
/* add partitions */
|
||||
for (p = 1; p < state->limit; p++) {
|
||||
sector_t size, from;
|
||||
struct partition_meta_info *info = NULL;
|
||||
|
||||
size = state->parts[p].size;
|
||||
if (!size)
|
||||
continue;
|
||||
|
||||
from = state->parts[p].from;
|
||||
if (from >= get_capacity(disk)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: p%d start %llu is beyond EOD, ",
|
||||
disk->disk_name, p, (unsigned long long) from);
|
||||
if (disk_unlock_native_capacity(disk))
|
||||
goto rescan;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (from + size > get_capacity(disk)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: p%d size %llu extends beyond EOD, ",
|
||||
disk->disk_name, p, (unsigned long long) size);
|
||||
|
||||
if (disk_unlock_native_capacity(disk)) {
|
||||
/* free state and restart */
|
||||
goto rescan;
|
||||
} else {
|
||||
/*
|
||||
* we can not ignore partitions of broken tables
|
||||
* created by for example camera firmware, but
|
||||
* we limit them to the end of the disk to avoid
|
||||
* creating invalid block devices
|
||||
*/
|
||||
size = get_capacity(disk) - from;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->parts[p].has_info)
|
||||
info = &state->parts[p].info;
|
||||
part = add_partition(disk, p, from, size,
|
||||
state->parts[p].flags,
|
||||
&state->parts[p].info);
|
||||
if (IS_ERR(part)) {
|
||||
printk(KERN_ERR " %s: p%d could not be added: %ld\n",
|
||||
disk->disk_name, p, -PTR_ERR(part));
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_BLK_DEV_MD
|
||||
if (state->parts[p].flags & ADDPART_FLAG_RAID)
|
||||
md_autodetect_dev(part_to_dev(part)->devt);
|
||||
#endif
|
||||
}
|
||||
kfree(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
|
||||
{
|
||||
struct address_space *mapping = bdev->bd_inode->i_mapping;
|
||||
struct page *page;
|
||||
|
||||
page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
|
||||
NULL);
|
||||
if (!IS_ERR(page)) {
|
||||
if (PageError(page))
|
||||
goto fail;
|
||||
p->v = page;
|
||||
return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9);
|
||||
fail:
|
||||
page_cache_release(page);
|
||||
}
|
||||
p->v = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(read_dev_sector);
|
||||
49
block/partitions/check.h
Normal file
49
block/partitions/check.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
/*
|
||||
* add_gd_partition adds a partitions details to the devices partition
|
||||
* description.
|
||||
*/
|
||||
struct parsed_partitions {
|
||||
struct block_device *bdev;
|
||||
char name[BDEVNAME_SIZE];
|
||||
struct {
|
||||
sector_t from;
|
||||
sector_t size;
|
||||
int flags;
|
||||
bool has_info;
|
||||
struct partition_meta_info info;
|
||||
} parts[DISK_MAX_PARTS];
|
||||
int next;
|
||||
int limit;
|
||||
bool access_beyond_eod;
|
||||
char *pp_buf;
|
||||
};
|
||||
|
||||
static inline void *read_part_sector(struct parsed_partitions *state,
|
||||
sector_t n, Sector *p)
|
||||
{
|
||||
if (n >= get_capacity(state->bdev->bd_disk)) {
|
||||
state->access_beyond_eod = true;
|
||||
return NULL;
|
||||
}
|
||||
return read_dev_sector(state->bdev, n, p);
|
||||
}
|
||||
|
||||
static inline void
|
||||
put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
|
||||
{
|
||||
if (n < p->limit) {
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 1];
|
||||
|
||||
p->parts[n].from = from;
|
||||
p->parts[n].size = size;
|
||||
snprintf(tmp, sizeof(tmp), " %s%d", p->name, n);
|
||||
strlcat(p->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
extern int warn_no_part;
|
||||
|
||||
675
block/partitions/efi.c
Normal file
675
block/partitions/efi.c
Normal file
@@ -0,0 +1,675 @@
|
||||
/************************************************************
|
||||
* EFI GUID Partition Table handling
|
||||
*
|
||||
* http://www.uefi.org/specs/
|
||||
* http://www.intel.com/technology/efi/
|
||||
*
|
||||
* efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Copyright 2000,2001,2002,2004 Dell Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*
|
||||
* TODO:
|
||||
*
|
||||
* Changelog:
|
||||
* Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - test for valid PMBR and valid PGPT before ever reading
|
||||
* AGPT, allow override with 'gpt' kernel command line option.
|
||||
* - check for first/last_usable_lba outside of size of disk
|
||||
*
|
||||
* Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Ported to 2.5.7-pre1 and 2.5.7-dj2
|
||||
* - Applied patch to avoid fault in alternate header handling
|
||||
* - cleaned up find_valid_gpt
|
||||
* - On-disk structure and copy in memory is *always* LE now -
|
||||
* swab fields as needed
|
||||
* - remove print_gpt_header()
|
||||
* - only use first max_p partition entries, to keep the kernel minor number
|
||||
* and partition numbers tied.
|
||||
*
|
||||
* Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Removed __PRIPTR_PREFIX - not being used
|
||||
*
|
||||
* Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
|
||||
*
|
||||
* Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Added compare_gpts().
|
||||
* - moved le_efi_guid_to_cpus() back into this file. GPT is the only
|
||||
* thing that keeps EFI GUIDs on disk.
|
||||
* - Changed gpt structure names and members to be simpler and more Linux-like.
|
||||
*
|
||||
* Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
|
||||
*
|
||||
* Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Changed function comments to DocBook style per Andreas Dilger suggestion.
|
||||
*
|
||||
* Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Change read_lba() to use the page cache per Al Viro's work.
|
||||
* - print u64s properly on all architectures
|
||||
* - fixed debug_printk(), now Dprintk()
|
||||
*
|
||||
* Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Style cleanups
|
||||
* - made most functions static
|
||||
* - Endianness addition
|
||||
* - remove test for second alternate header, as it's not per spec,
|
||||
* and is unnecessary. There's now a method to read/write the last
|
||||
* sector of an odd-sized disk from user space. No tools have ever
|
||||
* been released which used this code, so it's effectively dead.
|
||||
* - Per Asit Mallick of Intel, added a test for a valid PMBR.
|
||||
* - Added kernel command line option 'gpt' to override valid PMBR test.
|
||||
*
|
||||
* Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
|
||||
* - added devfs volume UUID support (/dev/volumes/uuids) for
|
||||
* mounting file systems by the partition GUID.
|
||||
*
|
||||
* Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Moved crc32() to linux/lib, added efi_crc32().
|
||||
*
|
||||
* Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Replaced Intel's CRC32 function with an equivalent
|
||||
* non-license-restricted version.
|
||||
*
|
||||
* Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Fixed the last_lba() call to return the proper last block
|
||||
*
|
||||
* Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Thanks to Andries Brouwer for his debugging assistance.
|
||||
* - Code works, detects all the partitions.
|
||||
*
|
||||
************************************************************/
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/slab.h>
|
||||
#include "check.h"
|
||||
#include "efi.h"
|
||||
|
||||
/* This allows a kernel command line option 'gpt' to override
|
||||
* the test for invalid PMBR. Not __initdata because reloading
|
||||
* the partition tables happens after init too.
|
||||
*/
|
||||
static int force_gpt;
|
||||
static int __init
|
||||
force_gpt_fn(char *str)
|
||||
{
|
||||
force_gpt = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("gpt", force_gpt_fn);
|
||||
|
||||
|
||||
/**
|
||||
* efi_crc32() - EFI version of crc32 function
|
||||
* @buf: buffer to calculate crc32 of
|
||||
* @len - length of buf
|
||||
*
|
||||
* Description: Returns EFI-style CRC32 value for @buf
|
||||
*
|
||||
* This function uses the little endian Ethernet polynomial
|
||||
* but seeds the function with ~0, and xor's with ~0 at the end.
|
||||
* Note, the EFI Specification, v1.02, has a reference to
|
||||
* Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
|
||||
*/
|
||||
static inline u32
|
||||
efi_crc32(const void *buf, unsigned long len)
|
||||
{
|
||||
return (crc32(~0L, buf, len) ^ ~0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* last_lba(): return number of last logical block of device
|
||||
* @bdev: block device
|
||||
*
|
||||
* Description: Returns last LBA value on success, 0 on error.
|
||||
* This is stored (by sd and ide-geometry) in
|
||||
* the part[0] entry for this disk, and is the number of
|
||||
* physical sectors available on the disk.
|
||||
*/
|
||||
static u64 last_lba(struct block_device *bdev)
|
||||
{
|
||||
if (!bdev || !bdev->bd_inode)
|
||||
return 0;
|
||||
return div_u64(bdev->bd_inode->i_size,
|
||||
bdev_logical_block_size(bdev)) - 1ULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pmbr_part_valid(struct partition *part)
|
||||
{
|
||||
if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
|
||||
le32_to_cpu(part->start_sect) == 1UL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_pmbr_valid(): test Protective MBR for validity
|
||||
* @mbr: pointer to a legacy mbr structure
|
||||
*
|
||||
* Description: Returns 1 if PMBR is valid, 0 otherwise.
|
||||
* Validity depends on two things:
|
||||
* 1) MSDOS signature is in the last two bytes of the MBR
|
||||
* 2) One partition of type 0xEE is found
|
||||
*/
|
||||
static int
|
||||
is_pmbr_valid(legacy_mbr *mbr)
|
||||
{
|
||||
int i;
|
||||
if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
|
||||
return 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
if (pmbr_part_valid(&mbr->partition_record[i]))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_lba(): Read bytes from disk, starting at given LBA
|
||||
* @state
|
||||
* @lba
|
||||
* @buffer
|
||||
* @size_t
|
||||
*
|
||||
* Description: Reads @count bytes from @state->bdev into @buffer.
|
||||
* Returns number of bytes read on success, 0 on error.
|
||||
*/
|
||||
static size_t read_lba(struct parsed_partitions *state,
|
||||
u64 lba, u8 *buffer, size_t count)
|
||||
{
|
||||
size_t totalreadcount = 0;
|
||||
struct block_device *bdev = state->bdev;
|
||||
sector_t n = lba * (bdev_logical_block_size(bdev) / 512);
|
||||
|
||||
if (!buffer || lba > last_lba(bdev))
|
||||
return 0;
|
||||
|
||||
while (count) {
|
||||
int copied = 512;
|
||||
Sector sect;
|
||||
unsigned char *data = read_part_sector(state, n++, §);
|
||||
if (!data)
|
||||
break;
|
||||
if (copied > count)
|
||||
copied = count;
|
||||
memcpy(buffer, data, copied);
|
||||
put_dev_sector(sect);
|
||||
buffer += copied;
|
||||
totalreadcount +=copied;
|
||||
count -= copied;
|
||||
}
|
||||
return totalreadcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_read_gpt_entries(): reads partition entries from disk
|
||||
* @state
|
||||
* @gpt - GPT header
|
||||
*
|
||||
* Description: Returns ptes on success, NULL on error.
|
||||
* Allocates space for PTEs based on information found in @gpt.
|
||||
* Notes: remember to free pte when you're done!
|
||||
*/
|
||||
static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state,
|
||||
gpt_header *gpt)
|
||||
{
|
||||
size_t count;
|
||||
gpt_entry *pte;
|
||||
|
||||
if (!gpt)
|
||||
return NULL;
|
||||
|
||||
count = le32_to_cpu(gpt->num_partition_entries) *
|
||||
le32_to_cpu(gpt->sizeof_partition_entry);
|
||||
if (!count)
|
||||
return NULL;
|
||||
pte = kzalloc(count, GFP_KERNEL);
|
||||
if (!pte)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba),
|
||||
(u8 *) pte,
|
||||
count) < count) {
|
||||
kfree(pte);
|
||||
pte=NULL;
|
||||
return NULL;
|
||||
}
|
||||
return pte;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
|
||||
* @state
|
||||
* @lba is the Logical Block Address of the partition table
|
||||
*
|
||||
* Description: returns GPT header on success, NULL on error. Allocates
|
||||
* and fills a GPT header starting at @ from @state->bdev.
|
||||
* Note: remember to free gpt when finished with it.
|
||||
*/
|
||||
static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state,
|
||||
u64 lba)
|
||||
{
|
||||
gpt_header *gpt;
|
||||
unsigned ssz = bdev_logical_block_size(state->bdev);
|
||||
|
||||
gpt = kzalloc(ssz, GFP_KERNEL);
|
||||
if (!gpt)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) {
|
||||
kfree(gpt);
|
||||
gpt=NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_gpt_valid() - tests one GPT header and PTEs for validity
|
||||
* @state
|
||||
* @lba is the logical block address of the GPT header to test
|
||||
* @gpt is a GPT header ptr, filled on return.
|
||||
* @ptes is a PTEs ptr, filled on return.
|
||||
*
|
||||
* Description: returns 1 if valid, 0 on error.
|
||||
* If valid, returns pointers to newly allocated GPT header and PTEs.
|
||||
*/
|
||||
static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
|
||||
gpt_header **gpt, gpt_entry **ptes)
|
||||
{
|
||||
u32 crc, origcrc;
|
||||
u64 lastlba;
|
||||
|
||||
if (!ptes)
|
||||
return 0;
|
||||
if (!(*gpt = alloc_read_gpt_header(state, lba)))
|
||||
return 0;
|
||||
|
||||
/* Check the GUID Partition Table signature */
|
||||
if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
|
||||
pr_debug("GUID Partition Table Header signature is wrong:"
|
||||
"%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->signature),
|
||||
(unsigned long long)GPT_HEADER_SIGNATURE);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table header size */
|
||||
if (le32_to_cpu((*gpt)->header_size) >
|
||||
bdev_logical_block_size(state->bdev)) {
|
||||
pr_debug("GUID Partition Table Header size is wrong: %u > %u\n",
|
||||
le32_to_cpu((*gpt)->header_size),
|
||||
bdev_logical_block_size(state->bdev));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table CRC */
|
||||
origcrc = le32_to_cpu((*gpt)->header_crc32);
|
||||
(*gpt)->header_crc32 = 0;
|
||||
crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
|
||||
|
||||
if (crc != origcrc) {
|
||||
pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n",
|
||||
crc, origcrc);
|
||||
goto fail;
|
||||
}
|
||||
(*gpt)->header_crc32 = cpu_to_le32(origcrc);
|
||||
|
||||
/* Check that the my_lba entry points to the LBA that contains
|
||||
* the GUID Partition Table */
|
||||
if (le64_to_cpu((*gpt)->my_lba) != lba) {
|
||||
pr_debug("GPT my_lba incorrect: %lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->my_lba),
|
||||
(unsigned long long)lba);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the first_usable_lba and last_usable_lba are
|
||||
* within the disk.
|
||||
*/
|
||||
lastlba = last_lba(state->bdev);
|
||||
if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
|
||||
pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
|
||||
(unsigned long long)lastlba);
|
||||
goto fail;
|
||||
}
|
||||
if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
|
||||
pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
|
||||
(unsigned long long)lastlba);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check that sizeof_partition_entry has the correct value */
|
||||
if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
|
||||
pr_debug("GUID Partitition Entry Size check failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
|
||||
goto fail;
|
||||
|
||||
/* Check the GUID Partition Entry Array CRC */
|
||||
crc = efi_crc32((const unsigned char *) (*ptes),
|
||||
le32_to_cpu((*gpt)->num_partition_entries) *
|
||||
le32_to_cpu((*gpt)->sizeof_partition_entry));
|
||||
|
||||
if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
|
||||
pr_debug("GUID Partitition Entry Array CRC check failed.\n");
|
||||
goto fail_ptes;
|
||||
}
|
||||
|
||||
/* We're done, all's well */
|
||||
return 1;
|
||||
|
||||
fail_ptes:
|
||||
kfree(*ptes);
|
||||
*ptes = NULL;
|
||||
fail:
|
||||
kfree(*gpt);
|
||||
*gpt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_pte_valid() - tests one PTE for validity
|
||||
* @pte is the pte to check
|
||||
* @lastlba is last lba of the disk
|
||||
*
|
||||
* Description: returns 1 if valid, 0 on error.
|
||||
*/
|
||||
static inline int
|
||||
is_pte_valid(const gpt_entry *pte, const u64 lastlba)
|
||||
{
|
||||
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
|
||||
le64_to_cpu(pte->starting_lba) > lastlba ||
|
||||
le64_to_cpu(pte->ending_lba) > lastlba)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare_gpts() - Search disk for valid GPT headers and PTEs
|
||||
* @pgpt is the primary GPT header
|
||||
* @agpt is the alternate GPT header
|
||||
* @lastlba is the last LBA number
|
||||
* Description: Returns nothing. Sanity checks pgpt and agpt fields
|
||||
* and prints warnings on discrepancies.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
|
||||
{
|
||||
int error_found = 0;
|
||||
if (!pgpt || !agpt)
|
||||
return;
|
||||
if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
|
||||
printk(KERN_WARNING
|
||||
"GPT:Primary header LBA != Alt. header alternate_lba\n");
|
||||
printk(KERN_WARNING "GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->my_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->alternate_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
|
||||
printk(KERN_WARNING
|
||||
"GPT:Primary header alternate_lba != Alt. header my_lba\n");
|
||||
printk(KERN_WARNING "GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->alternate_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->my_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->first_usable_lba) !=
|
||||
le64_to_cpu(agpt->first_usable_lba)) {
|
||||
printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
|
||||
printk(KERN_WARNING "GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->first_usable_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->last_usable_lba) !=
|
||||
le64_to_cpu(agpt->last_usable_lba)) {
|
||||
printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
|
||||
printk(KERN_WARNING "GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->last_usable_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
|
||||
printk(KERN_WARNING "GPT:disk_guids don't match.\n");
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->num_partition_entries) !=
|
||||
le32_to_cpu(agpt->num_partition_entries)) {
|
||||
printk(KERN_WARNING "GPT:num_partition_entries don't match: "
|
||||
"0x%x != 0x%x\n",
|
||||
le32_to_cpu(pgpt->num_partition_entries),
|
||||
le32_to_cpu(agpt->num_partition_entries));
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
|
||||
le32_to_cpu(agpt->sizeof_partition_entry)) {
|
||||
printk(KERN_WARNING
|
||||
"GPT:sizeof_partition_entry values don't match: "
|
||||
"0x%x != 0x%x\n",
|
||||
le32_to_cpu(pgpt->sizeof_partition_entry),
|
||||
le32_to_cpu(agpt->sizeof_partition_entry));
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
|
||||
le32_to_cpu(agpt->partition_entry_array_crc32)) {
|
||||
printk(KERN_WARNING
|
||||
"GPT:partition_entry_array_crc32 values don't match: "
|
||||
"0x%x != 0x%x\n",
|
||||
le32_to_cpu(pgpt->partition_entry_array_crc32),
|
||||
le32_to_cpu(agpt->partition_entry_array_crc32));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
|
||||
printk(KERN_WARNING
|
||||
"GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
|
||||
printk(KERN_WARNING "GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->alternate_lba),
|
||||
(unsigned long long)lastlba);
|
||||
error_found++;
|
||||
}
|
||||
|
||||
if (le64_to_cpu(agpt->my_lba) != lastlba) {
|
||||
printk(KERN_WARNING
|
||||
"GPT:Alternate GPT header not at the end of the disk.\n");
|
||||
printk(KERN_WARNING "GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(agpt->my_lba),
|
||||
(unsigned long long)lastlba);
|
||||
error_found++;
|
||||
}
|
||||
|
||||
if (error_found)
|
||||
printk(KERN_WARNING
|
||||
"GPT: Use GNU Parted to correct GPT errors.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_valid_gpt() - Search disk for valid GPT headers and PTEs
|
||||
* @state
|
||||
* @gpt is a GPT header ptr, filled on return.
|
||||
* @ptes is a PTEs ptr, filled on return.
|
||||
* Description: Returns 1 if valid, 0 on error.
|
||||
* If valid, returns pointers to newly allocated GPT header and PTEs.
|
||||
* Validity depends on PMBR being valid (or being overridden by the
|
||||
* 'gpt' kernel command line option) and finding either the Primary
|
||||
* GPT header and PTEs valid, or the Alternate GPT header and PTEs
|
||||
* valid. If the Primary GPT header is not valid, the Alternate GPT header
|
||||
* is not checked unless the 'gpt' kernel command line option is passed.
|
||||
* This protects against devices which misreport their size, and forces
|
||||
* the user to decide to use the Alternate GPT.
|
||||
*/
|
||||
static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
|
||||
gpt_entry **ptes)
|
||||
{
|
||||
int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
|
||||
gpt_header *pgpt = NULL, *agpt = NULL;
|
||||
gpt_entry *pptes = NULL, *aptes = NULL;
|
||||
legacy_mbr *legacymbr;
|
||||
u64 lastlba;
|
||||
|
||||
if (!ptes)
|
||||
return 0;
|
||||
|
||||
lastlba = last_lba(state->bdev);
|
||||
if (!force_gpt) {
|
||||
/* This will be added to the EFI Spec. per Intel after v1.02. */
|
||||
legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
|
||||
if (legacymbr) {
|
||||
read_lba(state, 0, (u8 *) legacymbr,
|
||||
sizeof (*legacymbr));
|
||||
good_pmbr = is_pmbr_valid(legacymbr);
|
||||
kfree(legacymbr);
|
||||
}
|
||||
if (!good_pmbr)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
|
||||
&pgpt, &pptes);
|
||||
if (good_pgpt)
|
||||
good_agpt = is_gpt_valid(state,
|
||||
le64_to_cpu(pgpt->alternate_lba),
|
||||
&agpt, &aptes);
|
||||
if (!good_agpt && force_gpt)
|
||||
good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
|
||||
|
||||
/* The obviously unsuccessful case */
|
||||
if (!good_pgpt && !good_agpt)
|
||||
goto fail;
|
||||
|
||||
compare_gpts(pgpt, agpt, lastlba);
|
||||
|
||||
/* The good cases */
|
||||
if (good_pgpt) {
|
||||
*gpt = pgpt;
|
||||
*ptes = pptes;
|
||||
kfree(agpt);
|
||||
kfree(aptes);
|
||||
if (!good_agpt) {
|
||||
printk(KERN_WARNING
|
||||
"Alternate GPT is invalid, "
|
||||
"using primary GPT.\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (good_agpt) {
|
||||
*gpt = agpt;
|
||||
*ptes = aptes;
|
||||
kfree(pgpt);
|
||||
kfree(pptes);
|
||||
printk(KERN_WARNING
|
||||
"Primary GPT is invalid, using alternate GPT.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fail:
|
||||
kfree(pgpt);
|
||||
kfree(agpt);
|
||||
kfree(pptes);
|
||||
kfree(aptes);
|
||||
*gpt = NULL;
|
||||
*ptes = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_partition(struct parsed_partitions *state)
|
||||
* @state
|
||||
*
|
||||
* Description: called from check.c, if the disk contains GPT
|
||||
* partitions, sets up partition entries in the kernel.
|
||||
*
|
||||
* If the first block on the disk is a legacy MBR,
|
||||
* it will get handled by msdos_partition().
|
||||
* If it's a Protective MBR, we'll handle it here.
|
||||
*
|
||||
* We do not create a Linux partition for GPT, but
|
||||
* only for the actual data partitions.
|
||||
* Returns:
|
||||
* -1 if unable to read the partition table
|
||||
* 0 if this isn't our partition table
|
||||
* 1 if successful
|
||||
*
|
||||
*/
|
||||
int efi_partition(struct parsed_partitions *state)
|
||||
{
|
||||
gpt_header *gpt = NULL;
|
||||
gpt_entry *ptes = NULL;
|
||||
u32 i;
|
||||
unsigned ssz = bdev_logical_block_size(state->bdev) / 512;
|
||||
u8 unparsed_guid[37];
|
||||
|
||||
if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) {
|
||||
kfree(gpt);
|
||||
kfree(ptes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_debug("GUID Partition Table is valid! Yea!\n");
|
||||
|
||||
for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
|
||||
struct partition_meta_info *info;
|
||||
unsigned label_count = 0;
|
||||
unsigned label_max;
|
||||
u64 start = le64_to_cpu(ptes[i].starting_lba);
|
||||
u64 size = le64_to_cpu(ptes[i].ending_lba) -
|
||||
le64_to_cpu(ptes[i].starting_lba) + 1ULL;
|
||||
|
||||
if (!is_pte_valid(&ptes[i], last_lba(state->bdev)))
|
||||
continue;
|
||||
|
||||
put_partition(state, i+1, start * ssz, size * ssz);
|
||||
|
||||
/* If this is a RAID volume, tell md */
|
||||
if (!efi_guidcmp(ptes[i].partition_type_guid,
|
||||
PARTITION_LINUX_RAID_GUID))
|
||||
state->parts[i + 1].flags = ADDPART_FLAG_RAID;
|
||||
|
||||
info = &state->parts[i + 1].info;
|
||||
/* Instead of doing a manual swap to big endian, reuse the
|
||||
* common ASCII hex format as the interim.
|
||||
*/
|
||||
efi_guid_unparse(&ptes[i].unique_partition_guid, unparsed_guid);
|
||||
part_pack_uuid(unparsed_guid, info->uuid);
|
||||
|
||||
/* Naively convert UTF16-LE to 7 bits. */
|
||||
label_max = min(sizeof(info->volname) - 1,
|
||||
sizeof(ptes[i].partition_name));
|
||||
info->volname[label_max] = 0;
|
||||
while (label_count < label_max) {
|
||||
u8 c = ptes[i].partition_name[label_count] & 0xff;
|
||||
if (c && !isprint(c))
|
||||
c = '!';
|
||||
info->volname[label_count] = c;
|
||||
label_count++;
|
||||
}
|
||||
state->parts[i + 1].has_info = true;
|
||||
}
|
||||
kfree(ptes);
|
||||
kfree(gpt);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
134
block/partitions/efi.h
Normal file
134
block/partitions/efi.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/************************************************************
|
||||
* EFI GUID Partition Table
|
||||
* Per Intel EFI Specification v1.02
|
||||
* http://developer.intel.com/technology/efi/efi.htm
|
||||
*
|
||||
* By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000
|
||||
* Copyright 2000,2001 Dell Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
#ifndef FS_PART_EFI_H_INCLUDED
|
||||
#define FS_PART_EFI_H_INCLUDED
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/efi.h>
|
||||
|
||||
#define MSDOS_MBR_SIGNATURE 0xaa55
|
||||
#define EFI_PMBR_OSTYPE_EFI 0xEF
|
||||
#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
|
||||
|
||||
#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
|
||||
#define GPT_HEADER_REVISION_V1 0x00010000
|
||||
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
|
||||
|
||||
#define PARTITION_SYSTEM_GUID \
|
||||
EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
|
||||
0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
|
||||
#define LEGACY_MBR_PARTITION_GUID \
|
||||
EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
|
||||
0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
|
||||
#define PARTITION_MSFT_RESERVED_GUID \
|
||||
EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
|
||||
0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
|
||||
#define PARTITION_BASIC_DATA_GUID \
|
||||
EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
|
||||
0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
|
||||
#define PARTITION_LINUX_RAID_GUID \
|
||||
EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
|
||||
0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
|
||||
#define PARTITION_LINUX_SWAP_GUID \
|
||||
EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
|
||||
0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
|
||||
#define PARTITION_LINUX_LVM_GUID \
|
||||
EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
|
||||
0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
|
||||
|
||||
typedef struct _gpt_header {
|
||||
__le64 signature;
|
||||
__le32 revision;
|
||||
__le32 header_size;
|
||||
__le32 header_crc32;
|
||||
__le32 reserved1;
|
||||
__le64 my_lba;
|
||||
__le64 alternate_lba;
|
||||
__le64 first_usable_lba;
|
||||
__le64 last_usable_lba;
|
||||
efi_guid_t disk_guid;
|
||||
__le64 partition_entry_lba;
|
||||
__le32 num_partition_entries;
|
||||
__le32 sizeof_partition_entry;
|
||||
__le32 partition_entry_array_crc32;
|
||||
|
||||
/* The rest of the logical block is reserved by UEFI and must be zero.
|
||||
* EFI standard handles this by:
|
||||
*
|
||||
* uint8_t reserved2[ BlockSize - 92 ];
|
||||
*/
|
||||
} __attribute__ ((packed)) gpt_header;
|
||||
|
||||
typedef struct _gpt_entry_attributes {
|
||||
u64 required_to_function:1;
|
||||
u64 reserved:47;
|
||||
u64 type_guid_specific:16;
|
||||
} __attribute__ ((packed)) gpt_entry_attributes;
|
||||
|
||||
typedef struct _gpt_entry {
|
||||
efi_guid_t partition_type_guid;
|
||||
efi_guid_t unique_partition_guid;
|
||||
__le64 starting_lba;
|
||||
__le64 ending_lba;
|
||||
gpt_entry_attributes attributes;
|
||||
efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
|
||||
} __attribute__ ((packed)) gpt_entry;
|
||||
|
||||
typedef struct _legacy_mbr {
|
||||
u8 boot_code[440];
|
||||
__le32 unique_mbr_signature;
|
||||
__le16 unknown;
|
||||
struct partition partition_record[4];
|
||||
__le16 signature;
|
||||
} __attribute__ ((packed)) legacy_mbr;
|
||||
|
||||
/* Functions */
|
||||
extern int efi_partition(struct parsed_partitions *state);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* --------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-indent-level: 4
|
||||
* c-brace-imaginary-offset: 0
|
||||
* c-brace-offset: -4
|
||||
* c-argdecl-indent: 4
|
||||
* c-label-offset: -4
|
||||
* c-continued-statement-offset: 4
|
||||
* c-continued-brace-offset: 0
|
||||
* indent-tabs-mode: nil
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
275
block/partitions/ibm.c
Normal file
275
block/partitions/ibm.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* File...........: linux/fs/partitions/ibm.c
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Volker Sameske <sameske@de.ibm.com>
|
||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
|
||||
*/
|
||||
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/dasd.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/vtoc.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "ibm.h"
|
||||
|
||||
/*
|
||||
* compute the block number from a
|
||||
* cyl-cyl-head-head structure
|
||||
*/
|
||||
static sector_t
|
||||
cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
|
||||
|
||||
sector_t cyl;
|
||||
__u16 head;
|
||||
|
||||
/*decode cylinder and heads for large volumes */
|
||||
cyl = ptr->hh & 0xFFF0;
|
||||
cyl <<= 12;
|
||||
cyl |= ptr->cc;
|
||||
head = ptr->hh & 0x000F;
|
||||
return cyl * geo->heads * geo->sectors +
|
||||
head * geo->sectors;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute the block number from a
|
||||
* cyl-cyl-head-head-block structure
|
||||
*/
|
||||
static sector_t
|
||||
cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
|
||||
|
||||
sector_t cyl;
|
||||
__u16 head;
|
||||
|
||||
/*decode cylinder and heads for large volumes */
|
||||
cyl = ptr->hh & 0xFFF0;
|
||||
cyl <<= 12;
|
||||
cyl |= ptr->cc;
|
||||
head = ptr->hh & 0x000F;
|
||||
return cyl * geo->heads * geo->sectors +
|
||||
head * geo->sectors +
|
||||
ptr->b;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
int ibm_partition(struct parsed_partitions *state)
|
||||
{
|
||||
struct block_device *bdev = state->bdev;
|
||||
int blocksize, res;
|
||||
loff_t i_size, offset, size, fmt_size;
|
||||
dasd_information2_t *info;
|
||||
struct hd_geometry *geo;
|
||||
char type[5] = {0,};
|
||||
char name[7] = {0,};
|
||||
union label_t {
|
||||
struct vtoc_volume_label_cdl vol;
|
||||
struct vtoc_volume_label_ldl lnx;
|
||||
struct vtoc_cms_label cms;
|
||||
} *label;
|
||||
unsigned char *data;
|
||||
Sector sect;
|
||||
sector_t labelsect;
|
||||
char tmp[64];
|
||||
|
||||
res = 0;
|
||||
blocksize = bdev_logical_block_size(bdev);
|
||||
if (blocksize <= 0)
|
||||
goto out_exit;
|
||||
i_size = i_size_read(bdev->bd_inode);
|
||||
if (i_size == 0)
|
||||
goto out_exit;
|
||||
|
||||
info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
|
||||
if (info == NULL)
|
||||
goto out_exit;
|
||||
geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
|
||||
if (geo == NULL)
|
||||
goto out_nogeo;
|
||||
label = kmalloc(sizeof(union label_t), GFP_KERNEL);
|
||||
if (label == NULL)
|
||||
goto out_nolab;
|
||||
|
||||
if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 ||
|
||||
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
|
||||
goto out_freeall;
|
||||
|
||||
/*
|
||||
* Special case for FBA disks: label sector does not depend on
|
||||
* blocksize.
|
||||
*/
|
||||
if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
|
||||
(info->cu_type == 0x3880 && info->dev_type == 0x3370))
|
||||
labelsect = info->label_block;
|
||||
else
|
||||
labelsect = info->label_block * (blocksize >> 9);
|
||||
|
||||
/*
|
||||
* Get volume label, extract name and type.
|
||||
*/
|
||||
data = read_part_sector(state, labelsect, §);
|
||||
if (data == NULL)
|
||||
goto out_readerr;
|
||||
|
||||
memcpy(label, data, sizeof(union label_t));
|
||||
put_dev_sector(sect);
|
||||
|
||||
if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
|
||||
strncpy(type, label->vol.vollbl, 4);
|
||||
strncpy(name, label->vol.volid, 6);
|
||||
} else {
|
||||
strncpy(type, label->lnx.vollbl, 4);
|
||||
strncpy(name, label->lnx.volid, 6);
|
||||
}
|
||||
EBCASC(type, 4);
|
||||
EBCASC(name, 6);
|
||||
|
||||
res = 1;
|
||||
|
||||
/*
|
||||
* Three different formats: LDL, CDL and unformated disk
|
||||
*
|
||||
* identified by info->format
|
||||
*
|
||||
* unformated disks we do not have to care about
|
||||
*/
|
||||
if (info->format == DASD_FORMAT_LDL) {
|
||||
if (strncmp(type, "CMS1", 4) == 0) {
|
||||
/*
|
||||
* VM style CMS1 labeled disk
|
||||
*/
|
||||
blocksize = label->cms.block_size;
|
||||
if (label->cms.disk_offset != 0) {
|
||||
snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/* disk is reserved minidisk */
|
||||
offset = label->cms.disk_offset;
|
||||
size = (label->cms.block_count - 1)
|
||||
* (blocksize >> 9);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
offset = (info->label_block + 1);
|
||||
size = label->cms.block_count
|
||||
* (blocksize >> 9);
|
||||
}
|
||||
put_partition(state, 1, offset*(blocksize >> 9),
|
||||
size-offset*(blocksize >> 9));
|
||||
} else {
|
||||
if (strncmp(type, "LNX1", 4) == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
if (label->lnx.ldl_version == 0xf2) {
|
||||
fmt_size = label->lnx.formatted_blocks
|
||||
* (blocksize >> 9);
|
||||
} else if (!strcmp(info->type, "ECKD")) {
|
||||
/* formated w/o large volume support */
|
||||
fmt_size = geo->cylinders * geo->heads
|
||||
* geo->sectors * (blocksize >> 9);
|
||||
} else {
|
||||
/* old label and no usable disk geometry
|
||||
* (e.g. DIAG) */
|
||||
fmt_size = i_size >> 9;
|
||||
}
|
||||
size = i_size >> 9;
|
||||
if (fmt_size < size)
|
||||
size = fmt_size;
|
||||
offset = (info->label_block + 1);
|
||||
} else {
|
||||
/* unlabeled disk */
|
||||
strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
|
||||
size = i_size >> 9;
|
||||
offset = (info->label_block + 1);
|
||||
}
|
||||
put_partition(state, 1, offset*(blocksize >> 9),
|
||||
size-offset*(blocksize >> 9));
|
||||
}
|
||||
} else if (info->format == DASD_FORMAT_CDL) {
|
||||
/*
|
||||
* New style CDL formatted disk
|
||||
*/
|
||||
sector_t blk;
|
||||
int counter;
|
||||
|
||||
/*
|
||||
* check if VOL1 label is available
|
||||
* if not, something is wrong, skipping partition detection
|
||||
*/
|
||||
if (strncmp(type, "VOL1", 4) == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/*
|
||||
* get block number and read then go through format1
|
||||
* labels
|
||||
*/
|
||||
blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
|
||||
counter = 0;
|
||||
data = read_part_sector(state, blk * (blocksize/512),
|
||||
§);
|
||||
while (data != NULL) {
|
||||
struct vtoc_format1_label f1;
|
||||
|
||||
memcpy(&f1, data,
|
||||
sizeof(struct vtoc_format1_label));
|
||||
put_dev_sector(sect);
|
||||
|
||||
/* skip FMT4 / FMT5 / FMT7 labels */
|
||||
if (f1.DS1FMTID == _ascebc['4']
|
||||
|| f1.DS1FMTID == _ascebc['5']
|
||||
|| f1.DS1FMTID == _ascebc['7']
|
||||
|| f1.DS1FMTID == _ascebc['9']) {
|
||||
blk++;
|
||||
data = read_part_sector(state,
|
||||
blk * (blocksize/512), §);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only FMT1 and 8 labels valid at this point */
|
||||
if (f1.DS1FMTID != _ascebc['1'] &&
|
||||
f1.DS1FMTID != _ascebc['8'])
|
||||
break;
|
||||
|
||||
/* OK, we got valid partition data */
|
||||
offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
|
||||
size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
|
||||
offset + geo->sectors;
|
||||
if (counter >= state->limit)
|
||||
break;
|
||||
put_partition(state, counter + 1,
|
||||
offset * (blocksize >> 9),
|
||||
size * (blocksize >> 9));
|
||||
counter++;
|
||||
blk++;
|
||||
data = read_part_sector(state,
|
||||
blk * (blocksize/512), §);
|
||||
}
|
||||
|
||||
if (!data)
|
||||
/* Are we not supposed to report this ? */
|
||||
goto out_readerr;
|
||||
} else
|
||||
printk(KERN_WARNING "Warning, expected Label VOL1 not "
|
||||
"found, treating as CDL formated Disk");
|
||||
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
goto out_freeall;
|
||||
|
||||
|
||||
out_readerr:
|
||||
res = -1;
|
||||
out_freeall:
|
||||
kfree(label);
|
||||
out_nolab:
|
||||
kfree(geo);
|
||||
out_nogeo:
|
||||
kfree(info);
|
||||
out_exit:
|
||||
return res;
|
||||
}
|
||||
1
block/partitions/ibm.h
Normal file
1
block/partitions/ibm.h
Normal file
@@ -0,0 +1 @@
|
||||
int ibm_partition(struct parsed_partitions *);
|
||||
57
block/partitions/karma.c
Normal file
57
block/partitions/karma.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* fs/partitions/karma.c
|
||||
* Rio Karma partition info.
|
||||
*
|
||||
* Copyright (C) 2006 Bob Copeland (me@bobcopeland.com)
|
||||
* based on osf.c
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "karma.h"
|
||||
|
||||
int karma_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
int slot = 1;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct disklabel {
|
||||
u8 d_reserved[270];
|
||||
struct d_partition {
|
||||
__le32 p_res;
|
||||
u8 p_fstype;
|
||||
u8 p_res2[3];
|
||||
__le32 p_offset;
|
||||
__le32 p_size;
|
||||
} d_partitions[2];
|
||||
u8 d_blank[208];
|
||||
__le16 d_magic;
|
||||
} __attribute__((packed)) *label;
|
||||
struct d_partition *p;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct disklabel *)data;
|
||||
if (le16_to_cpu(label->d_magic) != KARMA_LABEL_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = label->d_partitions;
|
||||
for (i = 0 ; i < 2; i++, p++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
if (p->p_fstype == 0x4d && le32_to_cpu(p->p_size)) {
|
||||
put_partition(state, slot, le32_to_cpu(p->p_offset),
|
||||
le32_to_cpu(p->p_size));
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
|
||||
8
block/partitions/karma.h
Normal file
8
block/partitions/karma.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/karma.h
|
||||
*/
|
||||
|
||||
#define KARMA_LABEL_MAGIC 0xAB56
|
||||
|
||||
int karma_partition(struct parsed_partitions *state);
|
||||
|
||||
1570
block/partitions/ldm.c
Normal file
1570
block/partitions/ldm.c
Normal file
File diff suppressed because it is too large
Load Diff
215
block/partitions/ldm.h
Normal file
215
block/partitions/ldm.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* ldm - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
|
||||
* Copyright (c) 2001-2007 Anton Altaparmakov
|
||||
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
|
||||
*
|
||||
* Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _FS_PT_LDM_H_
|
||||
#define _FS_PT_LDM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
struct parsed_partitions;
|
||||
|
||||
/* Magic numbers in CPU format. */
|
||||
#define MAGIC_VMDB 0x564D4442 /* VMDB */
|
||||
#define MAGIC_VBLK 0x56424C4B /* VBLK */
|
||||
#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */
|
||||
#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */
|
||||
|
||||
/* The defined vblk types. */
|
||||
#define VBLK_VOL5 0x51 /* Volume, version 5 */
|
||||
#define VBLK_CMP3 0x32 /* Component, version 3 */
|
||||
#define VBLK_PRT3 0x33 /* Partition, version 3 */
|
||||
#define VBLK_DSK3 0x34 /* Disk, version 3 */
|
||||
#define VBLK_DSK4 0x44 /* Disk, version 4 */
|
||||
#define VBLK_DGR3 0x35 /* Disk Group, version 3 */
|
||||
#define VBLK_DGR4 0x45 /* Disk Group, version 4 */
|
||||
|
||||
/* vblk flags indicating extra information will be present */
|
||||
#define VBLK_FLAG_COMP_STRIPE 0x10
|
||||
#define VBLK_FLAG_PART_INDEX 0x08
|
||||
#define VBLK_FLAG_DGR3_IDS 0x08
|
||||
#define VBLK_FLAG_DGR4_IDS 0x08
|
||||
#define VBLK_FLAG_VOLU_ID1 0x08
|
||||
#define VBLK_FLAG_VOLU_ID2 0x20
|
||||
#define VBLK_FLAG_VOLU_SIZE 0x80
|
||||
#define VBLK_FLAG_VOLU_DRIVE 0x02
|
||||
|
||||
/* size of a vblk's static parts */
|
||||
#define VBLK_SIZE_HEAD 16
|
||||
#define VBLK_SIZE_CMP3 22 /* Name and version */
|
||||
#define VBLK_SIZE_DGR3 12
|
||||
#define VBLK_SIZE_DGR4 44
|
||||
#define VBLK_SIZE_DSK3 12
|
||||
#define VBLK_SIZE_DSK4 45
|
||||
#define VBLK_SIZE_PRT3 28
|
||||
#define VBLK_SIZE_VOL5 58
|
||||
|
||||
/* component types */
|
||||
#define COMP_STRIPE 0x01 /* Stripe-set */
|
||||
#define COMP_BASIC 0x02 /* Basic disk */
|
||||
#define COMP_RAID 0x03 /* Raid-set */
|
||||
|
||||
/* Other constants. */
|
||||
#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */
|
||||
|
||||
#define OFF_PRIV1 6 /* Offset of the first privhead
|
||||
relative to the start of the
|
||||
device in sectors */
|
||||
|
||||
/* Offsets to structures within the LDM Database in sectors. */
|
||||
#define OFF_PRIV2 1856 /* Backup private headers. */
|
||||
#define OFF_PRIV3 2047
|
||||
|
||||
#define OFF_TOCB1 1 /* Tables of contents. */
|
||||
#define OFF_TOCB2 2
|
||||
#define OFF_TOCB3 2045
|
||||
#define OFF_TOCB4 2046
|
||||
|
||||
#define OFF_VMDB 17 /* List of partitions. */
|
||||
|
||||
#define LDM_PARTITION 0x42 /* Formerly SFS (Landis). */
|
||||
|
||||
#define TOC_BITMAP1 "config" /* Names of the two defined */
|
||||
#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
|
||||
|
||||
/* Borrowed from msdos.c */
|
||||
#define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
|
||||
|
||||
struct frag { /* VBLK Fragment handling */
|
||||
struct list_head list;
|
||||
u32 group;
|
||||
u8 num; /* Total number of records */
|
||||
u8 rec; /* This is record number n */
|
||||
u8 map; /* Which portions are in use */
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/* In memory LDM database structures. */
|
||||
|
||||
#define GUID_SIZE 16
|
||||
|
||||
struct privhead { /* Offsets and sizes are in sectors. */
|
||||
u16 ver_major;
|
||||
u16 ver_minor;
|
||||
u64 logical_disk_start;
|
||||
u64 logical_disk_size;
|
||||
u64 config_start;
|
||||
u64 config_size;
|
||||
u8 disk_id[GUID_SIZE];
|
||||
};
|
||||
|
||||
struct tocblock { /* We have exactly two bitmaps. */
|
||||
u8 bitmap1_name[16];
|
||||
u64 bitmap1_start;
|
||||
u64 bitmap1_size;
|
||||
u8 bitmap2_name[16];
|
||||
u64 bitmap2_start;
|
||||
u64 bitmap2_size;
|
||||
};
|
||||
|
||||
struct vmdb { /* VMDB: The database header */
|
||||
u16 ver_major;
|
||||
u16 ver_minor;
|
||||
u32 vblk_size;
|
||||
u32 vblk_offset;
|
||||
u32 last_vblk_seq;
|
||||
};
|
||||
|
||||
struct vblk_comp { /* VBLK Component */
|
||||
u8 state[16];
|
||||
u64 parent_id;
|
||||
u8 type;
|
||||
u8 children;
|
||||
u16 chunksize;
|
||||
};
|
||||
|
||||
struct vblk_dgrp { /* VBLK Disk Group */
|
||||
u8 disk_id[64];
|
||||
};
|
||||
|
||||
struct vblk_disk { /* VBLK Disk */
|
||||
u8 disk_id[GUID_SIZE];
|
||||
u8 alt_name[128];
|
||||
};
|
||||
|
||||
struct vblk_part { /* VBLK Partition */
|
||||
u64 start;
|
||||
u64 size; /* start, size and vol_off in sectors */
|
||||
u64 volume_offset;
|
||||
u64 parent_id;
|
||||
u64 disk_id;
|
||||
u8 partnum;
|
||||
};
|
||||
|
||||
struct vblk_volu { /* VBLK Volume */
|
||||
u8 volume_type[16];
|
||||
u8 volume_state[16];
|
||||
u8 guid[16];
|
||||
u8 drive_hint[4];
|
||||
u64 size;
|
||||
u8 partition_type;
|
||||
};
|
||||
|
||||
struct vblk_head { /* VBLK standard header */
|
||||
u32 group;
|
||||
u16 rec;
|
||||
u16 nrec;
|
||||
};
|
||||
|
||||
struct vblk { /* Generalised VBLK */
|
||||
u8 name[64];
|
||||
u64 obj_id;
|
||||
u32 sequence;
|
||||
u8 flags;
|
||||
u8 type;
|
||||
union {
|
||||
struct vblk_comp comp;
|
||||
struct vblk_dgrp dgrp;
|
||||
struct vblk_disk disk;
|
||||
struct vblk_part part;
|
||||
struct vblk_volu volu;
|
||||
} vblk;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct ldmdb { /* Cache of the database */
|
||||
struct privhead ph;
|
||||
struct tocblock toc;
|
||||
struct vmdb vm;
|
||||
struct list_head v_dgrp;
|
||||
struct list_head v_disk;
|
||||
struct list_head v_volu;
|
||||
struct list_head v_comp;
|
||||
struct list_head v_part;
|
||||
};
|
||||
|
||||
int ldm_partition(struct parsed_partitions *state);
|
||||
|
||||
#endif /* _FS_PT_LDM_H_ */
|
||||
|
||||
134
block/partitions/mac.c
Normal file
134
block/partitions/mac.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* fs/partitions/mac.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include "check.h"
|
||||
#include "mac.h"
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
#include <asm/machdep.h>
|
||||
extern void note_bootable_part(dev_t dev, int part, int goodness);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Code to understand MacOS partition tables.
|
||||
*/
|
||||
|
||||
static inline void mac_fix_string(char *stg, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
|
||||
stg[i] = 0;
|
||||
}
|
||||
|
||||
int mac_partition(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
int slot, blocks_in_map;
|
||||
unsigned secsize;
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
int found_root = 0;
|
||||
int found_root_goodness = 0;
|
||||
#endif
|
||||
struct mac_partition *part;
|
||||
struct mac_driver_desc *md;
|
||||
|
||||
/* Get 0th block and look at the first partition map entry. */
|
||||
md = read_part_sector(state, 0, §);
|
||||
if (!md)
|
||||
return -1;
|
||||
if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
secsize = be16_to_cpu(md->block_size);
|
||||
put_dev_sector(sect);
|
||||
data = read_part_sector(state, secsize/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + secsize%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0; /* not a MacOS disk */
|
||||
}
|
||||
blocks_in_map = be32_to_cpu(part->map_count);
|
||||
if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
|
||||
for (slot = 1; slot <= blocks_in_map; ++slot) {
|
||||
int pos = slot * secsize;
|
||||
put_dev_sector(sect);
|
||||
data = read_part_sector(state, pos/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + pos%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
|
||||
break;
|
||||
put_partition(state, slot,
|
||||
be32_to_cpu(part->start_block) * (secsize/512),
|
||||
be32_to_cpu(part->block_count) * (secsize/512));
|
||||
|
||||
if (!strnicmp(part->type, "Linux_RAID", 10))
|
||||
state->parts[slot].flags = ADDPART_FLAG_RAID;
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/*
|
||||
* If this is the first bootable partition, tell the
|
||||
* setup code, in case it wants to make this the root.
|
||||
*/
|
||||
if (machine_is(powermac)) {
|
||||
int goodness = 0;
|
||||
|
||||
mac_fix_string(part->processor, 16);
|
||||
mac_fix_string(part->name, 32);
|
||||
mac_fix_string(part->type, 32);
|
||||
|
||||
if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
|
||||
&& strcasecmp(part->processor, "powerpc") == 0)
|
||||
goodness++;
|
||||
|
||||
if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
|
||||
|| (strnicmp(part->type, "Linux", 5) == 0
|
||||
&& strcasecmp(part->type, "Linux_swap") != 0)) {
|
||||
int i, l;
|
||||
|
||||
goodness++;
|
||||
l = strlen(part->name);
|
||||
if (strcmp(part->name, "/") == 0)
|
||||
goodness++;
|
||||
for (i = 0; i <= l - 4; ++i) {
|
||||
if (strnicmp(part->name + i, "root",
|
||||
4) == 0) {
|
||||
goodness += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (strnicmp(part->name, "swap", 4) == 0)
|
||||
goodness--;
|
||||
}
|
||||
|
||||
if (goodness > found_root_goodness) {
|
||||
found_root = slot;
|
||||
found_root_goodness = goodness;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PPC_PMAC */
|
||||
}
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
if (found_root_goodness)
|
||||
note_bootable_part(state->bdev->bd_dev, found_root,
|
||||
found_root_goodness);
|
||||
#endif
|
||||
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
44
block/partitions/mac.h
Normal file
44
block/partitions/mac.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* fs/partitions/mac.h
|
||||
*/
|
||||
|
||||
#define MAC_PARTITION_MAGIC 0x504d
|
||||
|
||||
/* type field value for A/UX or other Unix partitions */
|
||||
#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
|
||||
|
||||
struct mac_partition {
|
||||
__be16 signature; /* expected to be MAC_PARTITION_MAGIC */
|
||||
__be16 res1;
|
||||
__be32 map_count; /* # blocks in partition map */
|
||||
__be32 start_block; /* absolute starting block # of partition */
|
||||
__be32 block_count; /* number of blocks in partition */
|
||||
char name[32]; /* partition name */
|
||||
char type[32]; /* string type description */
|
||||
__be32 data_start; /* rel block # of first data block */
|
||||
__be32 data_count; /* number of data blocks */
|
||||
__be32 status; /* partition status bits */
|
||||
__be32 boot_start;
|
||||
__be32 boot_size;
|
||||
__be32 boot_load;
|
||||
__be32 boot_load2;
|
||||
__be32 boot_entry;
|
||||
__be32 boot_entry2;
|
||||
__be32 boot_cksum;
|
||||
char processor[16]; /* identifies ISA of boot */
|
||||
/* there is more stuff after this that we don't need */
|
||||
};
|
||||
|
||||
#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
|
||||
|
||||
#define MAC_DRIVER_MAGIC 0x4552
|
||||
|
||||
/* Driver descriptor structure, in block 0 */
|
||||
struct mac_driver_desc {
|
||||
__be16 signature; /* expected to be MAC_DRIVER_MAGIC */
|
||||
__be16 block_size;
|
||||
__be32 block_count;
|
||||
/* ... more stuff */
|
||||
};
|
||||
|
||||
int mac_partition(struct parsed_partitions *state);
|
||||
552
block/partitions/msdos.c
Normal file
552
block/partitions/msdos.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* fs/partitions/msdos.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
*
|
||||
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
|
||||
* in the early extended-partition checks and added DM partitions
|
||||
*
|
||||
* Support for DiskManager v6.0x added by Mark Lord,
|
||||
* with information provided by OnTrack. This now works for linux fdisk
|
||||
* and LILO, as well as loadlin and bootln. Note that disks other than
|
||||
* /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
|
||||
*
|
||||
* More flexible handling of extended partitions - aeb, 950831
|
||||
*
|
||||
* Check partition table on IDE disks for common CHS translations
|
||||
*
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
#include <linux/msdos_fs.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "msdos.h"
|
||||
#include "efi.h"
|
||||
|
||||
/*
|
||||
* Many architectures don't like unaligned accesses, while
|
||||
* the nr_sects and start_sect partition table entries are
|
||||
* at a 2 (mod 4) address.
|
||||
*/
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define SYS_IND(p) get_unaligned(&p->sys_ind)
|
||||
|
||||
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)
|
||||
{
|
||||
return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
|
||||
SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
|
||||
SYS_IND(p) == LINUX_EXTENDED_PARTITION);
|
||||
}
|
||||
|
||||
#define MSDOS_LABEL_MAGIC1 0x55
|
||||
#define MSDOS_LABEL_MAGIC2 0xAA
|
||||
|
||||
static inline int
|
||||
msdos_magic_present(unsigned char *p)
|
||||
{
|
||||
return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
|
||||
}
|
||||
|
||||
/* Value is EBCDIC 'IBMA' */
|
||||
#define AIX_LABEL_MAGIC1 0xC9
|
||||
#define AIX_LABEL_MAGIC2 0xC2
|
||||
#define AIX_LABEL_MAGIC3 0xD4
|
||||
#define AIX_LABEL_MAGIC4 0xC1
|
||||
static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
|
||||
{
|
||||
struct partition *pt = (struct partition *) (p + 0x1be);
|
||||
Sector sect;
|
||||
unsigned char *d;
|
||||
int slot, ret = 0;
|
||||
|
||||
if (!(p[0] == AIX_LABEL_MAGIC1 &&
|
||||
p[1] == AIX_LABEL_MAGIC2 &&
|
||||
p[2] == AIX_LABEL_MAGIC3 &&
|
||||
p[3] == AIX_LABEL_MAGIC4))
|
||||
return 0;
|
||||
/* Assume the partition table is valid if Linux partitions exists */
|
||||
for (slot = 1; slot <= 4; slot++, pt++) {
|
||||
if (pt->sys_ind == LINUX_SWAP_PARTITION ||
|
||||
pt->sys_ind == LINUX_RAID_PARTITION ||
|
||||
pt->sys_ind == LINUX_DATA_PARTITION ||
|
||||
pt->sys_ind == LINUX_LVM_PARTITION ||
|
||||
is_extended_partition(pt))
|
||||
return 0;
|
||||
}
|
||||
d = read_part_sector(state, 7, §);
|
||||
if (d) {
|
||||
if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
|
||||
ret = 1;
|
||||
put_dev_sector(sect);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create devices for each logical partition in an extended partition.
|
||||
* The logical partitions form a linked list, with each entry being
|
||||
* a partition table with two entries. The first entry
|
||||
* is the real data partition (with a start relative to the partition
|
||||
* table start). The second is a pointer to the next logical partition
|
||||
* (with a start relative to the entire extended partition).
|
||||
* We do not create a Linux partition for the partition tables, but
|
||||
* only for the actual data partitions.
|
||||
*/
|
||||
|
||||
static void parse_extended(struct parsed_partitions *state,
|
||||
sector_t first_sector, sector_t first_size)
|
||||
{
|
||||
struct partition *p;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
sector_t this_sector, this_size;
|
||||
sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
|
||||
int loopct = 0; /* number of links followed
|
||||
without finding a data partition */
|
||||
int i;
|
||||
|
||||
this_sector = first_sector;
|
||||
this_size = first_size;
|
||||
|
||||
while (1) {
|
||||
if (++loopct > 100)
|
||||
return;
|
||||
if (state->next == state->limit)
|
||||
return;
|
||||
data = read_part_sector(state, this_sector, §);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (!msdos_magic_present(data + 510))
|
||||
goto done;
|
||||
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
|
||||
/*
|
||||
* Usually, the first entry is the real data partition,
|
||||
* the 2nd entry is the next extended partition, or empty,
|
||||
* and the 3rd and 4th entries are unused.
|
||||
* However, DRDOS sometimes has the extended partition as
|
||||
* the first entry (when the data partition is empty),
|
||||
* and OS/2 seems to use all four entries.
|
||||
*/
|
||||
|
||||
/*
|
||||
* First process the data partition(s)
|
||||
*/
|
||||
for (i=0; i<4; i++, 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;
|
||||
next = this_sector + offs;
|
||||
if (i >= 2) {
|
||||
if (offs + size > this_size)
|
||||
continue;
|
||||
if (next < first_sector)
|
||||
continue;
|
||||
if (next + size > first_sector + first_size)
|
||||
continue;
|
||||
}
|
||||
|
||||
put_partition(state, state->next, next, size);
|
||||
if (SYS_IND(p) == LINUX_RAID_PARTITION)
|
||||
state->parts[state->next].flags = ADDPART_FLAG_RAID;
|
||||
loopct = 0;
|
||||
if (++state->next == state->limit)
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Next, process the (first) extended partition, if present.
|
||||
* (So far, there seems to be no reason to make
|
||||
* parse_extended() recursive and allow a tree
|
||||
* of extended partitions.)
|
||||
* It should be a link to the next logical partition.
|
||||
*/
|
||||
p -= 4;
|
||||
for (i=0; i<4; i++, 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;
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
done:
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
|
||||
/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
|
||||
indicates linux swap. Be careful before believing this is Solaris. */
|
||||
|
||||
static void parse_solaris_x86(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_SOLARIS_X86_PARTITION
|
||||
Sector sect;
|
||||
struct solaris_x86_vtoc *v;
|
||||
int i;
|
||||
short max_nparts;
|
||||
|
||||
v = read_part_sector(state, offset + 1, §);
|
||||
if (!v)
|
||||
return;
|
||||
if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
{
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
if (le32_to_cpu(v->v_version) != 1) {
|
||||
char tmp[64];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n",
|
||||
le32_to_cpu(v->v_version));
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
/* Ensure we can handle previous case of VTOC with 8 entries gracefully */
|
||||
max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8;
|
||||
for (i=0; i<max_nparts && state->next<state->limit; i++) {
|
||||
struct solaris_x86_slice *s = &v->v_slice[i];
|
||||
char tmp[3 + 10 + 1 + 1];
|
||||
|
||||
if (s->s_size == 0)
|
||||
continue;
|
||||
snprintf(tmp, sizeof(tmp), " [s%d]", i);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/* solaris partitions are relative to current MS-DOS
|
||||
* one; must add the offset of the current partition */
|
||||
put_partition(state, state->next++,
|
||||
le32_to_cpu(s->s_start)+offset,
|
||||
le32_to_cpu(s->s_size));
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BSD_DISKLABEL)
|
||||
/*
|
||||
* Create devices for BSD partitions listed in a disklabel, under a
|
||||
* dos-like partition. See parse_extended() for more information.
|
||||
*/
|
||||
static void parse_bsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin, char *flavour,
|
||||
int max_partitions)
|
||||
{
|
||||
Sector sect;
|
||||
struct bsd_disklabel *l;
|
||||
struct bsd_partition *p;
|
||||
char tmp[64];
|
||||
|
||||
l = read_part_sector(state, offset + 1, §);
|
||||
if (!l)
|
||||
return;
|
||||
if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
|
||||
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++) {
|
||||
sector_t bsd_start, bsd_size;
|
||||
|
||||
if (state->next == state->limit)
|
||||
break;
|
||||
if (p->p_fstype == BSD_FS_UNUSED)
|
||||
continue;
|
||||
bsd_start = le32_to_cpu(p->p_offset);
|
||||
bsd_size = le32_to_cpu(p->p_size);
|
||||
if (offset == bsd_start && size == bsd_size)
|
||||
/* full parent partition, we have it already */
|
||||
continue;
|
||||
if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
|
||||
strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
put_partition(state, state->next++, bsd_start, bsd_size);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
if (le16_to_cpu(l->d_npartitions) > max_partitions) {
|
||||
snprintf(tmp, sizeof(tmp), " (ignored %d more)",
|
||||
le16_to_cpu(l->d_npartitions) - max_partitions);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void parse_freebsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_netbsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_openbsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, offset, size, origin, "openbsd",
|
||||
OPENBSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Create devices for Unixware partitions listed in a disklabel, under a
|
||||
* dos-like partition. See parse_extended() for more information.
|
||||
*/
|
||||
static void parse_unixware(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_UNIXWARE_DISKLABEL
|
||||
Sector sect;
|
||||
struct unixware_disklabel *l;
|
||||
struct unixware_slice *p;
|
||||
|
||||
l = read_part_sector(state, offset + 29, §);
|
||||
if (!l)
|
||||
return;
|
||||
if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
|
||||
le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
{
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
p = &l->vtoc.v_slice[1];
|
||||
/* I omit the 0th slice as it is the same as whole disk. */
|
||||
while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
|
||||
if (state->next == state->limit)
|
||||
break;
|
||||
|
||||
if (p->s_label != UNIXWARE_FS_UNUSED)
|
||||
put_partition(state, state->next++,
|
||||
le32_to_cpu(p->start_sect),
|
||||
le32_to_cpu(p->nr_sects));
|
||||
p++;
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Minix 2.0.0/2.0.2 subpartition support.
|
||||
* Anand Krishnamurthy <anandk@wiproge.med.ge.com>
|
||||
* Rajeev V. Pillai <rajeevvp@yahoo.com>
|
||||
*/
|
||||
static void parse_minix(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_MINIX_SUBPARTITION
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct partition *p;
|
||||
int i;
|
||||
|
||||
data = read_part_sector(state, offset, §);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
p = (struct partition *)(data + 0x1be);
|
||||
|
||||
/* The first sector of a Minix partition can have either
|
||||
* a secondary MBR describing its subpartitions, or
|
||||
* the normal boot sector. */
|
||||
if (msdos_magic_present (data + 510) &&
|
||||
SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
|
||||
if (state->next == state->limit)
|
||||
break;
|
||||
/* add each partition in use */
|
||||
if (SYS_IND(p) == MINIX_PARTITION)
|
||||
put_partition(state, state->next++,
|
||||
start_sect(p), nr_sects(p));
|
||||
}
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
#endif /* CONFIG_MINIX_SUBPARTITION */
|
||||
}
|
||||
|
||||
static struct {
|
||||
unsigned char id;
|
||||
void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
|
||||
} subtypes[] = {
|
||||
{FREEBSD_PARTITION, parse_freebsd},
|
||||
{NETBSD_PARTITION, parse_netbsd},
|
||||
{OPENBSD_PARTITION, parse_openbsd},
|
||||
{MINIX_PARTITION, parse_minix},
|
||||
{UNIXWARE_PARTITION, parse_unixware},
|
||||
{SOLARIS_X86_PARTITION, parse_solaris_x86},
|
||||
{NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
int msdos_partition(struct parsed_partitions *state)
|
||||
{
|
||||
sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct partition *p;
|
||||
struct fat_boot_sector *fb;
|
||||
int slot;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
if (!msdos_magic_present(data + 510)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aix_magic_present(state, data)) {
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that the 55aa signature is present, this is probably
|
||||
* either the boot sector of a FAT filesystem or a DOS-type
|
||||
* partition table. Reject this in case the boot indicator
|
||||
* is not 0 or 0x80.
|
||||
*/
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
for (slot = 1; slot <= 4; slot++, p++) {
|
||||
if (p->boot_ind != 0 && p->boot_ind != 0x80) {
|
||||
/*
|
||||
* Even without a valid boot inidicator value
|
||||
* its still possible this is valid FAT filesystem
|
||||
* without a partition table.
|
||||
*/
|
||||
fb = (struct fat_boot_sector *) data;
|
||||
if (slot == 1 && fb->reserved && fb->fats
|
||||
&& fat_valid_media(fb->media)) {
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
} else {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_PARTITION
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
for (slot = 1 ; slot <= 4 ; slot++, p++) {
|
||||
/* If this is an EFI GPT disk, msdos should ignore it. */
|
||||
if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
|
||||
/*
|
||||
* Look for partitions in two passes:
|
||||
* First find the primary and DOS-type extended partitions.
|
||||
* On the second pass look inside *BSD, Unixware and Solaris partitions.
|
||||
*/
|
||||
|
||||
state->next = 5;
|
||||
for (slot = 1 ; slot <= 4 ; slot++, p++) {
|
||||
sector_t start = start_sect(p)*sector_size;
|
||||
sector_t size = nr_sects(p)*sector_size;
|
||||
if (!size)
|
||||
continue;
|
||||
if (is_extended_partition(p)) {
|
||||
/*
|
||||
* prevent someone doing mkfs or mkswap on an
|
||||
* extended partition, but leave room for LILO
|
||||
* FIXME: this uses one logical sector for > 512b
|
||||
* sector, although it may not be enough/proper.
|
||||
*/
|
||||
sector_t n = 2;
|
||||
n = min(size, max(sector_size, n));
|
||||
put_partition(state, slot, start, n);
|
||||
|
||||
strlcat(state->pp_buf, " <", PAGE_SIZE);
|
||||
parse_extended(state, start, size);
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
put_partition(state, slot, start, size);
|
||||
if (SYS_IND(p) == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags = ADDPART_FLAG_RAID;
|
||||
if (SYS_IND(p) == DM6_PARTITION)
|
||||
strlcat(state->pp_buf, "[DM]", PAGE_SIZE);
|
||||
if (SYS_IND(p) == EZD_PARTITION)
|
||||
strlcat(state->pp_buf, "[EZD]", PAGE_SIZE);
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
/* second pass - output for each on a separate line */
|
||||
p = (struct partition *) (0x1be + data);
|
||||
for (slot = 1 ; slot <= 4 ; slot++, p++) {
|
||||
unsigned char id = SYS_IND(p);
|
||||
int n;
|
||||
|
||||
if (!nr_sects(p))
|
||||
continue;
|
||||
|
||||
for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
|
||||
;
|
||||
|
||||
if (!subtypes[n].parse)
|
||||
continue;
|
||||
subtypes[n].parse(state, start_sect(p) * sector_size,
|
||||
nr_sects(p) * sector_size, slot);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
8
block/partitions/msdos.h
Normal file
8
block/partitions/msdos.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/msdos.h
|
||||
*/
|
||||
|
||||
#define MSDOS_LABEL_MAGIC 0xAA55
|
||||
|
||||
int msdos_partition(struct parsed_partitions *state);
|
||||
|
||||
86
block/partitions/osf.c
Normal file
86
block/partitions/osf.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* fs/partitions/osf.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "osf.h"
|
||||
|
||||
#define MAX_OSF_PARTITIONS 18
|
||||
|
||||
int osf_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
int slot = 1;
|
||||
unsigned int npartitions;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct disklabel {
|
||||
__le32 d_magic;
|
||||
__le16 d_type,d_subtype;
|
||||
u8 d_typename[16];
|
||||
u8 d_packname[16];
|
||||
__le32 d_secsize;
|
||||
__le32 d_nsectors;
|
||||
__le32 d_ntracks;
|
||||
__le32 d_ncylinders;
|
||||
__le32 d_secpercyl;
|
||||
__le32 d_secprtunit;
|
||||
__le16 d_sparespertrack;
|
||||
__le16 d_sparespercyl;
|
||||
__le32 d_acylinders;
|
||||
__le16 d_rpm, d_interleave, d_trackskew, d_cylskew;
|
||||
__le32 d_headswitch, d_trkseek, d_flags;
|
||||
__le32 d_drivedata[5];
|
||||
__le32 d_spare[5];
|
||||
__le32 d_magic2;
|
||||
__le16 d_checksum;
|
||||
__le16 d_npartitions;
|
||||
__le32 d_bbsize, d_sbsize;
|
||||
struct d_partition {
|
||||
__le32 p_size;
|
||||
__le32 p_offset;
|
||||
__le32 p_fsize;
|
||||
u8 p_fstype;
|
||||
u8 p_frag;
|
||||
__le16 p_cpg;
|
||||
} d_partitions[MAX_OSF_PARTITIONS];
|
||||
} * label;
|
||||
struct d_partition * partition;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct disklabel *) (data+64);
|
||||
partition = label->d_partitions;
|
||||
if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
npartitions = le16_to_cpu(label->d_npartitions);
|
||||
if (npartitions > MAX_OSF_PARTITIONS) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0 ; i < npartitions; i++, partition++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
if (le32_to_cpu(partition->p_size))
|
||||
put_partition(state, slot,
|
||||
le32_to_cpu(partition->p_offset),
|
||||
le32_to_cpu(partition->p_size));
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
7
block/partitions/osf.h
Normal file
7
block/partitions/osf.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* fs/partitions/osf.h
|
||||
*/
|
||||
|
||||
#define DISKLABELMAGIC (0x82564557UL)
|
||||
|
||||
int osf_partition(struct parsed_partitions *state);
|
||||
82
block/partitions/sgi.c
Normal file
82
block/partitions/sgi.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* fs/partitions/sgi.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sgi.h"
|
||||
|
||||
struct sgi_disklabel {
|
||||
__be32 magic_mushroom; /* Big fat spliff... */
|
||||
__be16 root_part_num; /* Root partition number */
|
||||
__be16 swap_part_num; /* Swap partition number */
|
||||
s8 boot_file[16]; /* Name of boot file for ARCS */
|
||||
u8 _unused0[48]; /* Device parameter useless crapola.. */
|
||||
struct sgi_volume {
|
||||
s8 name[8]; /* Name of volume */
|
||||
__be32 block_num; /* Logical block number */
|
||||
__be32 num_bytes; /* How big, in bytes */
|
||||
} volume[15];
|
||||
struct sgi_partition {
|
||||
__be32 num_blocks; /* Size in logical blocks */
|
||||
__be32 first_block; /* First logical block */
|
||||
__be32 type; /* Type of this partition */
|
||||
} partitions[16];
|
||||
__be32 csum; /* Disk label checksum */
|
||||
__be32 _unused1; /* Padding */
|
||||
};
|
||||
|
||||
int sgi_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i, csum;
|
||||
__be32 magic;
|
||||
int slot = 1;
|
||||
unsigned int start, blocks;
|
||||
__be32 *ui, cs;
|
||||
Sector sect;
|
||||
struct sgi_disklabel *label;
|
||||
struct sgi_partition *p;
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
label = read_part_sector(state, 0, §);
|
||||
if (!label)
|
||||
return -1;
|
||||
p = &label->partitions[0];
|
||||
magic = label->magic_mushroom;
|
||||
if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
|
||||
/*printk("Dev %s SGI disklabel: bad magic %08x\n",
|
||||
bdevname(bdev, b), be32_to_cpu(magic));*/
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
ui = ((__be32 *) (label + 1)) - 1;
|
||||
for(csum = 0; ui >= ((__be32 *) label);) {
|
||||
cs = *ui--;
|
||||
csum += be32_to_cpu(cs);
|
||||
}
|
||||
if(csum) {
|
||||
printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
|
||||
bdevname(state->bdev, b));
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
/* All SGI disk labels have 16 partitions, disks under Linux only
|
||||
* have 15 minor's. Luckily there are always a few zero length
|
||||
* partitions which we don't care about so we never overflow the
|
||||
* current_minor.
|
||||
*/
|
||||
for(i = 0; i < 16; i++, p++) {
|
||||
blocks = be32_to_cpu(p->num_blocks);
|
||||
start = be32_to_cpu(p->first_block);
|
||||
if (blocks) {
|
||||
put_partition(state, slot, start, blocks);
|
||||
if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags = ADDPART_FLAG_RAID;
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
8
block/partitions/sgi.h
Normal file
8
block/partitions/sgi.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/sgi.h
|
||||
*/
|
||||
|
||||
extern int sgi_partition(struct parsed_partitions *state);
|
||||
|
||||
#define SGI_LABEL_MAGIC 0x0be5a941
|
||||
|
||||
122
block/partitions/sun.c
Normal file
122
block/partitions/sun.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* fs/partitions/sun.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sun.h"
|
||||
|
||||
int sun_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
__be16 csum;
|
||||
int slot = 1;
|
||||
__be16 *ush;
|
||||
Sector sect;
|
||||
struct sun_disklabel {
|
||||
unsigned char info[128]; /* Informative text string */
|
||||
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 */
|
||||
__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 */
|
||||
__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;
|
||||
struct sun_partition *p;
|
||||
unsigned long spc;
|
||||
char b[BDEVNAME_SIZE];
|
||||
int use_vtoc;
|
||||
int nparts;
|
||||
|
||||
label = read_part_sector(state, 0, §);
|
||||
if (!label)
|
||||
return -1;
|
||||
|
||||
p = label->partitions;
|
||||
if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
|
||||
/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
|
||||
bdevname(bdev, b), be16_to_cpu(label->magic)); */
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
/* Look at the checksum */
|
||||
ush = ((__be16 *) (label+1)) - 1;
|
||||
for (csum = 0; ush >= ((__be16 *) label);)
|
||||
csum ^= *ush--;
|
||||
if (csum) {
|
||||
printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
|
||||
bdevname(state->bdev, b));
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 < nparts; i++, p++) {
|
||||
unsigned long st_sector;
|
||||
unsigned int num_sectors;
|
||||
|
||||
st_sector = be32_to_cpu(p->start_cylinder) * spc;
|
||||
num_sectors = be32_to_cpu(p->num_sectors);
|
||||
if (num_sectors) {
|
||||
put_partition(state, slot, st_sector, num_sectors);
|
||||
state->parts[slot].flags = 0;
|
||||
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++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
8
block/partitions/sun.h
Normal file
8
block/partitions/sun.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/sun.h
|
||||
*/
|
||||
|
||||
#define SUN_LABEL_MAGIC 0xDABE
|
||||
#define SUN_VTOC_SANITY 0x600DDEEE
|
||||
|
||||
int sun_partition(struct parsed_partitions *state);
|
||||
95
block/partitions/sysv68.c
Normal file
95
block/partitions/sysv68.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* fs/partitions/sysv68.c
|
||||
*
|
||||
* Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be>
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sysv68.h"
|
||||
|
||||
/*
|
||||
* Volume ID structure: on first 256-bytes sector of disk
|
||||
*/
|
||||
|
||||
struct volumeid {
|
||||
u8 vid_unused[248];
|
||||
u8 vid_mac[8]; /* ASCII string "MOTOROLA" */
|
||||
};
|
||||
|
||||
/*
|
||||
* config block: second 256-bytes sector on disk
|
||||
*/
|
||||
|
||||
struct dkconfig {
|
||||
u8 ios_unused0[128];
|
||||
__be32 ios_slcblk; /* Slice table block number */
|
||||
__be16 ios_slccnt; /* Number of entries in slice table */
|
||||
u8 ios_unused1[122];
|
||||
};
|
||||
|
||||
/*
|
||||
* combined volumeid and dkconfig block
|
||||
*/
|
||||
|
||||
struct dkblk0 {
|
||||
struct volumeid dk_vid;
|
||||
struct dkconfig dk_ios;
|
||||
};
|
||||
|
||||
/*
|
||||
* Slice Table Structure
|
||||
*/
|
||||
|
||||
struct slice {
|
||||
__be32 nblocks; /* slice size (in blocks) */
|
||||
__be32 blkoff; /* block offset of slice */
|
||||
};
|
||||
|
||||
|
||||
int sysv68_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i, slices;
|
||||
int slot = 1;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct dkblk0 *b;
|
||||
struct slice *slice;
|
||||
char tmp[64];
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
b = (struct dkblk0 *)data;
|
||||
if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
slices = be16_to_cpu(b->dk_ios.ios_slccnt);
|
||||
i = be32_to_cpu(b->dk_ios.ios_slcblk);
|
||||
put_dev_sector(sect);
|
||||
|
||||
data = read_part_sector(state, i, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
slices -= 1; /* last slice is the whole disk */
|
||||
snprintf(tmp, sizeof(tmp), "sysV68: %s(s%u)", state->name, slices);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
slice = (struct slice *)data;
|
||||
for (i = 0; i < slices; i++, slice++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
if (be32_to_cpu(slice->nblocks)) {
|
||||
put_partition(state, slot,
|
||||
be32_to_cpu(slice->blkoff),
|
||||
be32_to_cpu(slice->nblocks));
|
||||
snprintf(tmp, sizeof(tmp), "(s%u)", i);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
1
block/partitions/sysv68.h
Normal file
1
block/partitions/sysv68.h
Normal file
@@ -0,0 +1 @@
|
||||
extern int sysv68_partition(struct parsed_partitions *state);
|
||||
48
block/partitions/ultrix.c
Normal file
48
block/partitions/ultrix.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* fs/partitions/ultrix.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Re-organised Jul 1999 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "ultrix.h"
|
||||
|
||||
int ultrix_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct ultrix_disklabel {
|
||||
s32 pt_magic; /* magic no. indicating part. info exits */
|
||||
s32 pt_valid; /* set by driver if pt is current */
|
||||
struct pt_info {
|
||||
s32 pi_nblocks; /* no. of sectors */
|
||||
u32 pi_blkoff; /* block offset for start */
|
||||
} pt_part[8];
|
||||
} *label;
|
||||
|
||||
#define PT_MAGIC 0x032957 /* Partition magic number */
|
||||
#define PT_VALID 1 /* Indicates if struct is valid */
|
||||
|
||||
data = read_part_sector(state, (16384 - sizeof(*label))/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
|
||||
|
||||
if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
|
||||
for (i=0; i<8; i++)
|
||||
if (label->pt_part[i].pi_nblocks)
|
||||
put_partition(state, i+1,
|
||||
label->pt_part[i].pi_blkoff,
|
||||
label->pt_part[i].pi_nblocks);
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
} else {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
5
block/partitions/ultrix.h
Normal file
5
block/partitions/ultrix.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* fs/partitions/ultrix.h
|
||||
*/
|
||||
|
||||
int ultrix_partition(struct parsed_partitions *state);
|
||||
Reference in New Issue
Block a user