move fs/partitions to block/

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro
2011-09-16 00:25:05 -04:00
parent 4752bc309b
commit 9be96f3fd1
36 changed files with 8 additions and 10 deletions

251
block/partitions/Kconfig Normal file
View 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
View 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
View 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, &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, &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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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
View 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
View 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, &sect);
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, &sect);
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
View File

@@ -0,0 +1,6 @@
/*
* fs/partitions/amiga.h
*/
int amiga_partition(struct parsed_partitions *state);

149
block/partitions/atari.c Normal file
View 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, &sect);
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, &sect2);
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
View 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
View 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
View 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
View 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++, &sect);
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
View 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
View 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, &sect);
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),
&sect);
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), &sect);
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), &sect);
}
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
View File

@@ -0,0 +1 @@
int ibm_partition(struct parsed_partitions *);

57
block/partitions/karma.c Normal file
View 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, &sect);
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
View 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

File diff suppressed because it is too large Load Diff

215
block/partitions/ldm.h Normal file
View 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
View 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, &sect);
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, &sect);
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, &sect);
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
View 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
View 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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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
View 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
View 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, &sect);
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
View 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
View 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, &sect);
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
View 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
View 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, &sect);
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
View 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
View 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, &sect);
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, &sect);
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;
}

View File

@@ -0,0 +1 @@
extern int sysv68_partition(struct parsed_partitions *state);

48
block/partitions/ultrix.c Normal file
View 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, &sect);
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;
}
}

View File

@@ -0,0 +1,5 @@
/*
* fs/partitions/ultrix.h
*/
int ultrix_partition(struct parsed_partitions *state);