Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
238
fs/partitions/Kconfig
Normal file
238
fs/partitions/Kconfig
Normal file
@@ -0,0 +1,238 @@
|
||||
#
|
||||
# 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 or XP's Logical Disk Manager.
|
||||
They are also known as "Dynamic Disks".
|
||||
|
||||
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 and
|
||||
XP.
|
||||
|
||||
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 (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
|
||||
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.
|
||||
19
fs/partitions/Makefile
Normal file
19
fs/partitions/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# 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
|
||||
556
fs/partitions/acorn.c
Normal file
556
fs/partitions/acorn.c
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* linux/fs/partitions/acorn.c
|
||||
*
|
||||
* Copyright (c) 1996-2000 Russell King.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Scan ADFS partitions on hard disk drives. Unfortunately, there
|
||||
* isn't a standard for partitioning drives on Acorn machines, so
|
||||
* every single manufacturer of SCSI and IDE cards created their own
|
||||
* method.
|
||||
*/
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/adfs_fs.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "acorn.h"
|
||||
|
||||
/*
|
||||
* Partition types. (Oh for reusability)
|
||||
*/
|
||||
#define PARTITION_RISCIX_MFM 1
|
||||
#define PARTITION_RISCIX_SCSI 2
|
||||
#define PARTITION_LINUX 9
|
||||
|
||||
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)
|
||||
printk(" [%s]", name);
|
||||
put_partition(state, slot, first_sector, nr_sects);
|
||||
return dr;
|
||||
}
|
||||
|
||||
#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];
|
||||
};
|
||||
|
||||
static int
|
||||
riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
|
||||
unsigned long first_sect, int slot, unsigned long nr_sects)
|
||||
{
|
||||
Sector sect;
|
||||
struct riscix_record *rr;
|
||||
|
||||
rr = (struct riscix_record *)read_dev_sector(bdev, first_sect, §);
|
||||
if (!rr)
|
||||
return -1;
|
||||
|
||||
printk(" [RISCiX]");
|
||||
|
||||
|
||||
if (rr->magic == RISCIX_MAGIC) {
|
||||
unsigned long size = nr_sects > 2 ? 2 : nr_sects;
|
||||
int part;
|
||||
|
||||
printk(" <");
|
||||
|
||||
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));
|
||||
printk("(%s)", rr->part[part].name);
|
||||
}
|
||||
}
|
||||
|
||||
printk(" >\n");
|
||||
} else {
|
||||
put_partition(state, slot++, first_sect, nr_sects);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define LINUX_NATIVE_MAGIC 0xdeafa1de
|
||||
#define LINUX_SWAP_MAGIC 0xdeafab1e
|
||||
|
||||
struct linux_part {
|
||||
__le32 magic;
|
||||
__le32 start_sect;
|
||||
__le32 nr_sects;
|
||||
};
|
||||
|
||||
static int
|
||||
linux_partition(struct parsed_partitions *state, struct block_device *bdev,
|
||||
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;
|
||||
|
||||
printk(" [Linux]");
|
||||
|
||||
put_partition(state, slot++, first_sect, size);
|
||||
|
||||
linuxp = (struct linux_part *)read_dev_sector(bdev, first_sect, §);
|
||||
if (!linuxp)
|
||||
return -1;
|
||||
|
||||
printk(" <");
|
||||
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 ++;
|
||||
}
|
||||
printk(" >");
|
||||
|
||||
put_dev_sector(sect);
|
||||
return slot;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_CUMANA
|
||||
int
|
||||
adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
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_dev_sector(bdev, start_blk * 2 + 6, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
dr = adfs_partition(state, name, data, first_sector, slot++);
|
||||
if (!dr)
|
||||
break;
|
||||
|
||||
name = NULL;
|
||||
|
||||
nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
|
||||
(dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
|
||||
dr->secspertrack;
|
||||
|
||||
if (!nr_sects)
|
||||
break;
|
||||
|
||||
first = 0;
|
||||
first_sector += nr_sects;
|
||||
start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
|
||||
nr_sects = 0; /* hmm - should be partition size */
|
||||
|
||||
switch (data[0x1fc] & 15) {
|
||||
case 0: /* No partition / ADFS? */
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
case PARTITION_RISCIX_SCSI:
|
||||
/* RISCiX - we don't know how to find the next one. */
|
||||
slot = riscix_partition(state, bdev, first_sector,
|
||||
slot, nr_sects);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PARTITION_LINUX:
|
||||
slot = linux_partition(state, bdev, 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, struct block_device *bdev)
|
||||
{
|
||||
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_dev_sector(bdev, 6, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
dr = adfs_partition(state, "ADFS", data, 0, slot++);
|
||||
if (!dr) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
heads = dr->heads + ((dr->lowsector >> 6) & 1);
|
||||
sectscyl = dr->secspertrack * heads;
|
||||
start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
|
||||
id = data[0x1fc] & 15;
|
||||
put_dev_sector(sect);
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_MFM
|
||||
if (MAJOR(bdev->bd_dev) == MFM_ACORN_MAJOR) {
|
||||
extern void xd_set_geometry(struct block_device *,
|
||||
unsigned char, unsigned char, unsigned int);
|
||||
xd_set_geometry(bdev, dr->secspertrack, heads, 1);
|
||||
invalidate_bdev(bdev, 1);
|
||||
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Work out start of non-adfs partition.
|
||||
*/
|
||||
nr_sects = (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, bdev, start_sect,
|
||||
slot, nr_sects);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PARTITION_LINUX:
|
||||
slot = linux_partition(state, bdev, start_sect,
|
||||
slot, nr_sects);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_ICS
|
||||
|
||||
struct ics_part {
|
||||
__le32 start;
|
||||
__le32 size;
|
||||
};
|
||||
|
||||
static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data = read_dev_sector(bdev, block, §);
|
||||
int result = 0;
|
||||
|
||||
if (data) {
|
||||
if (memcmp(data, "LinuxPart", 9) == 0)
|
||||
result = 1;
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a valid ICS partition using the checksum.
|
||||
*/
|
||||
static inline int valid_ics_sector(const unsigned char *data)
|
||||
{
|
||||
unsigned long sum;
|
||||
int i;
|
||||
|
||||
for (i = 0, sum = 0x50617274; i < 508; i++)
|
||||
sum += data[i];
|
||||
|
||||
sum -= le32_to_cpu(*(__le32 *)(&data[508]));
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Purpose: allocate ICS partitions.
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
* Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition 0 on first drive.
|
||||
* hda2 = ADFS partition 1 on first drive.
|
||||
* ..etc..
|
||||
*/
|
||||
int
|
||||
adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
const unsigned char *data;
|
||||
const struct ics_part *p;
|
||||
int slot;
|
||||
Sector sect;
|
||||
|
||||
/*
|
||||
* Try ICS style partitions - sector 0 contains partition info.
|
||||
*/
|
||||
data = read_dev_sector(bdev, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (!valid_ics_sector(data)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(" [ICS]");
|
||||
|
||||
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(bdev, start)) {
|
||||
start += 1;
|
||||
size -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
put_partition(state, slot++, start, size);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
printk("\n");
|
||||
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, struct block_device *bdev)
|
||||
{
|
||||
Sector sect;
|
||||
const unsigned char *data;
|
||||
const struct ptec_part *p;
|
||||
int slot = 1;
|
||||
int i;
|
||||
|
||||
data = read_dev_sector(bdev, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (!valid_ptec_sector(data)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(" [POWERTEC]");
|
||||
|
||||
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);
|
||||
printk("\n");
|
||||
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, struct block_device *bdev)
|
||||
{
|
||||
Sector sect;
|
||||
const unsigned char *data;
|
||||
unsigned char buffer[256];
|
||||
struct eesox_part *p;
|
||||
sector_t start = 0;
|
||||
int i, slot = 1;
|
||||
|
||||
data = read_dev_sector(bdev, 7, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* "Decrypt" the partition table. God knows why...
|
||||
*/
|
||||
for (i = 0; i < 256; i++)
|
||||
buffer[i] = data[i] ^ eesox_name[i & 15];
|
||||
|
||||
put_dev_sector(sect);
|
||||
|
||||
for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
|
||||
sector_t next;
|
||||
|
||||
if (memcmp(p->magic, "Eesox", 6))
|
||||
break;
|
||||
|
||||
next = le32_to_cpu(p->start);
|
||||
if (i)
|
||||
put_partition(state, slot++, start, next - start);
|
||||
start = next;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
sector_t size;
|
||||
|
||||
size = get_capacity(bdev->bd_disk);
|
||||
put_partition(state, slot++, start, size - start);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
return i ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
14
fs/partitions/acorn.h
Normal file
14
fs/partitions/acorn.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* linux/fs/partitions/acorn.h
|
||||
*
|
||||
* Copyright (C) 1996-2001 Russell King.
|
||||
*
|
||||
* I _hate_ this partitioning mess - why can't we have one defined
|
||||
* format, and everyone stick to it?
|
||||
*/
|
||||
|
||||
int adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev);
|
||||
int adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev);
|
||||
int adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev);
|
||||
int adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev);
|
||||
int adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev);
|
||||
130
fs/partitions/amiga.c
Normal file
130
fs/partitions/amiga.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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, struct block_device *bdev)
|
||||
{
|
||||
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_dev_sector(bdev, blk, §);
|
||||
if (!data) {
|
||||
if (warn_no_part)
|
||||
printk("Dev %s: unable to read RDB block %d\n",
|
||||
bdevname(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(bdev, b), blk);
|
||||
}
|
||||
|
||||
/* blksize is blocks per 512 byte standard block */
|
||||
blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512;
|
||||
|
||||
printk(" RDSK (%d)", blksize * 512); /* Be more informative */
|
||||
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_dev_sector(bdev, blk, §);
|
||||
if (!data) {
|
||||
if (warn_no_part)
|
||||
printk("Dev %s: unable to read partition block %d\n",
|
||||
bdevname(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];
|
||||
__be32 *dt = (__be32 *)dostype;
|
||||
*dt = pb->pb_Environment[16];
|
||||
if (dostype[3] < ' ')
|
||||
printk(" (%c%c%c^%c)",
|
||||
dostype[0], dostype[1],
|
||||
dostype[2], dostype[3] + '@' );
|
||||
else
|
||||
printk(" (%c%c%c%c)",
|
||||
dostype[0], dostype[1],
|
||||
dostype[2], dostype[3]);
|
||||
printk("(res %d spb %d)",
|
||||
be32_to_cpu(pb->pb_Environment[6]),
|
||||
be32_to_cpu(pb->pb_Environment[4]));
|
||||
}
|
||||
res = 1;
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
rdb_done:
|
||||
return res;
|
||||
}
|
||||
6
fs/partitions/amiga.h
Normal file
6
fs/partitions/amiga.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* fs/partitions/amiga.h
|
||||
*/
|
||||
|
||||
int amiga_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
|
||||
149
fs/partitions/atari.c
Normal file
149
fs/partitions/atari.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* fs/partitions/atari.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include "check.h"
|
||||
#include "atari.h"
|
||||
|
||||
/* ++guenther: this should be settable by the user ("make config")?.
|
||||
*/
|
||||
#define ICD_PARTS
|
||||
|
||||
/* check if a partition entry looks valid -- Atari format is assumed if at
|
||||
least one of the primary entries is ok this way */
|
||||
#define VALID_PARTITION(pi,hdsiz) \
|
||||
(((pi)->flg & 1) && \
|
||||
isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
|
||||
be32_to_cpu((pi)->st) <= (hdsiz) && \
|
||||
be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
|
||||
|
||||
static inline int OK_id(char *s)
|
||||
{
|
||||
return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 ||
|
||||
memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 ||
|
||||
memcmp (s, "RAW", 3) == 0 ;
|
||||
}
|
||||
|
||||
int atari_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
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 = (struct rootsector *) read_dev_sector(bdev, 0, §);
|
||||
if (!rs)
|
||||
return -1;
|
||||
|
||||
/* Verify this is an Atari rootsector: */
|
||||
hd_size = 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];
|
||||
printk (" AHDI");
|
||||
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
|
||||
printk(" XGM<");
|
||||
partsect = extensect = be32_to_cpu(pi->st);
|
||||
while (1) {
|
||||
xrs = (struct rootsector *)read_dev_sector(bdev, partsect, §2);
|
||||
if (!xrs) {
|
||||
printk (" block %ld read failed\n", partsect);
|
||||
put_dev_sector(sect);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ++roman: sanity check: bit 0 of flg field must be set */
|
||||
if (!(xrs->part[0].flg & 1)) {
|
||||
printk( "\nFirst sub-partition in extended partition is not valid!\n" );
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
|
||||
put_partition(state, slot,
|
||||
partsect + be32_to_cpu(xrs->part[0].st),
|
||||
be32_to_cpu(xrs->part[0].siz));
|
||||
|
||||
if (!(xrs->part[1].flg & 1)) {
|
||||
/* end of linked partition list */
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
|
||||
printk("\nID of extended partition is not XGM!\n");
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
|
||||
partsect = be32_to_cpu(xrs->part[1].st) + extensect;
|
||||
put_dev_sector(sect2);
|
||||
if (++slot == state->limit) {
|
||||
printk( "\nMaximum number of partitions reached!\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
printk(" >");
|
||||
}
|
||||
#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)) {
|
||||
printk(" ICD<");
|
||||
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));
|
||||
}
|
||||
printk(" >");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
put_dev_sector(sect);
|
||||
|
||||
printk ("\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
34
fs/partitions/atari.h
Normal file
34
fs/partitions/atari.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* fs/partitions/atari.h
|
||||
* Moved by Russell King from:
|
||||
*
|
||||
* linux/include/linux/atari_rootsec.h
|
||||
* definitions for Atari Rootsector layout
|
||||
* by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
|
||||
*
|
||||
* modified for ICD/Supra partitioning scheme restricted to at most 12
|
||||
* partitions
|
||||
* by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
|
||||
*/
|
||||
|
||||
struct partition_info
|
||||
{
|
||||
u8 flg; /* bit 0: active; bit 7: bootable */
|
||||
char id[3]; /* "GEM", "BGM", "XGM", or other */
|
||||
__be32 st; /* start of partition */
|
||||
__be32 siz; /* length of partition */
|
||||
};
|
||||
|
||||
struct rootsector
|
||||
{
|
||||
char unused[0x156]; /* room for boot code */
|
||||
struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
|
||||
char unused2[0xc];
|
||||
u32 hd_siz; /* size of disk in blocks */
|
||||
struct partition_info part[4];
|
||||
u32 bsl_st; /* start of bad sector list */
|
||||
u32 bsl_cnt; /* length of bad sector list */
|
||||
u16 checksum; /* checksum for bootable disks */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
int atari_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
619
fs/partitions/check.c
Normal file
619
fs/partitions/check.c
Normal file
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* 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/kmod.h>
|
||||
#include <linux/ctype.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"
|
||||
|
||||
#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 *, struct block_device *) = {
|
||||
/*
|
||||
* 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
|
||||
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 part, char *buf)
|
||||
{
|
||||
if (!part)
|
||||
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, part);
|
||||
else
|
||||
snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *bdevname(struct block_device *bdev, char *buf)
|
||||
{
|
||||
int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor;
|
||||
return disk_name(bdev->bd_disk, part, 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 = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
disk_name(hd, 0, state->name);
|
||||
printk(KERN_INFO " %s:", state->name);
|
||||
if (isdigit(state->name[strlen(state->name)-1]))
|
||||
sprintf(state->name, "p");
|
||||
|
||||
state->limit = hd->minors;
|
||||
i = res = err = 0;
|
||||
while (!res && check_part[i]) {
|
||||
memset(&state->parts, 0, sizeof(state->parts));
|
||||
res = check_part[i++](state, bdev);
|
||||
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)
|
||||
return state;
|
||||
if (err)
|
||||
/* The partition is unrecognized. So report I/O errors if there were any */
|
||||
res = err;
|
||||
if (!res)
|
||||
printk(" unknown partition table\n");
|
||||
else if (warn_no_part)
|
||||
printk(" unable to read partition table\n");
|
||||
kfree(state);
|
||||
return ERR_PTR(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs bindings for partitions
|
||||
*/
|
||||
|
||||
struct part_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct hd_struct *,char *);
|
||||
ssize_t (*store)(struct hd_struct *,const char *, size_t);
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
part_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
|
||||
{
|
||||
struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
|
||||
struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
|
||||
ssize_t ret = 0;
|
||||
if (part_attr->show)
|
||||
ret = part_attr->show(p, page);
|
||||
return ret;
|
||||
}
|
||||
static ssize_t
|
||||
part_attr_store(struct kobject * kobj, struct attribute * attr,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
|
||||
struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (part_attr->store)
|
||||
ret = part_attr->store(p, page, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sysfs_ops part_sysfs_ops = {
|
||||
.show = part_attr_show,
|
||||
.store = part_attr_store,
|
||||
};
|
||||
|
||||
static ssize_t part_uevent_store(struct hd_struct * p,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
return count;
|
||||
}
|
||||
static ssize_t part_dev_read(struct hd_struct * p, char *page)
|
||||
{
|
||||
struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
|
||||
dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno);
|
||||
return print_dev_t(page, dev);
|
||||
}
|
||||
static ssize_t part_start_read(struct hd_struct * p, char *page)
|
||||
{
|
||||
return sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
|
||||
}
|
||||
static ssize_t part_size_read(struct hd_struct * p, char *page)
|
||||
{
|
||||
return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
|
||||
}
|
||||
static ssize_t part_stat_read(struct hd_struct * p, char *page)
|
||||
{
|
||||
return sprintf(page, "%8u %8llu %8u %8llu\n",
|
||||
p->ios[0], (unsigned long long)p->sectors[0],
|
||||
p->ios[1], (unsigned long long)p->sectors[1]);
|
||||
}
|
||||
static struct part_attribute part_attr_uevent = {
|
||||
.attr = {.name = "uevent", .mode = S_IWUSR },
|
||||
.store = part_uevent_store
|
||||
};
|
||||
static struct part_attribute part_attr_dev = {
|
||||
.attr = {.name = "dev", .mode = S_IRUGO },
|
||||
.show = part_dev_read
|
||||
};
|
||||
static struct part_attribute part_attr_start = {
|
||||
.attr = {.name = "start", .mode = S_IRUGO },
|
||||
.show = part_start_read
|
||||
};
|
||||
static struct part_attribute part_attr_size = {
|
||||
.attr = {.name = "size", .mode = S_IRUGO },
|
||||
.show = part_size_read
|
||||
};
|
||||
static struct part_attribute part_attr_stat = {
|
||||
.attr = {.name = "stat", .mode = S_IRUGO },
|
||||
.show = part_stat_read
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
||||
|
||||
static ssize_t part_fail_store(struct hd_struct * p,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (count > 0 && sscanf(buf, "%d", &i) > 0)
|
||||
p->make_it_fail = (i == 0) ? 0 : 1;
|
||||
|
||||
return count;
|
||||
}
|
||||
static ssize_t part_fail_read(struct hd_struct * p, char *page)
|
||||
{
|
||||
return sprintf(page, "%d\n", p->make_it_fail);
|
||||
}
|
||||
static struct part_attribute part_attr_fail = {
|
||||
.attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
|
||||
.store = part_fail_store,
|
||||
.show = part_fail_read
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static struct attribute * default_attrs[] = {
|
||||
&part_attr_uevent.attr,
|
||||
&part_attr_dev.attr,
|
||||
&part_attr_start.attr,
|
||||
&part_attr_size.attr,
|
||||
&part_attr_stat.attr,
|
||||
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
||||
&part_attr_fail.attr,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
extern struct subsystem block_subsys;
|
||||
|
||||
static void part_release(struct kobject *kobj)
|
||||
{
|
||||
struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
struct kobj_type ktype_part = {
|
||||
.release = part_release,
|
||||
.default_attrs = default_attrs,
|
||||
.sysfs_ops = &part_sysfs_ops,
|
||||
};
|
||||
|
||||
static inline void partition_sysfs_add_subdir(struct hd_struct *p)
|
||||
{
|
||||
struct kobject *k;
|
||||
|
||||
k = kobject_get(&p->kobj);
|
||||
p->holder_dir = kobject_add_dir(k, "holders");
|
||||
kobject_put(k);
|
||||
}
|
||||
|
||||
static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
|
||||
{
|
||||
struct kobject *k;
|
||||
|
||||
k = kobject_get(&disk->kobj);
|
||||
disk->holder_dir = kobject_add_dir(k, "holders");
|
||||
disk->slave_dir = kobject_add_dir(k, "slaves");
|
||||
kobject_put(k);
|
||||
}
|
||||
|
||||
void delete_partition(struct gendisk *disk, int part)
|
||||
{
|
||||
struct hd_struct *p = disk->part[part-1];
|
||||
if (!p)
|
||||
return;
|
||||
if (!p->nr_sects)
|
||||
return;
|
||||
disk->part[part-1] = NULL;
|
||||
p->start_sect = 0;
|
||||
p->nr_sects = 0;
|
||||
p->ios[0] = p->ios[1] = 0;
|
||||
p->sectors[0] = p->sectors[1] = 0;
|
||||
sysfs_remove_link(&p->kobj, "subsystem");
|
||||
kobject_unregister(p->holder_dir);
|
||||
kobject_uevent(&p->kobj, KOBJ_REMOVE);
|
||||
kobject_del(&p->kobj);
|
||||
kobject_put(&p->kobj);
|
||||
}
|
||||
|
||||
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags)
|
||||
{
|
||||
struct hd_struct *p;
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->start_sect = start;
|
||||
p->nr_sects = len;
|
||||
p->partno = part;
|
||||
p->policy = disk->policy;
|
||||
|
||||
if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
|
||||
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
|
||||
else
|
||||
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
|
||||
p->kobj.parent = &disk->kobj;
|
||||
p->kobj.ktype = &ktype_part;
|
||||
kobject_init(&p->kobj);
|
||||
kobject_add(&p->kobj);
|
||||
if (!disk->part_uevent_suppress)
|
||||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem");
|
||||
if (flags & ADDPART_FLAG_WHOLEDISK) {
|
||||
static struct attribute addpartattr = {
|
||||
.name = "whole_disk",
|
||||
.mode = S_IRUSR | S_IRGRP | S_IROTH,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
sysfs_create_file(&p->kobj, &addpartattr);
|
||||
}
|
||||
partition_sysfs_add_subdir(p);
|
||||
disk->part[part-1] = p;
|
||||
}
|
||||
|
||||
static char *make_block_name(struct gendisk *disk)
|
||||
{
|
||||
char *name;
|
||||
static char *block_str = "block:";
|
||||
int size;
|
||||
char *s;
|
||||
|
||||
size = strlen(block_str) + strlen(disk->disk_name) + 1;
|
||||
name = kmalloc(size, GFP_KERNEL);
|
||||
if (!name)
|
||||
return NULL;
|
||||
strcpy(name, block_str);
|
||||
strcat(name, disk->disk_name);
|
||||
/* ewww... some of these buggers have / in name... */
|
||||
s = strchr(name, '/');
|
||||
if (s)
|
||||
*s = '!';
|
||||
return name;
|
||||
}
|
||||
|
||||
static int disk_sysfs_symlinks(struct gendisk *disk)
|
||||
{
|
||||
struct device *target = get_device(disk->driverfs_dev);
|
||||
int err;
|
||||
char *disk_name = NULL;
|
||||
|
||||
if (target) {
|
||||
disk_name = make_block_name(disk);
|
||||
if (!disk_name) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = sysfs_create_link(&disk->kobj, &target->kobj, "device");
|
||||
if (err)
|
||||
goto err_out_disk_name;
|
||||
|
||||
err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);
|
||||
if (err)
|
||||
goto err_out_dev_link;
|
||||
}
|
||||
|
||||
err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj,
|
||||
"subsystem");
|
||||
if (err)
|
||||
goto err_out_disk_name_lnk;
|
||||
|
||||
kfree(disk_name);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_disk_name_lnk:
|
||||
if (target) {
|
||||
sysfs_remove_link(&target->kobj, disk_name);
|
||||
err_out_dev_link:
|
||||
sysfs_remove_link(&disk->kobj, "device");
|
||||
err_out_disk_name:
|
||||
kfree(disk_name);
|
||||
err_out:
|
||||
put_device(target);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Not exported, helper to add_disk(). */
|
||||
void register_disk(struct gendisk *disk)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
char *s;
|
||||
int i;
|
||||
struct hd_struct *p;
|
||||
int err;
|
||||
|
||||
strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
|
||||
/* ewww... some of these buggers have / in name... */
|
||||
s = strchr(disk->kobj.name, '/');
|
||||
if (s)
|
||||
*s = '!';
|
||||
if ((err = kobject_add(&disk->kobj)))
|
||||
return;
|
||||
err = disk_sysfs_symlinks(disk);
|
||||
if (err) {
|
||||
kobject_del(&disk->kobj);
|
||||
return;
|
||||
}
|
||||
disk_sysfs_add_subdirs(disk);
|
||||
|
||||
/* No minors to use for partitions */
|
||||
if (disk->minors == 1)
|
||||
goto exit;
|
||||
|
||||
/* No such device (e.g., media were just removed) */
|
||||
if (!get_capacity(disk))
|
||||
goto exit;
|
||||
|
||||
bdev = bdget_disk(disk, 0);
|
||||
if (!bdev)
|
||||
goto exit;
|
||||
|
||||
/* scan partition table, but suppress uevents */
|
||||
bdev->bd_invalidated = 1;
|
||||
disk->part_uevent_suppress = 1;
|
||||
err = blkdev_get(bdev, FMODE_READ, 0);
|
||||
disk->part_uevent_suppress = 0;
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
blkdev_put(bdev);
|
||||
|
||||
exit:
|
||||
/* announce disk after possible partitions are already created */
|
||||
kobject_uevent(&disk->kobj, KOBJ_ADD);
|
||||
|
||||
/* announce possible partitions */
|
||||
for (i = 1; i < disk->minors; i++) {
|
||||
p = disk->part[i-1];
|
||||
if (!p || !p->nr_sects)
|
||||
continue;
|
||||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
}
|
||||
}
|
||||
|
||||
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
|
||||
{
|
||||
struct parsed_partitions *state;
|
||||
int p, res;
|
||||
|
||||
if (bdev->bd_part_count)
|
||||
return -EBUSY;
|
||||
res = invalidate_partition(disk, 0);
|
||||
if (res)
|
||||
return res;
|
||||
bdev->bd_invalidated = 0;
|
||||
for (p = 1; p < disk->minors; p++)
|
||||
delete_partition(disk, p);
|
||||
if (disk->fops->revalidate_disk)
|
||||
disk->fops->revalidate_disk(disk);
|
||||
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
|
||||
return 0;
|
||||
if (IS_ERR(state)) /* I/O error reading the partition table */
|
||||
return -EIO;
|
||||
for (p = 1; p < state->limit; p++) {
|
||||
sector_t size = state->parts[p].size;
|
||||
sector_t from = state->parts[p].from;
|
||||
if (!size)
|
||||
continue;
|
||||
if (from + size > get_capacity(disk)) {
|
||||
printk(" %s: p%d exceeds device capacity\n",
|
||||
disk->disk_name, p);
|
||||
}
|
||||
add_partition(disk, p, from, size, state->parts[p].flags);
|
||||
#ifdef CONFIG_BLK_DEV_MD
|
||||
if (state->parts[p].flags & ADDPART_FLAG_RAID)
|
||||
md_autodetect_dev(bdev->bd_dev+p);
|
||||
#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)) {
|
||||
wait_on_page_locked(page);
|
||||
if (!PageUptodate(page))
|
||||
goto fail;
|
||||
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);
|
||||
|
||||
void del_gendisk(struct gendisk *disk)
|
||||
{
|
||||
int p;
|
||||
|
||||
/* invalidate stuff */
|
||||
for (p = disk->minors - 1; p > 0; p--) {
|
||||
invalidate_partition(disk, p);
|
||||
delete_partition(disk, p);
|
||||
}
|
||||
invalidate_partition(disk, 0);
|
||||
disk->capacity = 0;
|
||||
disk->flags &= ~GENHD_FL_UP;
|
||||
unlink_gendisk(disk);
|
||||
disk_stat_set_all(disk, 0);
|
||||
disk->stamp = 0;
|
||||
|
||||
kobject_uevent(&disk->kobj, KOBJ_REMOVE);
|
||||
kobject_unregister(disk->holder_dir);
|
||||
kobject_unregister(disk->slave_dir);
|
||||
if (disk->driverfs_dev) {
|
||||
char *disk_name = make_block_name(disk);
|
||||
sysfs_remove_link(&disk->kobj, "device");
|
||||
if (disk_name) {
|
||||
sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name);
|
||||
kfree(disk_name);
|
||||
}
|
||||
put_device(disk->driverfs_dev);
|
||||
disk->driverfs_dev = NULL;
|
||||
}
|
||||
sysfs_remove_link(&disk->kobj, "subsystem");
|
||||
kobject_del(&disk->kobj);
|
||||
}
|
||||
32
fs/partitions/check.h
Normal file
32
fs/partitions/check.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
/*
|
||||
* add_gd_partition adds a partitions details to the devices partition
|
||||
* description.
|
||||
*/
|
||||
enum { MAX_PART = 256 };
|
||||
|
||||
struct parsed_partitions {
|
||||
char name[BDEVNAME_SIZE];
|
||||
struct {
|
||||
sector_t from;
|
||||
sector_t size;
|
||||
int flags;
|
||||
} parts[MAX_PART];
|
||||
int next;
|
||||
int limit;
|
||||
};
|
||||
|
||||
static inline void
|
||||
put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
|
||||
{
|
||||
if (n < p->limit) {
|
||||
p->parts[n].from = from;
|
||||
p->parts[n].size = size;
|
||||
printk(" %s%d", p->name, n);
|
||||
}
|
||||
}
|
||||
|
||||
extern int warn_no_part;
|
||||
|
||||
641
fs/partitions/efi.c
Normal file
641
fs/partitions/efi.c
Normal file
@@ -0,0 +1,641 @@
|
||||
/************************************************************
|
||||
* EFI GUID Partition Table handling
|
||||
* Per Intel EFI Specification v1.02
|
||||
* http://developer.intel.com/technology/efi/efi.htm
|
||||
* 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 "check.h"
|
||||
#include "efi.h"
|
||||
|
||||
#undef EFI_DEBUG
|
||||
#ifdef EFI_DEBUG
|
||||
#define Dprintk(x...) printk(KERN_DEBUG x)
|
||||
#else
|
||||
#define Dprintk(x...)
|
||||
#endif
|
||||
|
||||
/* 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 (bdev->bd_inode->i_size >> 9) - 1ULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pmbr_part_valid(struct partition *part, u64 lastlba)
|
||||
{
|
||||
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
|
||||
* @lastlba: last_lba for the whole device
|
||||
*
|
||||
* 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, u64 lastlba)
|
||||
{
|
||||
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], lastlba))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_lba(): Read bytes from disk, starting at given LBA
|
||||
* @bdev
|
||||
* @lba
|
||||
* @buffer
|
||||
* @size_t
|
||||
*
|
||||
* Description: Reads @count bytes from @bdev into @buffer.
|
||||
* Returns number of bytes read on success, 0 on error.
|
||||
*/
|
||||
static size_t
|
||||
read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count)
|
||||
{
|
||||
size_t totalreadcount = 0;
|
||||
|
||||
if (!bdev || !buffer || lba > last_lba(bdev))
|
||||
return 0;
|
||||
|
||||
while (count) {
|
||||
int copied = 512;
|
||||
Sector sect;
|
||||
unsigned char *data = read_dev_sector(bdev, lba++, §);
|
||||
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
|
||||
* @bdev
|
||||
* @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 block_device *bdev, gpt_header *gpt)
|
||||
{
|
||||
size_t count;
|
||||
gpt_entry *pte;
|
||||
if (!bdev || !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(bdev, 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
|
||||
* @bdev
|
||||
* @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 @bdev.
|
||||
* Note: remember to free gpt when finished with it.
|
||||
*/
|
||||
static gpt_header *
|
||||
alloc_read_gpt_header(struct block_device *bdev, u64 lba)
|
||||
{
|
||||
gpt_header *gpt;
|
||||
if (!bdev)
|
||||
return NULL;
|
||||
|
||||
gpt = kzalloc(sizeof (gpt_header), GFP_KERNEL);
|
||||
if (!gpt)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(bdev, lba, (u8 *) gpt,
|
||||
sizeof (gpt_header)) < sizeof (gpt_header)) {
|
||||
kfree(gpt);
|
||||
gpt=NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_gpt_valid() - tests one GPT header and PTEs for validity
|
||||
* @bdev
|
||||
* @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 block_device *bdev, u64 lba,
|
||||
gpt_header **gpt, gpt_entry **ptes)
|
||||
{
|
||||
u32 crc, origcrc;
|
||||
u64 lastlba;
|
||||
|
||||
if (!bdev || !gpt || !ptes)
|
||||
return 0;
|
||||
if (!(*gpt = alloc_read_gpt_header(bdev, lba)))
|
||||
return 0;
|
||||
|
||||
/* Check the GUID Partition Table signature */
|
||||
if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
|
||||
Dprintk("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 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) {
|
||||
Dprintk
|
||||
("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) {
|
||||
Dprintk("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(bdev);
|
||||
if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
|
||||
Dprintk("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) {
|
||||
Dprintk("GPT: last_usable_lba incorrect: %lld > %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
|
||||
(unsigned long long)lastlba);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(*ptes = alloc_read_gpt_entries(bdev, *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)) {
|
||||
Dprintk("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
|
||||
* @bdev
|
||||
* @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 block_device *bdev, 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 = NULL;
|
||||
u64 lastlba;
|
||||
if (!bdev || !gpt || !ptes)
|
||||
return 0;
|
||||
|
||||
lastlba = last_lba(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(bdev, 0, (u8 *) legacymbr,
|
||||
sizeof (*legacymbr));
|
||||
good_pmbr = is_pmbr_valid(legacymbr, lastlba);
|
||||
kfree(legacymbr);
|
||||
legacymbr=NULL;
|
||||
}
|
||||
if (!good_pmbr)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
|
||||
&pgpt, &pptes);
|
||||
if (good_pgpt)
|
||||
good_agpt = is_gpt_valid(bdev,
|
||||
le64_to_cpu(pgpt->alternate_lba),
|
||||
&agpt, &aptes);
|
||||
if (!good_agpt && force_gpt)
|
||||
good_agpt = is_gpt_valid(bdev, 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, struct block_device *bdev)
|
||||
* @state
|
||||
* @bdev
|
||||
*
|
||||
* 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, struct block_device *bdev)
|
||||
{
|
||||
gpt_header *gpt = NULL;
|
||||
gpt_entry *ptes = NULL;
|
||||
u32 i;
|
||||
|
||||
if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) {
|
||||
kfree(gpt);
|
||||
kfree(ptes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Dprintk("GUID Partition Table is valid! Yea!\n");
|
||||
|
||||
for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
|
||||
if (!is_pte_valid(&ptes[i], last_lba(bdev)))
|
||||
continue;
|
||||
|
||||
put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba),
|
||||
(le64_to_cpu(ptes[i].ending_lba) -
|
||||
le64_to_cpu(ptes[i].starting_lba) +
|
||||
1ULL));
|
||||
|
||||
/* 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 = 1;
|
||||
}
|
||||
kfree(ptes);
|
||||
kfree(gpt);
|
||||
printk("\n");
|
||||
return 1;
|
||||
}
|
||||
130
fs/partitions/efi.h
Normal file
130
fs/partitions/efi.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/************************************************************
|
||||
* 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_BLOCK_SIZE 512
|
||||
#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;
|
||||
u8 reserved2[GPT_BLOCK_SIZE - 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, struct block_device *bdev);
|
||||
|
||||
#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:
|
||||
*/
|
||||
193
fs/partitions/ibm.c
Normal file
193
fs/partitions/ibm.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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 inline int
|
||||
cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
|
||||
return ptr->cc * geo->heads * geo->sectors +
|
||||
ptr->hh * geo->sectors;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute the block number from a
|
||||
* cyl-cyl-head-head-block structure
|
||||
*/
|
||||
static inline int
|
||||
cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
|
||||
return ptr->cc * geo->heads * geo->sectors +
|
||||
ptr->hh * geo->sectors +
|
||||
ptr->b;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
int
|
||||
ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
int blocksize, offset, size,res;
|
||||
loff_t i_size;
|
||||
dasd_information_t *info;
|
||||
struct hd_geometry *geo;
|
||||
char type[5] = {0,};
|
||||
char name[7] = {0,};
|
||||
union label_t {
|
||||
struct vtoc_volume_label vol;
|
||||
struct vtoc_cms_label cms;
|
||||
} *label;
|
||||
unsigned char *data;
|
||||
Sector sect;
|
||||
|
||||
res = 0;
|
||||
blocksize = bdev_hardsect_size(bdev);
|
||||
if (blocksize <= 0)
|
||||
goto out_exit;
|
||||
i_size = i_size_read(bdev->bd_inode);
|
||||
if (i_size == 0)
|
||||
goto out_exit;
|
||||
|
||||
if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
|
||||
goto out_exit;
|
||||
if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
|
||||
goto out_nogeo;
|
||||
if ((label = kmalloc(sizeof(union label_t), GFP_KERNEL)) == NULL)
|
||||
goto out_nolab;
|
||||
|
||||
if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
|
||||
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
|
||||
goto out_freeall;
|
||||
|
||||
/*
|
||||
* Get volume label, extract name and type.
|
||||
*/
|
||||
data = read_dev_sector(bdev, info->label_block*(blocksize/512), §);
|
||||
if (data == NULL)
|
||||
goto out_readerr;
|
||||
|
||||
strncpy (type, data, 4);
|
||||
if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD")))
|
||||
strncpy(name, data + 8, 6);
|
||||
else
|
||||
strncpy(name, data + 4, 6);
|
||||
memcpy(label, data, sizeof(union label_t));
|
||||
put_dev_sector(sect);
|
||||
|
||||
EBCASC(type, 4);
|
||||
EBCASC(name, 6);
|
||||
|
||||
res = 1;
|
||||
|
||||
/*
|
||||
* Three different types: CMS1, VOL1 and LNX1/unlabeled
|
||||
*/
|
||||
if (strncmp(type, "CMS1", 4) == 0) {
|
||||
/*
|
||||
* VM style CMS1 labeled disk
|
||||
*/
|
||||
if (label->cms.disk_offset != 0) {
|
||||
printk("CMS1/%8s(MDSK):", name);
|
||||
/* disk is reserved minidisk */
|
||||
blocksize = label->cms.block_size;
|
||||
offset = label->cms.disk_offset;
|
||||
size = (label->cms.block_count - 1) * (blocksize >> 9);
|
||||
} else {
|
||||
printk("CMS1/%8s:", name);
|
||||
offset = (info->label_block + 1);
|
||||
size = i_size >> 9;
|
||||
}
|
||||
put_partition(state, 1, offset*(blocksize >> 9),
|
||||
size-offset*(blocksize >> 9));
|
||||
} else if ((strncmp(type, "VOL1", 4) == 0) &&
|
||||
(!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
|
||||
/*
|
||||
* New style VOL1 labeled disk
|
||||
*/
|
||||
unsigned int blk;
|
||||
int counter;
|
||||
|
||||
printk("VOL1/%8s:", name);
|
||||
|
||||
/* get block number and read then go through format1 labels */
|
||||
blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
|
||||
counter = 0;
|
||||
while ((data = read_dev_sector(bdev, blk*(blocksize/512),
|
||||
§)) != 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']) {
|
||||
blk++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only FMT1 valid at this point */
|
||||
if (f1.DS1FMTID != _ascebc['1'])
|
||||
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++;
|
||||
}
|
||||
if (!data)
|
||||
/* Are we not supposed to report this ? */
|
||||
goto out_readerr;
|
||||
} else {
|
||||
/*
|
||||
* Old style LNX1 or unlabeled disk
|
||||
*/
|
||||
if (strncmp(type, "LNX1", 4) == 0)
|
||||
printk ("LNX1/%8s:", name);
|
||||
else
|
||||
printk("(nonl)/%8s:", name);
|
||||
offset = (info->label_block + 1);
|
||||
size = i_size >> 9;
|
||||
put_partition(state, 1, offset*(blocksize >> 9),
|
||||
size-offset*(blocksize >> 9));
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
goto out_freeall;
|
||||
|
||||
|
||||
out_readerr:
|
||||
res = -1;
|
||||
out_freeall:
|
||||
kfree(label);
|
||||
out_nolab:
|
||||
kfree(geo);
|
||||
out_nogeo:
|
||||
kfree(info);
|
||||
out_exit:
|
||||
return res;
|
||||
}
|
||||
1
fs/partitions/ibm.h
Normal file
1
fs/partitions/ibm.h
Normal file
@@ -0,0 +1 @@
|
||||
int ibm_partition(struct parsed_partitions *, struct block_device *);
|
||||
57
fs/partitions/karma.c
Normal file
57
fs/partitions/karma.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* fs/partitions/karma.c
|
||||
* Rio Karma partition info.
|
||||
*
|
||||
* Copyright (C) 2006 Bob Copeland (me@bobcopeland.com)
|
||||
* based on osf.c
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "karma.h"
|
||||
|
||||
int karma_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
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_dev_sector(bdev, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct disklabel *)data;
|
||||
if (le16_to_cpu(label->d_magic) != KARMA_LABEL_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = label->d_partitions;
|
||||
for (i = 0 ; i < 2; i++, p++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
if (p->p_fstype == 0x4d && le32_to_cpu(p->p_size)) {
|
||||
put_partition(state, slot, le32_to_cpu(p->p_offset),
|
||||
le32_to_cpu(p->p_size));
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
printk("\n");
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
|
||||
8
fs/partitions/karma.h
Normal file
8
fs/partitions/karma.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/karma.h
|
||||
*/
|
||||
|
||||
#define KARMA_LABEL_MAGIC 0xAB56
|
||||
|
||||
int karma_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
|
||||
1478
fs/partitions/ldm.c
Normal file
1478
fs/partitions/ldm.c
Normal file
File diff suppressed because it is too large
Load Diff
220
fs/partitions/ldm.h
Normal file
220
fs/partitions/ldm.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* ldm - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
|
||||
* Copyright (C) 2001 Anton Altaparmakov <aia21@cantab.net>
|
||||
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
|
||||
*
|
||||
* Documentation is available at http://linux-ntfs.sf.net/ldm
|
||||
*
|
||||
* 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 59
|
||||
|
||||
/* 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 WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */
|
||||
|
||||
#define TOC_BITMAP1 "config" /* Names of the two defined */
|
||||
#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
|
||||
|
||||
/* Most numbers we deal with are big-endian and won't be aligned. */
|
||||
#define BE16(x) ((u16)be16_to_cpu(get_unaligned((__be16*)(x))))
|
||||
#define BE32(x) ((u32)be32_to_cpu(get_unaligned((__be32*)(x))))
|
||||
#define BE64(x) ((u64)be64_to_cpu(get_unaligned((__be64*)(x))))
|
||||
|
||||
/* 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, struct block_device *bdev);
|
||||
|
||||
#endif /* _FS_PT_LDM_H_ */
|
||||
|
||||
132
fs/partitions/mac.c
Normal file
132
fs/partitions/mac.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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, struct block_device *bdev)
|
||||
{
|
||||
int slot = 1;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
int blk, 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 = (struct mac_driver_desc *) read_dev_sector(bdev, 0, §);
|
||||
if (!md)
|
||||
return -1;
|
||||
if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
secsize = be16_to_cpu(md->block_size);
|
||||
put_dev_sector(sect);
|
||||
data = read_dev_sector(bdev, secsize/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + secsize%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0; /* not a MacOS disk */
|
||||
}
|
||||
printk(" [mac]");
|
||||
blocks_in_map = be32_to_cpu(part->map_count);
|
||||
for (blk = 1; blk <= blocks_in_map; ++blk) {
|
||||
int pos = blk * secsize;
|
||||
put_dev_sector(sect);
|
||||
data = read_dev_sector(bdev, pos/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + pos%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
|
||||
break;
|
||||
put_partition(state, slot,
|
||||
be32_to_cpu(part->start_block) * (secsize/512),
|
||||
be32_to_cpu(part->block_count) * (secsize/512));
|
||||
|
||||
if (!strnicmp(part->type, "Linux_RAID", 10))
|
||||
state->parts[slot].flags = 1;
|
||||
#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 = blk;
|
||||
found_root_goodness = goodness;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PPC_PMAC */
|
||||
|
||||
++slot;
|
||||
}
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
if (found_root_goodness)
|
||||
note_bootable_part(bdev->bd_dev, found_root, found_root_goodness);
|
||||
#endif
|
||||
|
||||
put_dev_sector(sect);
|
||||
printk("\n");
|
||||
return 1;
|
||||
}
|
||||
44
fs/partitions/mac.h
Normal file
44
fs/partitions/mac.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* fs/partitions/mac.h
|
||||
*/
|
||||
|
||||
#define MAC_PARTITION_MAGIC 0x504d
|
||||
|
||||
/* type field value for A/UX or other Unix partitions */
|
||||
#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
|
||||
|
||||
struct mac_partition {
|
||||
__be16 signature; /* expected to be MAC_PARTITION_MAGIC */
|
||||
__be16 res1;
|
||||
__be32 map_count; /* # blocks in partition map */
|
||||
__be32 start_block; /* absolute starting block # of partition */
|
||||
__be32 block_count; /* number of blocks in partition */
|
||||
char name[32]; /* partition name */
|
||||
char type[32]; /* string type description */
|
||||
__be32 data_start; /* rel block # of first data block */
|
||||
__be32 data_count; /* number of data blocks */
|
||||
__be32 status; /* partition status bits */
|
||||
__be32 boot_start;
|
||||
__be32 boot_size;
|
||||
__be32 boot_load;
|
||||
__be32 boot_load2;
|
||||
__be32 boot_entry;
|
||||
__be32 boot_entry2;
|
||||
__be32 boot_cksum;
|
||||
char processor[16]; /* identifies ISA of boot */
|
||||
/* there is more stuff after this that we don't need */
|
||||
};
|
||||
|
||||
#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
|
||||
|
||||
#define MAC_DRIVER_MAGIC 0x4552
|
||||
|
||||
/* Driver descriptor structure, in block 0 */
|
||||
struct mac_driver_desc {
|
||||
__be16 signature; /* expected to be MAC_DRIVER_MAGIC */
|
||||
__be16 block_size;
|
||||
__be32 block_count;
|
||||
/* ... more stuff */
|
||||
};
|
||||
|
||||
int mac_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
512
fs/partitions/msdos.c
Normal file
512
fs/partitions/msdos.c
Normal file
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* 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 "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))
|
||||
#define NR_SECTS(p) ({ __le32 __a = get_unaligned(&p->nr_sects); \
|
||||
le32_to_cpu(__a); \
|
||||
})
|
||||
|
||||
#define START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \
|
||||
le32_to_cpu(__a); \
|
||||
})
|
||||
|
||||
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(unsigned char *p, struct block_device *bdev)
|
||||
{
|
||||
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_dev_sector(bdev, 7, §);
|
||||
if (d) {
|
||||
if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
|
||||
ret = 1;
|
||||
put_dev_sector(sect);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create devices for each logical partition in an extended partition.
|
||||
* The logical partitions form a linked list, with each entry being
|
||||
* a partition table with two entries. The first entry
|
||||
* is the real data partition (with a start relative to the partition
|
||||
* table start). The second is a pointer to the next logical partition
|
||||
* (with a start relative to the entire extended partition).
|
||||
* We do not create a Linux partition for the partition tables, but
|
||||
* only for the actual data partitions.
|
||||
*/
|
||||
|
||||
static void
|
||||
parse_extended(struct parsed_partitions *state, struct block_device *bdev,
|
||||
u32 first_sector, u32 first_size)
|
||||
{
|
||||
struct partition *p;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
u32 this_sector, this_size;
|
||||
int sector_size = bdev_hardsect_size(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_dev_sector(bdev, this_sector, §);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (!msdos_magic_present(data + 510))
|
||||
goto done;
|
||||
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
|
||||
/*
|
||||
* Usually, the first entry is the real data partition,
|
||||
* the 2nd entry is the next extended partition, or empty,
|
||||
* and the 3rd and 4th entries are unused.
|
||||
* However, DRDOS sometimes has the extended partition as
|
||||
* the first entry (when the data partition is empty),
|
||||
* and OS/2 seems to use all four entries.
|
||||
*/
|
||||
|
||||
/*
|
||||
* First process the data partition(s)
|
||||
*/
|
||||
for (i=0; i<4; i++, p++) {
|
||||
u32 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, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_SOLARIS_X86_PARTITION
|
||||
Sector sect;
|
||||
struct solaris_x86_vtoc *v;
|
||||
int i;
|
||||
|
||||
v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §);
|
||||
if (!v)
|
||||
return;
|
||||
if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
printk(" %s%d: <solaris:", state->name, origin);
|
||||
if (le32_to_cpu(v->v_version) != 1) {
|
||||
printk(" cannot handle version %d vtoc>\n",
|
||||
le32_to_cpu(v->v_version));
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
for (i=0; i<SOLARIS_X86_NUMSLICE && state->next<state->limit; i++) {
|
||||
struct solaris_x86_slice *s = &v->v_slice[i];
|
||||
if (s->s_size == 0)
|
||||
continue;
|
||||
printk(" [s%d]", i);
|
||||
/* 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);
|
||||
printk(" >\n");
|
||||
#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, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin, char *flavour,
|
||||
int max_partitions)
|
||||
{
|
||||
Sector sect;
|
||||
struct bsd_disklabel *l;
|
||||
struct bsd_partition *p;
|
||||
|
||||
l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, §);
|
||||
if (!l)
|
||||
return;
|
||||
if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
printk(" %s%d: <%s:", state->name, origin, flavour);
|
||||
|
||||
if (le16_to_cpu(l->d_npartitions) < max_partitions)
|
||||
max_partitions = le16_to_cpu(l->d_npartitions);
|
||||
for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
|
||||
u32 bsd_start, bsd_size;
|
||||
|
||||
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) {
|
||||
printk("bad subpartition - ignored\n");
|
||||
continue;
|
||||
}
|
||||
put_partition(state, state->next++, bsd_start, bsd_size);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
if (le16_to_cpu(l->d_npartitions) > max_partitions)
|
||||
printk(" (ignored %d more)",
|
||||
le16_to_cpu(l->d_npartitions) - max_partitions);
|
||||
printk(" >\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
parse_freebsd(struct parsed_partitions *state, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, bdev, offset, size, origin,
|
||||
"bsd", BSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
parse_netbsd(struct parsed_partitions *state, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, bdev, offset, size, origin,
|
||||
"netbsd", BSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
parse_openbsd(struct parsed_partitions *state, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, bdev, 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, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_UNIXWARE_DISKLABEL
|
||||
Sector sect;
|
||||
struct unixware_disklabel *l;
|
||||
struct unixware_slice *p;
|
||||
|
||||
l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, §);
|
||||
if (!l)
|
||||
return;
|
||||
if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
|
||||
le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
printk(" %s%d: <unixware:", state->name, origin);
|
||||
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++,
|
||||
START_SECT(p), NR_SECTS(p));
|
||||
p++;
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
printk(" >\n");
|
||||
#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, struct block_device *bdev,
|
||||
u32 offset, u32 size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_MINIX_SUBPARTITION
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct partition *p;
|
||||
int i;
|
||||
|
||||
data = read_dev_sector(bdev, offset, §);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
p = (struct partition *)(data + 0x1be);
|
||||
|
||||
/* The first sector of a Minix partition can have either
|
||||
* a secondary MBR describing its subpartitions, or
|
||||
* the normal boot sector. */
|
||||
if (msdos_magic_present (data + 510) &&
|
||||
SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
|
||||
|
||||
printk(" %s%d: <minix:", state->name, origin);
|
||||
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));
|
||||
}
|
||||
printk(" >\n");
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
#endif /* CONFIG_MINIX_SUBPARTITION */
|
||||
}
|
||||
|
||||
static struct {
|
||||
unsigned char id;
|
||||
void (*parse)(struct parsed_partitions *, struct block_device *,
|
||||
u32, u32, 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, struct block_device *bdev)
|
||||
{
|
||||
int sector_size = bdev_hardsect_size(bdev) / 512;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct partition *p;
|
||||
int slot;
|
||||
|
||||
data = read_dev_sector(bdev, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
if (!msdos_magic_present(data + 510)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aix_magic_present(data, bdev)) {
|
||||
put_dev_sector(sect);
|
||||
printk( " [AIX]");
|
||||
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) {
|
||||
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++) {
|
||||
u32 start = START_SECT(p)*sector_size;
|
||||
u32 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 */
|
||||
put_partition(state, slot, start, size == 1 ? 1 : 2);
|
||||
printk(" <");
|
||||
parse_extended(state, bdev, start, size);
|
||||
printk(" >");
|
||||
continue;
|
||||
}
|
||||
put_partition(state, slot, start, size);
|
||||
if (SYS_IND(p) == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags = 1;
|
||||
if (SYS_IND(p) == DM6_PARTITION)
|
||||
printk("[DM]");
|
||||
if (SYS_IND(p) == EZD_PARTITION)
|
||||
printk("[EZD]");
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
|
||||
/* 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, bdev, START_SECT(p)*sector_size,
|
||||
NR_SECTS(p)*sector_size, slot);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
8
fs/partitions/msdos.h
Normal file
8
fs/partitions/msdos.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/msdos.h
|
||||
*/
|
||||
|
||||
#define MSDOS_LABEL_MAGIC 0xAA55
|
||||
|
||||
int msdos_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
|
||||
78
fs/partitions/osf.c
Normal file
78
fs/partitions/osf.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
int osf_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
int i;
|
||||
int slot = 1;
|
||||
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[8];
|
||||
} * label;
|
||||
struct d_partition * partition;
|
||||
|
||||
data = read_dev_sector(bdev, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct disklabel *) (data+64);
|
||||
partition = label->d_partitions;
|
||||
if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0 ; i < le16_to_cpu(label->d_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++;
|
||||
}
|
||||
printk("\n");
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
7
fs/partitions/osf.h
Normal file
7
fs/partitions/osf.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* fs/partitions/osf.h
|
||||
*/
|
||||
|
||||
#define DISKLABELMAGIC (0x82564557UL)
|
||||
|
||||
int osf_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
82
fs/partitions/sgi.c
Normal file
82
fs/partitions/sgi.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* fs/partitions/sgi.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sgi.h"
|
||||
|
||||
struct sgi_disklabel {
|
||||
__be32 magic_mushroom; /* Big fat spliff... */
|
||||
__be16 root_part_num; /* Root partition number */
|
||||
__be16 swap_part_num; /* Swap partition number */
|
||||
s8 boot_file[16]; /* Name of boot file for ARCS */
|
||||
u8 _unused0[48]; /* Device parameter useless crapola.. */
|
||||
struct sgi_volume {
|
||||
s8 name[8]; /* Name of volume */
|
||||
__be32 block_num; /* Logical block number */
|
||||
__be32 num_bytes; /* How big, in bytes */
|
||||
} volume[15];
|
||||
struct sgi_partition {
|
||||
__be32 num_blocks; /* Size in logical blocks */
|
||||
__be32 first_block; /* First logical block */
|
||||
__be32 type; /* Type of this partition */
|
||||
} partitions[16];
|
||||
__be32 csum; /* Disk label checksum */
|
||||
__be32 _unused1; /* Padding */
|
||||
};
|
||||
|
||||
int sgi_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
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 = (struct sgi_disklabel *) read_dev_sector(bdev, 0, §);
|
||||
if (!label)
|
||||
return -1;
|
||||
p = &label->partitions[0];
|
||||
magic = label->magic_mushroom;
|
||||
if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
|
||||
/*printk("Dev %s SGI disklabel: bad magic %08x\n",
|
||||
bdevname(bdev, b), be32_to_cpu(magic));*/
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
ui = ((__be32 *) (label + 1)) - 1;
|
||||
for(csum = 0; ui >= ((__be32 *) label);) {
|
||||
cs = *ui--;
|
||||
csum += be32_to_cpu(cs);
|
||||
}
|
||||
if(csum) {
|
||||
printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
|
||||
bdevname(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++;
|
||||
}
|
||||
printk("\n");
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
8
fs/partitions/sgi.h
Normal file
8
fs/partitions/sgi.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* fs/partitions/sgi.h
|
||||
*/
|
||||
|
||||
extern int sgi_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
|
||||
#define SGI_LABEL_MAGIC 0x0be5a941
|
||||
|
||||
94
fs/partitions/sun.c
Normal file
94
fs/partitions/sun.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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, struct block_device *bdev)
|
||||
{
|
||||
int i;
|
||||
__be16 csum;
|
||||
int slot = 1;
|
||||
__be16 *ush;
|
||||
Sector sect;
|
||||
struct sun_disklabel {
|
||||
unsigned char info[128]; /* Informative text string */
|
||||
unsigned char spare0[14];
|
||||
struct sun_info {
|
||||
unsigned char spare1;
|
||||
unsigned char id;
|
||||
unsigned char spare2;
|
||||
unsigned char flags;
|
||||
} infos[8];
|
||||
unsigned char spare[246]; /* Boot information etc. */
|
||||
__be16 rspeed; /* Disk rotational speed */
|
||||
__be16 pcylcount; /* Physical cylinder count */
|
||||
__be16 sparecyl; /* extra sects per cylinder */
|
||||
unsigned char spare2[4]; /* More magic... */
|
||||
__be16 ilfact; /* Interleave factor */
|
||||
__be16 ncyl; /* Data cylinder count */
|
||||
__be16 nacyl; /* Alt. cylinder count */
|
||||
__be16 ntrks; /* Tracks per cylinder */
|
||||
__be16 nsect; /* Sectors per track */
|
||||
unsigned char spare3[4]; /* Even more magic... */
|
||||
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];
|
||||
|
||||
label = (struct sun_disklabel *)read_dev_sector(bdev, 0, §);
|
||||
if (!label)
|
||||
return -1;
|
||||
|
||||
p = label->partitions;
|
||||
if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
|
||||
/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
|
||||
bdevname(bdev, b), be16_to_cpu(label->magic)); */
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
/* Look at the checksum */
|
||||
ush = ((__be16 *) (label+1)) - 1;
|
||||
for (csum = 0; ush >= ((__be16 *) label);)
|
||||
csum ^= *ush--;
|
||||
if (csum) {
|
||||
printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
|
||||
bdevname(bdev, b));
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* All Sun disks have 8 partition entries */
|
||||
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
|
||||
for (i = 0; i < 8; 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 (label->infos[i].id == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags |= ADDPART_FLAG_RAID;
|
||||
if (label->infos[i].id == SUN_WHOLE_DISK)
|
||||
state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK;
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
printk("\n");
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
7
fs/partitions/sun.h
Normal file
7
fs/partitions/sun.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* fs/partitions/sun.h
|
||||
*/
|
||||
|
||||
#define SUN_LABEL_MAGIC 0xDABE
|
||||
|
||||
int sun_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
48
fs/partitions/ultrix.c
Normal file
48
fs/partitions/ultrix.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* fs/partitions/ultrix.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Re-organised Jul 1999 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "ultrix.h"
|
||||
|
||||
int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||
{
|
||||
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_dev_sector(bdev, (16384 - sizeof(*label))/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
|
||||
|
||||
if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
|
||||
for (i=0; i<8; i++)
|
||||
if (label->pt_part[i].pi_nblocks)
|
||||
put_partition(state, i+1,
|
||||
label->pt_part[i].pi_blkoff,
|
||||
label->pt_part[i].pi_nblocks);
|
||||
put_dev_sector(sect);
|
||||
printk ("\n");
|
||||
return 1;
|
||||
} else {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
5
fs/partitions/ultrix.h
Normal file
5
fs/partitions/ultrix.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* fs/partitions/ultrix.h
|
||||
*/
|
||||
|
||||
int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev);
|
||||
Reference in New Issue
Block a user