aboutsummaryrefslogtreecommitdiffstats
path: root/fs/partitions
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/partitions
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'fs/partitions')
-rw-r--r--fs/partitions/Kconfig228
-rw-r--r--fs/partitions/Makefile20
-rw-r--r--fs/partitions/acorn.c557
-rw-r--r--fs/partitions/acorn.h14
-rw-r--r--fs/partitions/amiga.c128
-rw-r--r--fs/partitions/amiga.h6
-rw-r--r--fs/partitions/atari.c149
-rw-r--r--fs/partitions/atari.h34
-rw-r--r--fs/partitions/check.c445
-rw-r--r--fs/partitions/check.h36
-rw-r--r--fs/partitions/devfs.c130
-rw-r--r--fs/partitions/devfs.h10
-rw-r--r--fs/partitions/efi.c645
-rw-r--r--fs/partitions/efi.h131
-rw-r--r--fs/partitions/ibm.c191
-rw-r--r--fs/partitions/ibm.h1
-rw-r--r--fs/partitions/ldm.c1483
-rw-r--r--fs/partitions/ldm.h220
-rw-r--r--fs/partitions/mac.c130
-rw-r--r--fs/partitions/mac.h44
-rw-r--r--fs/partitions/msdos.c479
-rw-r--r--fs/partitions/msdos.h8
-rw-r--r--fs/partitions/osf.c78
-rw-r--r--fs/partitions/osf.h7
-rw-r--r--fs/partitions/sgi.c82
-rw-r--r--fs/partitions/sgi.h8
-rw-r--r--fs/partitions/sun.c91
-rw-r--r--fs/partitions/sun.h7
-rw-r--r--fs/partitions/ultrix.c47
-rw-r--r--fs/partitions/ultrix.h5
30 files changed, 5414 insertions, 0 deletions
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
new file mode 100644
index 00000000000..deb25b661f0
--- /dev/null
+++ b/fs/partitions/Kconfig
@@ -0,0 +1,228 @@
1#
2# Partition configuration
3#
4config PARTITION_ADVANCED
5 bool "Advanced partition selection"
6 help
7 Say Y here if you would like to use hard disks under Linux which
8 were partitioned under an operating system running on a different
9 architecture than your Linux system.
10
11 Note that the answer to this question won't directly affect the
12 kernel: saying N will just cause the configurator to skip all
13 the questions about foreign partitioning schemes.
14
15 If unsure, say N.
16
17config ACORN_PARTITION
18 bool "Acorn partition support" if PARTITION_ADVANCED
19 default y if ARCH_ACORN
20 help
21 Support hard disks partitioned under Acorn operating systems.
22
23config ACORN_PARTITION_CUMANA
24 bool "Cumana partition support" if PARTITION_ADVANCED && ACORN_PARTITION
25 default y if ARCH_ACORN
26 help
27 Say Y here if you would like to use hard disks under Linux which
28 were partitioned using the Cumana interface on Acorn machines.
29
30config ACORN_PARTITION_EESOX
31 bool "EESOX partition support" if PARTITION_ADVANCED && ACORN_PARTITION
32 default y if ARCH_ACORN
33
34config ACORN_PARTITION_ICS
35 bool "ICS partition support" if PARTITION_ADVANCED && ACORN_PARTITION
36 default y if ARCH_ACORN
37 help
38 Say Y here if you would like to use hard disks under Linux which
39 were partitioned using the ICS interface on Acorn machines.
40
41config ACORN_PARTITION_ADFS
42 bool "Native filecore partition support" if PARTITION_ADVANCED && ACORN_PARTITION
43 default y if ARCH_ACORN
44 help
45 The Acorn Disc Filing System is the standard file system of the
46 RiscOS operating system which runs on Acorn's ARM-based Risc PC
47 systems and the Acorn Archimedes range of machines. If you say
48 `Y' here, Linux will support disk partitions created under ADFS.
49
50config ACORN_PARTITION_POWERTEC
51 bool "PowerTec partition support" if PARTITION_ADVANCED && ACORN_PARTITION
52 default y if ARCH_ACORN
53 help
54 Support reading partition tables created on Acorn machines using
55 the PowerTec SCSI drive.
56
57config ACORN_PARTITION_RISCIX
58 bool "RISCiX partition support" if PARTITION_ADVANCED && ACORN_PARTITION
59 default y if ARCH_ACORN
60 help
61 Once upon a time, there was a native Unix port for the Acorn series
62 of machines called RISCiX. If you say 'Y' here, Linux will be able
63 to read disks partitioned under RISCiX.
64
65config OSF_PARTITION
66 bool "Alpha OSF partition support" if PARTITION_ADVANCED
67 default y if ALPHA
68 help
69 Say Y here if you would like to use hard disks under Linux which
70 were partitioned on an Alpha machine.
71
72config AMIGA_PARTITION
73 bool "Amiga partition table support" if PARTITION_ADVANCED
74 default y if (AMIGA || AFFS_FS=y)
75 help
76 Say Y here if you would like to use hard disks under Linux which
77 were partitioned under AmigaOS.
78
79config ATARI_PARTITION
80 bool "Atari partition table support" if PARTITION_ADVANCED
81 default y if ATARI
82 help
83 Say Y here if you would like to use hard disks under Linux which
84 were partitioned under the Atari OS.
85
86config IBM_PARTITION
87 bool "IBM disk label and partition support"
88 depends on PARTITION_ADVANCED && ARCH_S390
89 help
90 Say Y here if you would like to be able to read the hard disk
91 partition table format used by IBM DASD disks operating under CMS.
92 Otherwise, say N.
93
94config MAC_PARTITION
95 bool "Macintosh partition map support" if PARTITION_ADVANCED
96 default y if MAC
97 help
98 Say Y here if you would like to use hard disks under Linux which
99 were partitioned on a Macintosh.
100
101config MSDOS_PARTITION
102 bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED
103 default y
104 help
105 Say Y here.
106
107config BSD_DISKLABEL
108 bool "BSD disklabel (FreeBSD partition tables) support"
109 depends on PARTITION_ADVANCED && MSDOS_PARTITION
110 help
111 FreeBSD uses its own hard disk partition scheme on your PC. It
112 requires only one entry in the primary partition table of your disk
113 and manages it similarly to DOS extended partitions, putting in its
114 first sector a new partition table in BSD disklabel format. Saying Y
115 here allows you to read these disklabels and further mount FreeBSD
116 partitions from within Linux if you have also said Y to "UFS
117 file system support", above. If you don't know what all this is
118 about, say N.
119
120config MINIX_SUBPARTITION
121 bool "Minix subpartition support"
122 depends on PARTITION_ADVANCED && MSDOS_PARTITION
123 help
124 Minix 2.0.0/2.0.2 subpartition table support for Linux.
125 Say Y here if you want to mount and use Minix 2.0.0/2.0.2
126 subpartitions.
127
128config SOLARIS_X86_PARTITION
129 bool "Solaris (x86) partition table support"
130 depends on PARTITION_ADVANCED && MSDOS_PARTITION
131 help
132 Like most systems, Solaris x86 uses its own hard disk partition
133 table format, incompatible with all others. Saying Y here allows you
134 to read these partition tables and further mount Solaris x86
135 partitions from within Linux if you have also said Y to "UFS
136 file system support", above.
137
138config UNIXWARE_DISKLABEL
139 bool "Unixware slices support"
140 depends on PARTITION_ADVANCED && MSDOS_PARTITION
141 ---help---
142 Like some systems, UnixWare uses its own slice table inside a
143 partition (VTOC - Virtual Table of Contents). Its format is
144 incompatible with all other OSes. Saying Y here allows you to read
145 VTOC and further mount UnixWare partitions read-only from within
146 Linux if you have also said Y to "UFS file system support" or
147 "System V and Coherent file system support", above.
148
149 This is mainly used to carry data from a UnixWare box to your
150 Linux box via a removable medium like magneto-optical, ZIP or
151 removable IDE drives. Note, however, that a good portable way to
152 transport files and directories between unixes (and even other
153 operating systems) is given by the tar program ("man tar" or
154 preferably "info tar").
155
156 If you don't know what all this is about, say N.
157
158config LDM_PARTITION
159 bool "Windows Logical Disk Manager (Dynamic Disk) support"
160 depends on PARTITION_ADVANCED
161 ---help---
162 Say Y here if you would like to use hard disks under Linux which
163 were partitioned using Windows 2000's or XP's Logical Disk Manager.
164 They are also known as "Dynamic Disks".
165
166 Windows 2000 introduced the concept of Dynamic Disks to get around
167 the limitations of the PC's partitioning scheme. The Logical Disk
168 Manager allows the user to repartition a disk and create spanned,
169 mirrored, striped or RAID volumes, all without the need for
170 rebooting.
171
172 Normal partitions are now called Basic Disks under Windows 2000 and
173 XP.
174
175 For a fuller description read <file:Documentation/ldm.txt>.
176
177 If unsure, say N.
178
179config LDM_DEBUG
180 bool "Windows LDM extra logging"
181 depends on LDM_PARTITION
182 help
183 Say Y here if you would like LDM to log verbosely. This could be
184 helpful if the driver doesn't work as expected and you'd like to
185 report a bug.
186
187 If unsure, say N.
188
189config SGI_PARTITION
190 bool "SGI partition support" if PARTITION_ADVANCED
191 default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM200_PCI) && !CPU_LITTLE_ENDIAN))
192 help
193 Say Y here if you would like to be able to read the hard disk
194 partition table format used by SGI machines.
195
196config ULTRIX_PARTITION
197 bool "Ultrix partition table support" if PARTITION_ADVANCED
198 default y if MACH_DECSTATION
199 help
200 Say Y here if you would like to be able to read the hard disk
201 partition table format used by DEC (now Compaq) Ultrix machines.
202 Otherwise, say N.
203
204config SUN_PARTITION
205 bool "Sun partition tables support" if PARTITION_ADVANCED
206 default y if (SPARC32 || SPARC64 || SUN3 || SUN3X)
207 ---help---
208 Like most systems, SunOS uses its own hard disk partition table
209 format, incompatible with all others. Saying Y here allows you to
210 read these partition tables and further mount SunOS partitions from
211 within Linux if you have also said Y to "UFS file system support",
212 above. This is mainly used to carry data from a SPARC under SunOS to
213 your Linux box via a removable medium like magneto-optical or ZIP
214 drives; note however that a good portable way to transport files and
215 directories between unixes (and even other operating systems) is
216 given by the tar program ("man tar" or preferably "info tar"). If
217 you don't know what all this is about, say N.
218
219config EFI_PARTITION
220 bool "EFI GUID Partition support"
221 depends on PARTITION_ADVANCED
222 select CRC32
223 help
224 Say Y here if you would like to use hard disks under Linux which
225 were partitioned using EFI GPT. Presently only useful on the
226 IA-64 platform.
227
228# define_bool CONFIG_ACORN_PARTITION_CUMANA y
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
new file mode 100644
index 00000000000..4c83c17969e
--- /dev/null
+++ b/fs/partitions/Makefile
@@ -0,0 +1,20 @@
1#
2# Makefile for the linux kernel.
3#
4
5obj-y := check.o
6
7obj-$(CONFIG_DEVFS_FS) += devfs.o
8obj-$(CONFIG_ACORN_PARTITION) += acorn.o
9obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
10obj-$(CONFIG_ATARI_PARTITION) += atari.o
11obj-$(CONFIG_MAC_PARTITION) += mac.o
12obj-$(CONFIG_LDM_PARTITION) += ldm.o
13obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
14obj-$(CONFIG_OSF_PARTITION) += osf.o
15obj-$(CONFIG_SGI_PARTITION) += sgi.o
16obj-$(CONFIG_SUN_PARTITION) += sun.o
17obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
18obj-$(CONFIG_IBM_PARTITION) += ibm.o
19obj-$(CONFIG_EFI_PARTITION) += efi.o
20obj-$(CONFIG_NEC98_PARTITION) += nec98.o msdos.o
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
new file mode 100644
index 00000000000..c05085710fc
--- /dev/null
+++ b/fs/partitions/acorn.c
@@ -0,0 +1,557 @@
1/*
2 * linux/fs/partitions/acorn.c
3 *
4 * Copyright (c) 1996-2000 Russell King.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Scan ADFS partitions on hard disk drives. Unfortunately, there
11 * isn't a standard for partitioning drives on Acorn machines, so
12 * every single manufacturer of SCSI and IDE cards created their own
13 * method.
14 */
15#include <linux/config.h>
16#include <linux/buffer_head.h>
17#include <linux/adfs_fs.h>
18
19#include "check.h"
20#include "acorn.h"
21
22/*
23 * Partition types. (Oh for reusability)
24 */
25#define PARTITION_RISCIX_MFM 1
26#define PARTITION_RISCIX_SCSI 2
27#define PARTITION_LINUX 9
28
29static struct adfs_discrecord *
30adfs_partition(struct parsed_partitions *state, char *name, char *data,
31 unsigned long first_sector, int slot)
32{
33 struct adfs_discrecord *dr;
34 unsigned int nr_sects;
35
36 if (adfs_checkbblk(data))
37 return NULL;
38
39 dr = (struct adfs_discrecord *)(data + 0x1c0);
40
41 if (dr->disc_size == 0 && dr->disc_size_high == 0)
42 return NULL;
43
44 nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
45 (le32_to_cpu(dr->disc_size) >> 9);
46
47 if (name)
48 printk(" [%s]", name);
49 put_partition(state, slot, first_sector, nr_sects);
50 return dr;
51}
52
53#ifdef CONFIG_ACORN_PARTITION_RISCIX
54
55struct riscix_part {
56 __le32 start;
57 __le32 length;
58 __le32 one;
59 char name[16];
60};
61
62struct riscix_record {
63 __le32 magic;
64#define RISCIX_MAGIC cpu_to_le32(0x4a657320)
65 __le32 date;
66 struct riscix_part part[8];
67};
68
69static int
70riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
71 unsigned long first_sect, int slot, unsigned long nr_sects)
72{
73 Sector sect;
74 struct riscix_record *rr;
75
76 rr = (struct riscix_record *)read_dev_sector(bdev, first_sect, &sect);
77 if (!rr)
78 return -1;
79
80 printk(" [RISCiX]");
81
82
83 if (rr->magic == RISCIX_MAGIC) {
84 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
85 int part;
86
87 printk(" <");
88
89 put_partition(state, slot++, first_sect, size);
90 for (part = 0; part < 8; part++) {
91 if (rr->part[part].one &&
92 memcmp(rr->part[part].name, "All\0", 4)) {
93 put_partition(state, slot++,
94 le32_to_cpu(rr->part[part].start),
95 le32_to_cpu(rr->part[part].length));
96 printk("(%s)", rr->part[part].name);
97 }
98 }
99
100 printk(" >\n");
101 } else {
102 put_partition(state, slot++, first_sect, nr_sects);
103 }
104
105 put_dev_sector(sect);
106 return slot;
107}
108#endif
109
110#define LINUX_NATIVE_MAGIC 0xdeafa1de
111#define LINUX_SWAP_MAGIC 0xdeafab1e
112
113struct linux_part {
114 __le32 magic;
115 __le32 start_sect;
116 __le32 nr_sects;
117};
118
119static int
120linux_partition(struct parsed_partitions *state, struct block_device *bdev,
121 unsigned long first_sect, int slot, unsigned long nr_sects)
122{
123 Sector sect;
124 struct linux_part *linuxp;
125 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
126
127 printk(" [Linux]");
128
129 put_partition(state, slot++, first_sect, size);
130
131 linuxp = (struct linux_part *)read_dev_sector(bdev, first_sect, &sect);
132 if (!linuxp)
133 return -1;
134
135 printk(" <");
136 while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
137 linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
138 if (slot == state->limit)
139 break;
140 put_partition(state, slot++, first_sect +
141 le32_to_cpu(linuxp->start_sect),
142 le32_to_cpu(linuxp->nr_sects));
143 linuxp ++;
144 }
145 printk(" >");
146
147 put_dev_sector(sect);
148 return slot;
149}
150
151#ifdef CONFIG_ACORN_PARTITION_CUMANA
152int
153adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev)
154{
155 unsigned long first_sector = 0;
156 unsigned int start_blk = 0;
157 Sector sect;
158 unsigned char *data;
159 char *name = "CUMANA/ADFS";
160 int first = 1;
161 int slot = 1;
162
163 /*
164 * Try Cumana style partitions - sector 6 contains ADFS boot block
165 * with pointer to next 'drive'.
166 *
167 * There are unknowns in this code - is the 'cylinder number' of the
168 * next partition relative to the start of this one - I'm assuming
169 * it is.
170 *
171 * Also, which ID did Cumana use?
172 *
173 * This is totally unfinished, and will require more work to get it
174 * going. Hence it is totally untested.
175 */
176 do {
177 struct adfs_discrecord *dr;
178 unsigned int nr_sects;
179
180 data = read_dev_sector(bdev, start_blk * 2 + 6, &sect);
181 if (!data)
182 return -1;
183
184 if (slot == state->limit)
185 break;
186
187 dr = adfs_partition(state, name, data, first_sector, slot++);
188 if (!dr)
189 break;
190
191 name = NULL;
192
193 nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
194 (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
195 dr->secspertrack;
196
197 if (!nr_sects)
198 break;
199
200 first = 0;
201 first_sector += nr_sects;
202 start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
203 nr_sects = 0; /* hmm - should be partition size */
204
205 switch (data[0x1fc] & 15) {
206 case 0: /* No partition / ADFS? */
207 break;
208
209#ifdef CONFIG_ACORN_PARTITION_RISCIX
210 case PARTITION_RISCIX_SCSI:
211 /* RISCiX - we don't know how to find the next one. */
212 slot = riscix_partition(state, bdev, first_sector,
213 slot, nr_sects);
214 break;
215#endif
216
217 case PARTITION_LINUX:
218 slot = linux_partition(state, bdev, first_sector,
219 slot, nr_sects);
220 break;
221 }
222 put_dev_sector(sect);
223 if (slot == -1)
224 return -1;
225 } while (1);
226 put_dev_sector(sect);
227 return first ? 0 : 1;
228}
229#endif
230
231#ifdef CONFIG_ACORN_PARTITION_ADFS
232/*
233 * Purpose: allocate ADFS partitions.
234 *
235 * Params : hd - pointer to gendisk structure to store partition info.
236 * dev - device number to access.
237 *
238 * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
239 *
240 * Alloc : hda = whole drive
241 * hda1 = ADFS partition on first drive.
242 * hda2 = non-ADFS partition.
243 */
244int
245adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev)
246{
247 unsigned long start_sect, nr_sects, sectscyl, heads;
248 Sector sect;
249 unsigned char *data;
250 struct adfs_discrecord *dr;
251 unsigned char id;
252 int slot = 1;
253
254 data = read_dev_sector(bdev, 6, &sect);
255 if (!data)
256 return -1;
257
258 dr = adfs_partition(state, "ADFS", data, 0, slot++);
259 if (!dr) {
260 put_dev_sector(sect);
261 return 0;
262 }
263
264 heads = dr->heads + ((dr->lowsector >> 6) & 1);
265 sectscyl = dr->secspertrack * heads;
266 start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
267 id = data[0x1fc] & 15;
268 put_dev_sector(sect);
269
270#ifdef CONFIG_BLK_DEV_MFM
271 if (MAJOR(bdev->bd_dev) == MFM_ACORN_MAJOR) {
272 extern void xd_set_geometry(struct block_device *,
273 unsigned char, unsigned char, unsigned int);
274 xd_set_geometry(bdev, dr->secspertrack, heads, 1);
275 invalidate_bdev(bdev, 1);
276 truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
277 }
278#endif
279
280 /*
281 * Work out start of non-adfs partition.
282 */
283 nr_sects = (bdev->bd_inode->i_size >> 9) - start_sect;
284
285 if (start_sect) {
286 switch (id) {
287#ifdef CONFIG_ACORN_PARTITION_RISCIX
288 case PARTITION_RISCIX_SCSI:
289 case PARTITION_RISCIX_MFM:
290 slot = riscix_partition(state, bdev, start_sect,
291 slot, nr_sects);
292 break;
293#endif
294
295 case PARTITION_LINUX:
296 slot = linux_partition(state, bdev, start_sect,
297 slot, nr_sects);
298 break;
299 }
300 }
301 printk("\n");
302 return 1;
303}
304#endif
305
306#ifdef CONFIG_ACORN_PARTITION_ICS
307
308struct ics_part {
309 __le32 start;
310 __le32 size;
311};
312
313static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block)
314{
315 Sector sect;
316 unsigned char *data = read_dev_sector(bdev, block, &sect);
317 int result = 0;
318
319 if (data) {
320 if (memcmp(data, "LinuxPart", 9) == 0)
321 result = 1;
322 put_dev_sector(sect);
323 }
324
325 return result;
326}
327
328/*
329 * Check for a valid ICS partition using the checksum.
330 */
331static inline int valid_ics_sector(const unsigned char *data)
332{
333 unsigned long sum;
334 int i;
335
336 for (i = 0, sum = 0x50617274; i < 508; i++)
337 sum += data[i];
338
339 sum -= le32_to_cpu(*(__le32 *)(&data[508]));
340
341 return sum == 0;
342}
343
344/*
345 * Purpose: allocate ICS partitions.
346 * Params : hd - pointer to gendisk structure to store partition info.
347 * dev - device number to access.
348 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
349 * Alloc : hda = whole drive
350 * hda1 = ADFS partition 0 on first drive.
351 * hda2 = ADFS partition 1 on first drive.
352 * ..etc..
353 */
354int
355adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev)
356{
357 const unsigned char *data;
358 const struct ics_part *p;
359 int slot;
360 Sector sect;
361
362 /*
363 * Try ICS style partitions - sector 0 contains partition info.
364 */
365 data = read_dev_sector(bdev, 0, &sect);
366 if (!data)
367 return -1;
368
369 if (!valid_ics_sector(data)) {
370 put_dev_sector(sect);
371 return 0;
372 }
373
374 printk(" [ICS]");
375
376 for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
377 u32 start = le32_to_cpu(p->start);
378 s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
379
380 if (slot == state->limit)
381 break;
382
383 /*
384 * Negative sizes tell the RISC OS ICS driver to ignore
385 * this partition - in effect it says that this does not
386 * contain an ADFS filesystem.
387 */
388 if (size < 0) {
389 size = -size;
390
391 /*
392 * Our own extension - We use the first sector
393 * of the partition to identify what type this
394 * partition is. We must not make this visible
395 * to the filesystem.
396 */
397 if (size > 1 && adfspart_check_ICSLinux(bdev, start)) {
398 start += 1;
399 size -= 1;
400 }
401 }
402
403 if (size)
404 put_partition(state, slot++, start, size);
405 }
406
407 put_dev_sector(sect);
408 printk("\n");
409 return 1;
410}
411#endif
412
413#ifdef CONFIG_ACORN_PARTITION_POWERTEC
414struct ptec_part {
415 __le32 unused1;
416 __le32 unused2;
417 __le32 start;
418 __le32 size;
419 __le32 unused5;
420 char type[8];
421};
422
423static inline int valid_ptec_sector(const unsigned char *data)
424{
425 unsigned char checksum = 0x2a;
426 int i;
427
428 /*
429 * If it looks like a PC/BIOS partition, then it
430 * probably isn't PowerTec.
431 */
432 if (data[510] == 0x55 && data[511] == 0xaa)
433 return 0;
434
435 for (i = 0; i < 511; i++)
436 checksum += data[i];
437
438 return checksum == data[511];
439}
440
441/*
442 * Purpose: allocate ICS partitions.
443 * Params : hd - pointer to gendisk structure to store partition info.
444 * dev - device number to access.
445 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
446 * Alloc : hda = whole drive
447 * hda1 = ADFS partition 0 on first drive.
448 * hda2 = ADFS partition 1 on first drive.
449 * ..etc..
450 */
451int
452adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev)
453{
454 Sector sect;
455 const unsigned char *data;
456 const struct ptec_part *p;
457 int slot = 1;
458 int i;
459
460 data = read_dev_sector(bdev, 0, &sect);
461 if (!data)
462 return -1;
463
464 if (!valid_ptec_sector(data)) {
465 put_dev_sector(sect);
466 return 0;
467 }
468
469 printk(" [POWERTEC]");
470
471 for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
472 u32 start = le32_to_cpu(p->start);
473 u32 size = le32_to_cpu(p->size);
474
475 if (size)
476 put_partition(state, slot++, start, size);
477 }
478
479 put_dev_sector(sect);
480 printk("\n");
481 return 1;
482}
483#endif
484
485#ifdef CONFIG_ACORN_PARTITION_EESOX
486struct eesox_part {
487 char magic[6];
488 char name[10];
489 __le32 start;
490 __le32 unused6;
491 __le32 unused7;
492 __le32 unused8;
493};
494
495/*
496 * Guess who created this format?
497 */
498static const char eesox_name[] = {
499 'N', 'e', 'i', 'l', ' ',
500 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
501};
502
503/*
504 * EESOX SCSI partition format.
505 *
506 * This is a goddamned awful partition format. We don't seem to store
507 * the size of the partition in this table, only the start addresses.
508 *
509 * There are two possibilities where the size comes from:
510 * 1. The individual ADFS boot block entries that are placed on the disk.
511 * 2. The start address of the next entry.
512 */
513int
514adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev)
515{
516 Sector sect;
517 const unsigned char *data;
518 unsigned char buffer[256];
519 struct eesox_part *p;
520 sector_t start = 0;
521 int i, slot = 1;
522
523 data = read_dev_sector(bdev, 7, &sect);
524 if (!data)
525 return -1;
526
527 /*
528 * "Decrypt" the partition table. God knows why...
529 */
530 for (i = 0; i < 256; i++)
531 buffer[i] = data[i] ^ eesox_name[i & 15];
532
533 put_dev_sector(sect);
534
535 for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
536 sector_t next;
537
538 if (memcmp(p->magic, "Eesox", 6))
539 break;
540
541 next = le32_to_cpu(p->start);
542 if (i)
543 put_partition(state, slot++, start, next - start);
544 start = next;
545 }
546
547 if (i != 0) {
548 sector_t size;
549
550 size = get_capacity(bdev->bd_disk);
551 put_partition(state, slot++, start, size - start);
552 printk("\n");
553 }
554
555 return i ? 1 : 0;
556}
557#endif
diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h
new file mode 100644
index 00000000000..81fd50ecc08
--- /dev/null
+++ b/fs/partitions/acorn.h
@@ -0,0 +1,14 @@
1/*
2 * linux/fs/partitions/acorn.h
3 *
4 * Copyright (C) 1996-2001 Russell King.
5 *
6 * I _hate_ this partitioning mess - why can't we have one defined
7 * format, and everyone stick to it?
8 */
9
10int adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev);
11int adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev);
12int adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev);
13int adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev);
14int adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c
new file mode 100644
index 00000000000..3068528890a
--- /dev/null
+++ b/fs/partitions/amiga.c
@@ -0,0 +1,128 @@
1/*
2 * fs/partitions/amiga.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include <linux/types.h>
11#include <linux/affs_hardblocks.h>
12
13#include "check.h"
14#include "amiga.h"
15
16static __inline__ u32
17checksum_block(__be32 *m, int size)
18{
19 u32 sum = 0;
20
21 while (size--)
22 sum += be32_to_cpu(*m++);
23 return sum;
24}
25
26int
27amiga_partition(struct parsed_partitions *state, struct block_device *bdev)
28{
29 Sector sect;
30 unsigned char *data;
31 struct RigidDiskBlock *rdb;
32 struct PartitionBlock *pb;
33 int start_sect, nr_sects, blk, part, res = 0;
34 int blksize = 1; /* Multiplier for disk block size */
35 int slot = 1;
36 char b[BDEVNAME_SIZE];
37
38 for (blk = 0; ; blk++, put_dev_sector(sect)) {
39 if (blk == RDB_ALLOCATION_LIMIT)
40 goto rdb_done;
41 data = read_dev_sector(bdev, blk, &sect);
42 if (!data) {
43 if (warn_no_part)
44 printk("Dev %s: unable to read RDB block %d\n",
45 bdevname(bdev, b), blk);
46 goto rdb_done;
47 }
48 if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
49 continue;
50
51 rdb = (struct RigidDiskBlock *)data;
52 if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
53 break;
54 /* Try again with 0xdc..0xdf zeroed, Windows might have
55 * trashed it.
56 */
57 *(__be32 *)(data+0xdc) = 0;
58 if (checksum_block((__be32 *)data,
59 be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
60 printk("Warning: Trashed word at 0xd0 in block %d "
61 "ignored in checksum calculation\n",blk);
62 break;
63 }
64
65 printk("Dev %s: RDB in block %d has bad checksum\n",
66 bdevname(bdev, b), blk);
67 }
68
69 /* blksize is blocks per 512 byte standard block */
70 blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512;
71
72 printk(" RDSK (%d)", blksize * 512); /* Be more informative */
73 blk = be32_to_cpu(rdb->rdb_PartitionList);
74 put_dev_sector(sect);
75 for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
76 blk *= blksize; /* Read in terms partition table understands */
77 data = read_dev_sector(bdev, blk, &sect);
78 if (!data) {
79 if (warn_no_part)
80 printk("Dev %s: unable to read partition block %d\n",
81 bdevname(bdev, b), blk);
82 goto rdb_done;
83 }
84 pb = (struct PartitionBlock *)data;
85 blk = be32_to_cpu(pb->pb_Next);
86 if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
87 continue;
88 if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
89 continue;
90
91 /* Tell Kernel about it */
92
93 nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
94 be32_to_cpu(pb->pb_Environment[9])) *
95 be32_to_cpu(pb->pb_Environment[3]) *
96 be32_to_cpu(pb->pb_Environment[5]) *
97 blksize;
98 if (!nr_sects)
99 continue;
100 start_sect = be32_to_cpu(pb->pb_Environment[9]) *
101 be32_to_cpu(pb->pb_Environment[3]) *
102 be32_to_cpu(pb->pb_Environment[5]) *
103 blksize;
104 put_partition(state,slot++,start_sect,nr_sects);
105 {
106 /* Be even more informative to aid mounting */
107 char dostype[4];
108 __be32 *dt = (__be32 *)dostype;
109 *dt = pb->pb_Environment[16];
110 if (dostype[3] < ' ')
111 printk(" (%c%c%c^%c)",
112 dostype[0], dostype[1],
113 dostype[2], dostype[3] + '@' );
114 else
115 printk(" (%c%c%c%c)",
116 dostype[0], dostype[1],
117 dostype[2], dostype[3]);
118 printk("(res %d spb %d)",
119 be32_to_cpu(pb->pb_Environment[6]),
120 be32_to_cpu(pb->pb_Environment[4]));
121 }
122 res = 1;
123 }
124 printk("\n");
125
126rdb_done:
127 return res;
128}
diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h
new file mode 100644
index 00000000000..2f3e9ce22d5
--- /dev/null
+++ b/fs/partitions/amiga.h
@@ -0,0 +1,6 @@
1/*
2 * fs/partitions/amiga.h
3 */
4
5int amiga_partition(struct parsed_partitions *state, struct block_device *bdev);
6
diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c
new file mode 100644
index 00000000000..192a6adfdef
--- /dev/null
+++ b/fs/partitions/atari.c
@@ -0,0 +1,149 @@
1/*
2 * fs/partitions/atari.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include <linux/ctype.h>
11#include "check.h"
12#include "atari.h"
13
14/* ++guenther: this should be settable by the user ("make config")?.
15 */
16#define ICD_PARTS
17
18/* check if a partition entry looks valid -- Atari format is assumed if at
19 least one of the primary entries is ok this way */
20#define VALID_PARTITION(pi,hdsiz) \
21 (((pi)->flg & 1) && \
22 isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
23 be32_to_cpu((pi)->st) <= (hdsiz) && \
24 be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
25
26static inline int OK_id(char *s)
27{
28 return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 ||
29 memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 ||
30 memcmp (s, "RAW", 3) == 0 ;
31}
32
33int atari_partition(struct parsed_partitions *state, struct block_device *bdev)
34{
35 Sector sect;
36 struct rootsector *rs;
37 struct partition_info *pi;
38 u32 extensect;
39 u32 hd_size;
40 int slot;
41#ifdef ICD_PARTS
42 int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
43#endif
44
45 rs = (struct rootsector *) read_dev_sector(bdev, 0, &sect);
46 if (!rs)
47 return -1;
48
49 /* Verify this is an Atari rootsector: */
50 hd_size = bdev->bd_inode->i_size >> 9;
51 if (!VALID_PARTITION(&rs->part[0], hd_size) &&
52 !VALID_PARTITION(&rs->part[1], hd_size) &&
53 !VALID_PARTITION(&rs->part[2], hd_size) &&
54 !VALID_PARTITION(&rs->part[3], hd_size)) {
55 /*
56 * if there's no valid primary partition, assume that no Atari
57 * format partition table (there's no reliable magic or the like
58 * :-()
59 */
60 put_dev_sector(sect);
61 return 0;
62 }
63
64 pi = &rs->part[0];
65 printk (" AHDI");
66 for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) {
67 struct rootsector *xrs;
68 Sector sect2;
69 ulong partsect;
70
71 if ( !(pi->flg & 1) )
72 continue;
73 /* active partition */
74 if (memcmp (pi->id, "XGM", 3) != 0) {
75 /* we don't care about other id's */
76 put_partition (state, slot, be32_to_cpu(pi->st),
77 be32_to_cpu(pi->siz));
78 continue;
79 }
80 /* extension partition */
81#ifdef ICD_PARTS
82 part_fmt = 1;
83#endif
84 printk(" XGM<");
85 partsect = extensect = be32_to_cpu(pi->st);
86 while (1) {
87 xrs = (struct rootsector *)read_dev_sector(bdev, partsect, &sect2);
88 if (!xrs) {
89 printk (" block %ld read failed\n", partsect);
90 put_dev_sector(sect);
91 return 0;
92 }
93
94 /* ++roman: sanity check: bit 0 of flg field must be set */
95 if (!(xrs->part[0].flg & 1)) {
96 printk( "\nFirst sub-partition in extended partition is not valid!\n" );
97 put_dev_sector(sect2);
98 break;
99 }
100
101 put_partition(state, slot,
102 partsect + be32_to_cpu(xrs->part[0].st),
103 be32_to_cpu(xrs->part[0].siz));
104
105 if (!(xrs->part[1].flg & 1)) {
106 /* end of linked partition list */
107 put_dev_sector(sect2);
108 break;
109 }
110 if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
111 printk("\nID of extended partition is not XGM!\n");
112 put_dev_sector(sect2);
113 break;
114 }
115
116 partsect = be32_to_cpu(xrs->part[1].st) + extensect;
117 put_dev_sector(sect2);
118 if (++slot == state->limit) {
119 printk( "\nMaximum number of partitions reached!\n" );
120 break;
121 }
122 }
123 printk(" >");
124 }
125#ifdef ICD_PARTS
126 if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */
127 pi = &rs->icdpart[0];
128 /* sanity check: no ICD format if first partition invalid */
129 if (OK_id(pi->id)) {
130 printk(" ICD<");
131 for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) {
132 /* accept only GEM,BGM,RAW,LNX,SWP partitions */
133 if (!((pi->flg & 1) && OK_id(pi->id)))
134 continue;
135 part_fmt = 2;
136 put_partition (state, slot,
137 be32_to_cpu(pi->st),
138 be32_to_cpu(pi->siz));
139 }
140 printk(" >");
141 }
142 }
143#endif
144 put_dev_sector(sect);
145
146 printk ("\n");
147
148 return 1;
149}
diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h
new file mode 100644
index 00000000000..63186b00e13
--- /dev/null
+++ b/fs/partitions/atari.h
@@ -0,0 +1,34 @@
1/*
2 * fs/partitions/atari.h
3 * Moved by Russell King from:
4 *
5 * linux/include/linux/atari_rootsec.h
6 * definitions for Atari Rootsector layout
7 * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
8 *
9 * modified for ICD/Supra partitioning scheme restricted to at most 12
10 * partitions
11 * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
12 */
13
14struct partition_info
15{
16 u8 flg; /* bit 0: active; bit 7: bootable */
17 char id[3]; /* "GEM", "BGM", "XGM", or other */
18 __be32 st; /* start of partition */
19 __be32 siz; /* length of partition */
20};
21
22struct rootsector
23{
24 char unused[0x156]; /* room for boot code */
25 struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
26 char unused2[0xc];
27 u32 hd_siz; /* size of disk in blocks */
28 struct partition_info part[4];
29 u32 bsl_st; /* start of bad sector list */
30 u32 bsl_cnt; /* length of bad sector list */
31 u16 checksum; /* checksum for bootable disks */
32} __attribute__((__packed__));
33
34int atari_partition(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
new file mode 100644
index 00000000000..31cff785b3b
--- /dev/null
+++ b/fs/partitions/check.c
@@ -0,0 +1,445 @@
1/*
2 * fs/partitions/check.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
6 * Re-organised Feb 1998 Russell King
7 *
8 * We now have independent partition support from the
9 * block drivers, which allows all the partition code to
10 * be grouped in one location, and it to be mostly self
11 * contained.
12 *
13 * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/kmod.h>
20#include <linux/ctype.h>
21#include <linux/devfs_fs_kernel.h>
22
23#include "check.h"
24#include "devfs.h"
25
26#include "acorn.h"
27#include "amiga.h"
28#include "atari.h"
29#include "ldm.h"
30#include "mac.h"
31#include "msdos.h"
32#include "osf.h"
33#include "sgi.h"
34#include "sun.h"
35#include "ibm.h"
36#include "ultrix.h"
37#include "efi.h"
38
39#ifdef CONFIG_BLK_DEV_MD
40extern void md_autodetect_dev(dev_t dev);
41#endif
42
43int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
44
45static int (*check_part[])(struct parsed_partitions *, struct block_device *) = {
46 /*
47 * Probe partition formats with tables at disk address 0
48 * that also have an ADFS boot block at 0xdc0.
49 */
50#ifdef CONFIG_ACORN_PARTITION_ICS
51 adfspart_check_ICS,
52#endif
53#ifdef CONFIG_ACORN_PARTITION_POWERTEC
54 adfspart_check_POWERTEC,
55#endif
56#ifdef CONFIG_ACORN_PARTITION_EESOX
57 adfspart_check_EESOX,
58#endif
59
60 /*
61 * Now move on to formats that only have partition info at
62 * disk address 0xdc0. Since these may also have stale
63 * PC/BIOS partition tables, they need to come before
64 * the msdos entry.
65 */
66#ifdef CONFIG_ACORN_PARTITION_CUMANA
67 adfspart_check_CUMANA,
68#endif
69#ifdef CONFIG_ACORN_PARTITION_ADFS
70 adfspart_check_ADFS,
71#endif
72
73#ifdef CONFIG_EFI_PARTITION
74 efi_partition, /* this must come before msdos */
75#endif
76#ifdef CONFIG_SGI_PARTITION
77 sgi_partition,
78#endif
79#ifdef CONFIG_LDM_PARTITION
80 ldm_partition, /* this must come before msdos */
81#endif
82#ifdef CONFIG_NEC98_PARTITION
83 nec98_partition, /* must be come before `msdos_partition' */
84#endif
85#ifdef CONFIG_MSDOS_PARTITION
86 msdos_partition,
87#endif
88#ifdef CONFIG_OSF_PARTITION
89 osf_partition,
90#endif
91#ifdef CONFIG_SUN_PARTITION
92 sun_partition,
93#endif
94#ifdef CONFIG_AMIGA_PARTITION
95 amiga_partition,
96#endif
97#ifdef CONFIG_ATARI_PARTITION
98 atari_partition,
99#endif
100#ifdef CONFIG_MAC_PARTITION
101 mac_partition,
102#endif
103#ifdef CONFIG_ULTRIX_PARTITION
104 ultrix_partition,
105#endif
106#ifdef CONFIG_IBM_PARTITION
107 ibm_partition,
108#endif
109 NULL
110};
111
112/*
113 * disk_name() is used by partition check code and the genhd driver.
114 * It formats the devicename of the indicated disk into
115 * the supplied buffer (of size at least 32), and returns
116 * a pointer to that same buffer (for convenience).
117 */
118
119char *disk_name(struct gendisk *hd, int part, char *buf)
120{
121 if (!part)
122 snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
123 else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
124 snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, part);
125 else
126 snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part);
127
128 return buf;
129}
130
131const char *bdevname(struct block_device *bdev, char *buf)
132{
133 int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor;
134 return disk_name(bdev->bd_disk, part, buf);
135}
136
137EXPORT_SYMBOL(bdevname);
138
139/*
140 * There's very little reason to use this, you should really
141 * have a struct block_device just about everywhere and use
142 * bdevname() instead.
143 */
144const char *__bdevname(dev_t dev, char *buffer)
145{
146 scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)",
147 MAJOR(dev), MINOR(dev));
148 return buffer;
149}
150
151EXPORT_SYMBOL(__bdevname);
152
153static struct parsed_partitions *
154check_partition(struct gendisk *hd, struct block_device *bdev)
155{
156 struct parsed_partitions *state;
157 int i, res;
158
159 state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
160 if (!state)
161 return NULL;
162
163#ifdef CONFIG_DEVFS_FS
164 if (hd->devfs_name[0] != '\0') {
165 printk(KERN_INFO " /dev/%s:", hd->devfs_name);
166 sprintf(state->name, "p");
167 }
168#endif
169 else {
170 disk_name(hd, 0, state->name);
171 printk(KERN_INFO " %s:", state->name);
172 if (isdigit(state->name[strlen(state->name)-1]))
173 sprintf(state->name, "p");
174 }
175 state->limit = hd->minors;
176 i = res = 0;
177 while (!res && check_part[i]) {
178 memset(&state->parts, 0, sizeof(state->parts));
179 res = check_part[i++](state, bdev);
180 }
181 if (res > 0)
182 return state;
183 if (!res)
184 printk(" unknown partition table\n");
185 else if (warn_no_part)
186 printk(" unable to read partition table\n");
187 kfree(state);
188 return NULL;
189}
190
191/*
192 * sysfs bindings for partitions
193 */
194
195struct part_attribute {
196 struct attribute attr;
197 ssize_t (*show)(struct hd_struct *,char *);
198};
199
200static ssize_t
201part_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
202{
203 struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
204 struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
205 ssize_t ret = 0;
206 if (part_attr->show)
207 ret = part_attr->show(p,page);
208 return ret;
209}
210
211static struct sysfs_ops part_sysfs_ops = {
212 .show = part_attr_show,
213};
214
215static ssize_t part_dev_read(struct hd_struct * p, char *page)
216{
217 struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
218 dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno);
219 return print_dev_t(page, dev);
220}
221static ssize_t part_start_read(struct hd_struct * p, char *page)
222{
223 return sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
224}
225static ssize_t part_size_read(struct hd_struct * p, char *page)
226{
227 return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
228}
229static ssize_t part_stat_read(struct hd_struct * p, char *page)
230{
231 return sprintf(page, "%8u %8llu %8u %8llu\n",
232 p->reads, (unsigned long long)p->read_sectors,
233 p->writes, (unsigned long long)p->write_sectors);
234}
235static struct part_attribute part_attr_dev = {
236 .attr = {.name = "dev", .mode = S_IRUGO },
237 .show = part_dev_read
238};
239static struct part_attribute part_attr_start = {
240 .attr = {.name = "start", .mode = S_IRUGO },
241 .show = part_start_read
242};
243static struct part_attribute part_attr_size = {
244 .attr = {.name = "size", .mode = S_IRUGO },
245 .show = part_size_read
246};
247static struct part_attribute part_attr_stat = {
248 .attr = {.name = "stat", .mode = S_IRUGO },
249 .show = part_stat_read
250};
251
252static struct attribute * default_attrs[] = {
253 &part_attr_dev.attr,
254 &part_attr_start.attr,
255 &part_attr_size.attr,
256 &part_attr_stat.attr,
257 NULL,
258};
259
260extern struct subsystem block_subsys;
261
262static void part_release(struct kobject *kobj)
263{
264 struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
265 kfree(p);
266}
267
268struct kobj_type ktype_part = {
269 .release = part_release,
270 .default_attrs = default_attrs,
271 .sysfs_ops = &part_sysfs_ops,
272};
273
274void delete_partition(struct gendisk *disk, int part)
275{
276 struct hd_struct *p = disk->part[part-1];
277 if (!p)
278 return;
279 if (!p->nr_sects)
280 return;
281 disk->part[part-1] = NULL;
282 p->start_sect = 0;
283 p->nr_sects = 0;
284 p->reads = p->writes = p->read_sectors = p->write_sectors = 0;
285 devfs_remove("%s/part%d", disk->devfs_name, part);
286 kobject_unregister(&p->kobj);
287}
288
289void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
290{
291 struct hd_struct *p;
292
293 p = kmalloc(sizeof(*p), GFP_KERNEL);
294 if (!p)
295 return;
296
297 memset(p, 0, sizeof(*p));
298 p->start_sect = start;
299 p->nr_sects = len;
300 p->partno = part;
301
302 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part),
303 S_IFBLK|S_IRUSR|S_IWUSR,
304 "%s/part%d", disk->devfs_name, part);
305
306 if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
307 snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
308 else
309 snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
310 p->kobj.parent = &disk->kobj;
311 p->kobj.ktype = &ktype_part;
312 kobject_register(&p->kobj);
313 disk->part[part-1] = p;
314}
315
316static void disk_sysfs_symlinks(struct gendisk *disk)
317{
318 struct device *target = get_device(disk->driverfs_dev);
319 if (target) {
320 sysfs_create_link(&disk->kobj,&target->kobj,"device");
321 sysfs_create_link(&target->kobj,&disk->kobj,"block");
322 }
323}
324
325/* Not exported, helper to add_disk(). */
326void register_disk(struct gendisk *disk)
327{
328 struct block_device *bdev;
329 char *s;
330 int err;
331
332 strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
333 /* ewww... some of these buggers have / in name... */
334 s = strchr(disk->kobj.name, '/');
335 if (s)
336 *s = '!';
337 if ((err = kobject_add(&disk->kobj)))
338 return;
339 disk_sysfs_symlinks(disk);
340
341 /* No minors to use for partitions */
342 if (disk->minors == 1) {
343 if (disk->devfs_name[0] != '\0')
344 devfs_add_disk(disk);
345 return;
346 }
347
348 /* always add handle for the whole disk */
349 devfs_add_partitioned(disk);
350
351 /* No such device (e.g., media were just removed) */
352 if (!get_capacity(disk))
353 return;
354
355 bdev = bdget_disk(disk, 0);
356 if (!bdev)
357 return;
358
359 bdev->bd_invalidated = 1;
360 if (blkdev_get(bdev, FMODE_READ, 0) < 0)
361 return;
362 blkdev_put(bdev);
363}
364
365int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
366{
367 struct parsed_partitions *state;
368 int p, res;
369
370 if (bdev->bd_part_count)
371 return -EBUSY;
372 res = invalidate_partition(disk, 0);
373 if (res)
374 return res;
375 bdev->bd_invalidated = 0;
376 for (p = 1; p < disk->minors; p++)
377 delete_partition(disk, p);
378 if (disk->fops->revalidate_disk)
379 disk->fops->revalidate_disk(disk);
380 if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
381 return 0;
382 for (p = 1; p < state->limit; p++) {
383 sector_t size = state->parts[p].size;
384 sector_t from = state->parts[p].from;
385 if (!size)
386 continue;
387 add_partition(disk, p, from, size);
388#ifdef CONFIG_BLK_DEV_MD
389 if (state->parts[p].flags)
390 md_autodetect_dev(bdev->bd_dev+p);
391#endif
392 }
393 kfree(state);
394 return 0;
395}
396
397unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
398{
399 struct address_space *mapping = bdev->bd_inode->i_mapping;
400 struct page *page;
401
402 page = read_cache_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
403 (filler_t *)mapping->a_ops->readpage, NULL);
404 if (!IS_ERR(page)) {
405 wait_on_page_locked(page);
406 if (!PageUptodate(page))
407 goto fail;
408 if (PageError(page))
409 goto fail;
410 p->v = page;
411 return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9);
412fail:
413 page_cache_release(page);
414 }
415 p->v = NULL;
416 return NULL;
417}
418
419EXPORT_SYMBOL(read_dev_sector);
420
421void del_gendisk(struct gendisk *disk)
422{
423 int p;
424
425 /* invalidate stuff */
426 for (p = disk->minors - 1; p > 0; p--) {
427 invalidate_partition(disk, p);
428 delete_partition(disk, p);
429 }
430 invalidate_partition(disk, 0);
431 disk->capacity = 0;
432 disk->flags &= ~GENHD_FL_UP;
433 unlink_gendisk(disk);
434 disk_stat_set_all(disk, 0);
435 disk->stamp = disk->stamp_idle = 0;
436
437 devfs_remove_disk(disk);
438
439 if (disk->driverfs_dev) {
440 sysfs_remove_link(&disk->kobj, "device");
441 sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
442 put_device(disk->driverfs_dev);
443 }
444 kobject_del(&disk->kobj);
445}
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
new file mode 100644
index 00000000000..43adcc68e47
--- /dev/null
+++ b/fs/partitions/check.h
@@ -0,0 +1,36 @@
1#include <linux/pagemap.h>
2#include <linux/blkdev.h>
3
4/*
5 * add_gd_partition adds a partitions details to the devices partition
6 * description.
7 */
8enum { MAX_PART = 256 };
9
10struct parsed_partitions {
11 char name[BDEVNAME_SIZE];
12 struct {
13 sector_t from;
14 sector_t size;
15 int flags;
16 } parts[MAX_PART];
17 int next;
18 int limit;
19};
20
21static inline void
22put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
23{
24 if (n < p->limit) {
25 p->parts[n].from = from;
26 p->parts[n].size = size;
27 printk(" %s%d", p->name, n);
28 }
29}
30
31extern int warn_no_part;
32
33extern void parse_bsd(struct parsed_partitions *state,
34 struct block_device *bdev, u32 offset, u32 size,
35 int origin, char *flavour, int max_partitions);
36
diff --git a/fs/partitions/devfs.c b/fs/partitions/devfs.c
new file mode 100644
index 00000000000..87f50444fd3
--- /dev/null
+++ b/fs/partitions/devfs.c
@@ -0,0 +1,130 @@
1/*
2 * This tries to keep block devices away from devfs as much as possible.
3 */
4#include <linux/fs.h>
5#include <linux/devfs_fs_kernel.h>
6#include <linux/vmalloc.h>
7#include <linux/genhd.h>
8#include <linux/bitops.h>
9#include <asm/semaphore.h>
10
11
12struct unique_numspace {
13 u32 num_free; /* Num free in bits */
14 u32 length; /* Array length in bytes */
15 unsigned long *bits;
16 struct semaphore mutex;
17};
18
19static DECLARE_MUTEX(numspace_mutex);
20
21static int expand_numspace(struct unique_numspace *s)
22{
23 u32 length;
24 void *bits;
25
26 if (s->length < 16)
27 length = 16;
28 else
29 length = s->length << 1;
30
31 bits = vmalloc(length);
32 if (!bits)
33 return -ENOMEM;
34 if (s->bits) {
35 memcpy(bits, s->bits, s->length);
36 vfree(s->bits);
37 }
38
39 s->num_free = (length - s->length) << 3;
40 s->bits = bits;
41 memset(bits + s->length, 0, length - s->length);
42 s->length = length;
43
44 return 0;
45}
46
47static int alloc_unique_number(struct unique_numspace *s)
48{
49 int rval = 0;
50
51 down(&numspace_mutex);
52 if (s->num_free < 1)
53 rval = expand_numspace(s);
54 if (!rval) {
55 rval = find_first_zero_bit(s->bits, s->length << 3);
56 --s->num_free;
57 __set_bit(rval, s->bits);
58 }
59 up(&numspace_mutex);
60
61 return rval;
62}
63
64static void dealloc_unique_number(struct unique_numspace *s, int number)
65{
66 int old_val;
67
68 if (number >= 0) {
69 down(&numspace_mutex);
70 old_val = __test_and_clear_bit(number, s->bits);
71 if (old_val)
72 ++s->num_free;
73 up(&numspace_mutex);
74 }
75}
76
77static struct unique_numspace disc_numspace;
78static struct unique_numspace cdrom_numspace;
79
80void devfs_add_partitioned(struct gendisk *disk)
81{
82 char dirname[64], symlink[16];
83
84 devfs_mk_dir(disk->devfs_name);
85 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
86 S_IFBLK|S_IRUSR|S_IWUSR,
87 "%s/disc", disk->devfs_name);
88
89 disk->number = alloc_unique_number(&disc_numspace);
90
91 sprintf(symlink, "discs/disc%d", disk->number);
92 sprintf(dirname, "../%s", disk->devfs_name);
93 devfs_mk_symlink(symlink, dirname);
94
95}
96
97void devfs_add_disk(struct gendisk *disk)
98{
99 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
100 (disk->flags & GENHD_FL_CD) ?
101 S_IFBLK|S_IRUGO|S_IWUGO :
102 S_IFBLK|S_IRUSR|S_IWUSR,
103 "%s", disk->devfs_name);
104
105 if (disk->flags & GENHD_FL_CD) {
106 char dirname[64], symlink[16];
107
108 disk->number = alloc_unique_number(&cdrom_numspace);
109
110 sprintf(symlink, "cdroms/cdrom%d", disk->number);
111 sprintf(dirname, "../%s", disk->devfs_name);
112 devfs_mk_symlink(symlink, dirname);
113 }
114}
115
116void devfs_remove_disk(struct gendisk *disk)
117{
118 if (disk->minors != 1) {
119 devfs_remove("discs/disc%d", disk->number);
120 dealloc_unique_number(&disc_numspace, disk->number);
121 devfs_remove("%s/disc", disk->devfs_name);
122 }
123 if (disk->flags & GENHD_FL_CD) {
124 devfs_remove("cdroms/cdrom%d", disk->number);
125 dealloc_unique_number(&cdrom_numspace, disk->number);
126 }
127 devfs_remove(disk->devfs_name);
128}
129
130
diff --git a/fs/partitions/devfs.h b/fs/partitions/devfs.h
new file mode 100644
index 00000000000..176118b4e49
--- /dev/null
+++ b/fs/partitions/devfs.h
@@ -0,0 +1,10 @@
1
2#ifdef CONFIG_DEVFS_FS
3void devfs_add_disk(struct gendisk *dev);
4void devfs_add_partitioned(struct gendisk *dev);
5void devfs_remove_disk(struct gendisk *dev);
6#else
7# define devfs_add_disk(disk) do { } while (0)
8# define devfs_add_partitioned(disk) do { } while (0)
9# define devfs_remove_disk(disk) do { } while (0)
10#endif
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
new file mode 100644
index 00000000000..0f5b017aeba
--- /dev/null
+++ b/fs/partitions/efi.c
@@ -0,0 +1,645 @@
1/************************************************************
2 * EFI GUID Partition Table handling
3 * Per Intel EFI Specification v1.02
4 * http://developer.intel.com/technology/efi/efi.htm
5 * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
6 * Copyright 2000,2001,2002,2004 Dell Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * TODO:
24 *
25 * Changelog:
26 * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
27 * - test for valid PMBR and valid PGPT before ever reading
28 * AGPT, allow override with 'gpt' kernel command line option.
29 * - check for first/last_usable_lba outside of size of disk
30 *
31 * Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
32 * - Ported to 2.5.7-pre1 and 2.5.7-dj2
33 * - Applied patch to avoid fault in alternate header handling
34 * - cleaned up find_valid_gpt
35 * - On-disk structure and copy in memory is *always* LE now -
36 * swab fields as needed
37 * - remove print_gpt_header()
38 * - only use first max_p partition entries, to keep the kernel minor number
39 * and partition numbers tied.
40 *
41 * Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com>
42 * - Removed __PRIPTR_PREFIX - not being used
43 *
44 * Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
45 * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
46 *
47 * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
48 * - Added compare_gpts().
49 * - moved le_efi_guid_to_cpus() back into this file. GPT is the only
50 * thing that keeps EFI GUIDs on disk.
51 * - Changed gpt structure names and members to be simpler and more Linux-like.
52 *
53 * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
54 * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
55 *
56 * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
57 * - Changed function comments to DocBook style per Andreas Dilger suggestion.
58 *
59 * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
60 * - Change read_lba() to use the page cache per Al Viro's work.
61 * - print u64s properly on all architectures
62 * - fixed debug_printk(), now Dprintk()
63 *
64 * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
65 * - Style cleanups
66 * - made most functions static
67 * - Endianness addition
68 * - remove test for second alternate header, as it's not per spec,
69 * and is unnecessary. There's now a method to read/write the last
70 * sector of an odd-sized disk from user space. No tools have ever
71 * been released which used this code, so it's effectively dead.
72 * - Per Asit Mallick of Intel, added a test for a valid PMBR.
73 * - Added kernel command line option 'gpt' to override valid PMBR test.
74 *
75 * Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
76 * - added devfs volume UUID support (/dev/volumes/uuids) for
77 * mounting file systems by the partition GUID.
78 *
79 * Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com>
80 * - Moved crc32() to linux/lib, added efi_crc32().
81 *
82 * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
83 * - Replaced Intel's CRC32 function with an equivalent
84 * non-license-restricted version.
85 *
86 * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
87 * - Fixed the last_lba() call to return the proper last block
88 *
89 * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
90 * - Thanks to Andries Brouwer for his debugging assistance.
91 * - Code works, detects all the partitions.
92 *
93 ************************************************************/
94#include <linux/config.h>
95#include <linux/crc32.h>
96#include "check.h"
97#include "efi.h"
98
99#undef EFI_DEBUG
100#ifdef EFI_DEBUG
101#define Dprintk(x...) printk(KERN_DEBUG x)
102#else
103#define Dprintk(x...)
104#endif
105
106/* This allows a kernel command line option 'gpt' to override
107 * the test for invalid PMBR. Not __initdata because reloading
108 * the partition tables happens after init too.
109 */
110static int force_gpt;
111static int __init
112force_gpt_fn(char *str)
113{
114 force_gpt = 1;
115 return 1;
116}
117__setup("gpt", force_gpt_fn);
118
119
120/**
121 * efi_crc32() - EFI version of crc32 function
122 * @buf: buffer to calculate crc32 of
123 * @len - length of buf
124 *
125 * Description: Returns EFI-style CRC32 value for @buf
126 *
127 * This function uses the little endian Ethernet polynomial
128 * but seeds the function with ~0, and xor's with ~0 at the end.
129 * Note, the EFI Specification, v1.02, has a reference to
130 * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
131 */
132static inline u32
133efi_crc32(const void *buf, unsigned long len)
134{
135 return (crc32(~0L, buf, len) ^ ~0L);
136}
137
138/**
139 * last_lba(): return number of last logical block of device
140 * @bdev: block device
141 *
142 * Description: Returns last LBA value on success, 0 on error.
143 * This is stored (by sd and ide-geometry) in
144 * the part[0] entry for this disk, and is the number of
145 * physical sectors available on the disk.
146 */
147static u64
148last_lba(struct block_device *bdev)
149{
150 if (!bdev || !bdev->bd_inode)
151 return 0;
152 return (bdev->bd_inode->i_size >> 9) - 1ULL;
153}
154
155static inline int
156pmbr_part_valid(struct partition *part, u64 lastlba)
157{
158 if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
159 le32_to_cpu(part->start_sect) == 1UL)
160 return 1;
161 return 0;
162}
163
164/**
165 * is_pmbr_valid(): test Protective MBR for validity
166 * @mbr: pointer to a legacy mbr structure
167 * @lastlba: last_lba for the whole device
168 *
169 * Description: Returns 1 if PMBR is valid, 0 otherwise.
170 * Validity depends on two things:
171 * 1) MSDOS signature is in the last two bytes of the MBR
172 * 2) One partition of type 0xEE is found
173 */
174static int
175is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
176{
177 int i;
178 if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
179 return 0;
180 for (i = 0; i < 4; i++)
181 if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
182 return 1;
183 return 0;
184}
185
186/**
187 * read_lba(): Read bytes from disk, starting at given LBA
188 * @bdev
189 * @lba
190 * @buffer
191 * @size_t
192 *
193 * Description: Reads @count bytes from @bdev into @buffer.
194 * Returns number of bytes read on success, 0 on error.
195 */
196static size_t
197read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count)
198{
199 size_t totalreadcount = 0;
200
201 if (!bdev || !buffer || lba > last_lba(bdev))
202 return 0;
203
204 while (count) {
205 int copied = 512;
206 Sector sect;
207 unsigned char *data = read_dev_sector(bdev, lba++, &sect);
208 if (!data)
209 break;
210 if (copied > count)
211 copied = count;
212 memcpy(buffer, data, copied);
213 put_dev_sector(sect);
214 buffer += copied;
215 totalreadcount +=copied;
216 count -= copied;
217 }
218 return totalreadcount;
219}
220
221/**
222 * alloc_read_gpt_entries(): reads partition entries from disk
223 * @bdev
224 * @gpt - GPT header
225 *
226 * Description: Returns ptes on success, NULL on error.
227 * Allocates space for PTEs based on information found in @gpt.
228 * Notes: remember to free pte when you're done!
229 */
230static gpt_entry *
231alloc_read_gpt_entries(struct block_device *bdev, gpt_header *gpt)
232{
233 size_t count;
234 gpt_entry *pte;
235 if (!bdev || !gpt)
236 return NULL;
237
238 count = le32_to_cpu(gpt->num_partition_entries) *
239 le32_to_cpu(gpt->sizeof_partition_entry);
240 if (!count)
241 return NULL;
242 pte = kmalloc(count, GFP_KERNEL);
243 if (!pte)
244 return NULL;
245 memset(pte, 0, count);
246
247 if (read_lba(bdev, le64_to_cpu(gpt->partition_entry_lba),
248 (u8 *) pte,
249 count) < count) {
250 kfree(pte);
251 pte=NULL;
252 return NULL;
253 }
254 return pte;
255}
256
257/**
258 * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
259 * @bdev
260 * @lba is the Logical Block Address of the partition table
261 *
262 * Description: returns GPT header on success, NULL on error. Allocates
263 * and fills a GPT header starting at @ from @bdev.
264 * Note: remember to free gpt when finished with it.
265 */
266static gpt_header *
267alloc_read_gpt_header(struct block_device *bdev, u64 lba)
268{
269 gpt_header *gpt;
270 if (!bdev)
271 return NULL;
272
273 gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL);
274 if (!gpt)
275 return NULL;
276 memset(gpt, 0, sizeof (gpt_header));
277
278 if (read_lba(bdev, lba, (u8 *) gpt,
279 sizeof (gpt_header)) < sizeof (gpt_header)) {
280 kfree(gpt);
281 gpt=NULL;
282 return NULL;
283 }
284
285 return gpt;
286}
287
288/**
289 * is_gpt_valid() - tests one GPT header and PTEs for validity
290 * @bdev
291 * @lba is the logical block address of the GPT header to test
292 * @gpt is a GPT header ptr, filled on return.
293 * @ptes is a PTEs ptr, filled on return.
294 *
295 * Description: returns 1 if valid, 0 on error.
296 * If valid, returns pointers to newly allocated GPT header and PTEs.
297 */
298static int
299is_gpt_valid(struct block_device *bdev, u64 lba,
300 gpt_header **gpt, gpt_entry **ptes)
301{
302 u32 crc, origcrc;
303 u64 lastlba;
304
305 if (!bdev || !gpt || !ptes)
306 return 0;
307 if (!(*gpt = alloc_read_gpt_header(bdev, lba)))
308 return 0;
309
310 /* Check the GUID Partition Table signature */
311 if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
312 Dprintk("GUID Partition Table Header signature is wrong:"
313 "%lld != %lld\n",
314 (unsigned long long)le64_to_cpu((*gpt)->signature),
315 (unsigned long long)GPT_HEADER_SIGNATURE);
316 goto fail;
317 }
318
319 /* Check the GUID Partition Table CRC */
320 origcrc = le32_to_cpu((*gpt)->header_crc32);
321 (*gpt)->header_crc32 = 0;
322 crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
323
324 if (crc != origcrc) {
325 Dprintk
326 ("GUID Partition Table Header CRC is wrong: %x != %x\n",
327 crc, origcrc);
328 goto fail;
329 }
330 (*gpt)->header_crc32 = cpu_to_le32(origcrc);
331
332 /* Check that the my_lba entry points to the LBA that contains
333 * the GUID Partition Table */
334 if (le64_to_cpu((*gpt)->my_lba) != lba) {
335 Dprintk("GPT my_lba incorrect: %lld != %lld\n",
336 (unsigned long long)le64_to_cpu((*gpt)->my_lba),
337 (unsigned long long)lba);
338 goto fail;
339 }
340
341 /* Check the first_usable_lba and last_usable_lba are
342 * within the disk.
343 */
344 lastlba = last_lba(bdev);
345 if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
346 Dprintk("GPT: first_usable_lba incorrect: %lld > %lld\n",
347 (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
348 (unsigned long long)lastlba);
349 goto fail;
350 }
351 if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
352 Dprintk("GPT: last_usable_lba incorrect: %lld > %lld\n",
353 (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
354 (unsigned long long)lastlba);
355 goto fail;
356 }
357
358 if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt)))
359 goto fail;
360
361 /* Check the GUID Partition Entry Array CRC */
362 crc = efi_crc32((const unsigned char *) (*ptes),
363 le32_to_cpu((*gpt)->num_partition_entries) *
364 le32_to_cpu((*gpt)->sizeof_partition_entry));
365
366 if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
367 Dprintk("GUID Partitition Entry Array CRC check failed.\n");
368 goto fail_ptes;
369 }
370
371 /* We're done, all's well */
372 return 1;
373
374 fail_ptes:
375 kfree(*ptes);
376 *ptes = NULL;
377 fail:
378 kfree(*gpt);
379 *gpt = NULL;
380 return 0;
381}
382
383/**
384 * is_pte_valid() - tests one PTE for validity
385 * @pte is the pte to check
386 * @lastlba is last lba of the disk
387 *
388 * Description: returns 1 if valid, 0 on error.
389 */
390static inline int
391is_pte_valid(const gpt_entry *pte, const u64 lastlba)
392{
393 if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
394 le64_to_cpu(pte->starting_lba) > lastlba ||
395 le64_to_cpu(pte->ending_lba) > lastlba)
396 return 0;
397 return 1;
398}
399
400/**
401 * compare_gpts() - Search disk for valid GPT headers and PTEs
402 * @pgpt is the primary GPT header
403 * @agpt is the alternate GPT header
404 * @lastlba is the last LBA number
405 * Description: Returns nothing. Sanity checks pgpt and agpt fields
406 * and prints warnings on discrepancies.
407 *
408 */
409static void
410compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
411{
412 int error_found = 0;
413 if (!pgpt || !agpt)
414 return;
415 if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
416 printk(KERN_WARNING
417 "GPT:Primary header LBA != Alt. header alternate_lba\n");
418 printk(KERN_WARNING "GPT:%lld != %lld\n",
419 (unsigned long long)le64_to_cpu(pgpt->my_lba),
420 (unsigned long long)le64_to_cpu(agpt->alternate_lba));
421 error_found++;
422 }
423 if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
424 printk(KERN_WARNING
425 "GPT:Primary header alternate_lba != Alt. header my_lba\n");
426 printk(KERN_WARNING "GPT:%lld != %lld\n",
427 (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
428 (unsigned long long)le64_to_cpu(agpt->my_lba));
429 error_found++;
430 }
431 if (le64_to_cpu(pgpt->first_usable_lba) !=
432 le64_to_cpu(agpt->first_usable_lba)) {
433 printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
434 printk(KERN_WARNING "GPT:%lld != %lld\n",
435 (unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
436 (unsigned long long)le64_to_cpu(agpt->first_usable_lba));
437 error_found++;
438 }
439 if (le64_to_cpu(pgpt->last_usable_lba) !=
440 le64_to_cpu(agpt->last_usable_lba)) {
441 printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
442 printk(KERN_WARNING "GPT:%lld != %lld\n",
443 (unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
444 (unsigned long long)le64_to_cpu(agpt->last_usable_lba));
445 error_found++;
446 }
447 if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
448 printk(KERN_WARNING "GPT:disk_guids don't match.\n");
449 error_found++;
450 }
451 if (le32_to_cpu(pgpt->num_partition_entries) !=
452 le32_to_cpu(agpt->num_partition_entries)) {
453 printk(KERN_WARNING "GPT:num_partition_entries don't match: "
454 "0x%x != 0x%x\n",
455 le32_to_cpu(pgpt->num_partition_entries),
456 le32_to_cpu(agpt->num_partition_entries));
457 error_found++;
458 }
459 if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
460 le32_to_cpu(agpt->sizeof_partition_entry)) {
461 printk(KERN_WARNING
462 "GPT:sizeof_partition_entry values don't match: "
463 "0x%x != 0x%x\n",
464 le32_to_cpu(pgpt->sizeof_partition_entry),
465 le32_to_cpu(agpt->sizeof_partition_entry));
466 error_found++;
467 }
468 if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
469 le32_to_cpu(agpt->partition_entry_array_crc32)) {
470 printk(KERN_WARNING
471 "GPT:partition_entry_array_crc32 values don't match: "
472 "0x%x != 0x%x\n",
473 le32_to_cpu(pgpt->partition_entry_array_crc32),
474 le32_to_cpu(agpt->partition_entry_array_crc32));
475 error_found++;
476 }
477 if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
478 printk(KERN_WARNING
479 "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
480 printk(KERN_WARNING "GPT:%lld != %lld\n",
481 (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
482 (unsigned long long)lastlba);
483 error_found++;
484 }
485
486 if (le64_to_cpu(agpt->my_lba) != lastlba) {
487 printk(KERN_WARNING
488 "GPT:Alternate GPT header not at the end of the disk.\n");
489 printk(KERN_WARNING "GPT:%lld != %lld\n",
490 (unsigned long long)le64_to_cpu(agpt->my_lba),
491 (unsigned long long)lastlba);
492 error_found++;
493 }
494
495 if (error_found)
496 printk(KERN_WARNING
497 "GPT: Use GNU Parted to correct GPT errors.\n");
498 return;
499}
500
501/**
502 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
503 * @bdev
504 * @gpt is a GPT header ptr, filled on return.
505 * @ptes is a PTEs ptr, filled on return.
506 * Description: Returns 1 if valid, 0 on error.
507 * If valid, returns pointers to newly allocated GPT header and PTEs.
508 * Validity depends on PMBR being valid (or being overridden by the
509 * 'gpt' kernel command line option) and finding either the Primary
510 * GPT header and PTEs valid, or the Alternate GPT header and PTEs
511 * valid. If the Primary GPT header is not valid, the Alternate GPT header
512 * is not checked unless the 'gpt' kernel command line option is passed.
513 * This protects against devices which misreport their size, and forces
514 * the user to decide to use the Alternate GPT.
515 */
516static int
517find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
518{
519 int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
520 gpt_header *pgpt = NULL, *agpt = NULL;
521 gpt_entry *pptes = NULL, *aptes = NULL;
522 legacy_mbr *legacymbr = NULL;
523 u64 lastlba;
524 if (!bdev || !gpt || !ptes)
525 return 0;
526
527 lastlba = last_lba(bdev);
528 if (!force_gpt) {
529 /* This will be added to the EFI Spec. per Intel after v1.02. */
530 legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
531 if (legacymbr) {
532 memset(legacymbr, 0, sizeof (*legacymbr));
533 read_lba(bdev, 0, (u8 *) legacymbr,
534 sizeof (*legacymbr));
535 good_pmbr = is_pmbr_valid(legacymbr, lastlba);
536 kfree(legacymbr);
537 legacymbr=NULL;
538 }
539 if (!good_pmbr)
540 goto fail;
541 }
542
543 good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
544 &pgpt, &pptes);
545 if (good_pgpt)
546 good_agpt = is_gpt_valid(bdev,
547 le64_to_cpu(pgpt->alternate_lba),
548 &agpt, &aptes);
549 if (!good_agpt && force_gpt)
550 good_agpt = is_gpt_valid(bdev, lastlba,
551 &agpt, &aptes);
552
553 /* The obviously unsuccessful case */
554 if (!good_pgpt && !good_agpt)
555 goto fail;
556
557 compare_gpts(pgpt, agpt, lastlba);
558
559 /* The good cases */
560 if (good_pgpt) {
561 *gpt = pgpt;
562 *ptes = pptes;
563 kfree(agpt);
564 kfree(aptes);
565 if (!good_agpt) {
566 printk(KERN_WARNING
567 "Alternate GPT is invalid, "
568 "using primary GPT.\n");
569 }
570 return 1;
571 }
572 else if (good_agpt) {
573 *gpt = agpt;
574 *ptes = aptes;
575 kfree(pgpt);
576 kfree(pptes);
577 printk(KERN_WARNING
578 "Primary GPT is invalid, using alternate GPT.\n");
579 return 1;
580 }
581
582 fail:
583 kfree(pgpt);
584 kfree(agpt);
585 kfree(pptes);
586 kfree(aptes);
587 *gpt = NULL;
588 *ptes = NULL;
589 return 0;
590}
591
592/**
593 * efi_partition(struct parsed_partitions *state, struct block_device *bdev)
594 * @state
595 * @bdev
596 *
597 * Description: called from check.c, if the disk contains GPT
598 * partitions, sets up partition entries in the kernel.
599 *
600 * If the first block on the disk is a legacy MBR,
601 * it will get handled by msdos_partition().
602 * If it's a Protective MBR, we'll handle it here.
603 *
604 * We do not create a Linux partition for GPT, but
605 * only for the actual data partitions.
606 * Returns:
607 * -1 if unable to read the partition table
608 * 0 if this isn't our partition table
609 * 1 if successful
610 *
611 */
612int
613efi_partition(struct parsed_partitions *state, struct block_device *bdev)
614{
615 gpt_header *gpt = NULL;
616 gpt_entry *ptes = NULL;
617 u32 i;
618
619 if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) {
620 kfree(gpt);
621 kfree(ptes);
622 return 0;
623 }
624
625 Dprintk("GUID Partition Table is valid! Yea!\n");
626
627 for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
628 if (!is_pte_valid(&ptes[i], last_lba(bdev)))
629 continue;
630
631 put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba),
632 (le64_to_cpu(ptes[i].ending_lba) -
633 le64_to_cpu(ptes[i].starting_lba) +
634 1ULL));
635
636 /* If this is a RAID volume, tell md */
637 if (!efi_guidcmp(ptes[i].partition_type_guid,
638 PARTITION_LINUX_RAID_GUID))
639 state->parts[i+1].flags = 1;
640 }
641 kfree(ptes);
642 kfree(gpt);
643 printk("\n");
644 return 1;
645}
diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h
new file mode 100644
index 00000000000..c44fb056144
--- /dev/null
+++ b/fs/partitions/efi.h
@@ -0,0 +1,131 @@
1/************************************************************
2 * EFI GUID Partition Table
3 * Per Intel EFI Specification v1.02
4 * http://developer.intel.com/technology/efi/efi.htm
5 *
6 * By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000
7 * Copyright 2000,2001 Dell Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ************************************************************/
24
25#ifndef FS_PART_EFI_H_INCLUDED
26#define FS_PART_EFI_H_INCLUDED
27
28#include <linux/types.h>
29#include <linux/config.h>
30#include <linux/fs.h>
31#include <linux/genhd.h>
32#include <linux/kernel.h>
33#include <linux/major.h>
34#include <linux/string.h>
35#include <linux/efi.h>
36
37#define MSDOS_MBR_SIGNATURE 0xaa55
38#define EFI_PMBR_OSTYPE_EFI 0xEF
39#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
40
41#define GPT_BLOCK_SIZE 512
42#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
43#define GPT_HEADER_REVISION_V1 0x00010000
44#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
45
46#define PARTITION_SYSTEM_GUID \
47 EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
48 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
49#define LEGACY_MBR_PARTITION_GUID \
50 EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
51 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
52#define PARTITION_MSFT_RESERVED_GUID \
53 EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
54 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
55#define PARTITION_BASIC_DATA_GUID \
56 EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
57 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
58#define PARTITION_LINUX_RAID_GUID \
59 EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
60 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
61#define PARTITION_LINUX_SWAP_GUID \
62 EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
63 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
64#define PARTITION_LINUX_LVM_GUID \
65 EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
66 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
67
68typedef struct _gpt_header {
69 __le64 signature;
70 __le32 revision;
71 __le32 header_size;
72 __le32 header_crc32;
73 __le32 reserved1;
74 __le64 my_lba;
75 __le64 alternate_lba;
76 __le64 first_usable_lba;
77 __le64 last_usable_lba;
78 efi_guid_t disk_guid;
79 __le64 partition_entry_lba;
80 __le32 num_partition_entries;
81 __le32 sizeof_partition_entry;
82 __le32 partition_entry_array_crc32;
83 u8 reserved2[GPT_BLOCK_SIZE - 92];
84} __attribute__ ((packed)) gpt_header;
85
86typedef struct _gpt_entry_attributes {
87 u64 required_to_function:1;
88 u64 reserved:47;
89 u64 type_guid_specific:16;
90} __attribute__ ((packed)) gpt_entry_attributes;
91
92typedef struct _gpt_entry {
93 efi_guid_t partition_type_guid;
94 efi_guid_t unique_partition_guid;
95 __le64 starting_lba;
96 __le64 ending_lba;
97 gpt_entry_attributes attributes;
98 efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
99} __attribute__ ((packed)) gpt_entry;
100
101typedef struct _legacy_mbr {
102 u8 boot_code[440];
103 __le32 unique_mbr_signature;
104 __le16 unknown;
105 struct partition partition_record[4];
106 __le16 signature;
107} __attribute__ ((packed)) legacy_mbr;
108
109/* Functions */
110extern int efi_partition(struct parsed_partitions *state, struct block_device *bdev);
111
112#endif
113
114/*
115 * Overrides for Emacs so that we follow Linus's tabbing style.
116 * Emacs will notice this stuff at the end of the file and automatically
117 * adjust the settings for this buffer only. This must remain at the end
118 * of the file.
119 * --------------------------------------------------------------------------
120 * Local variables:
121 * c-indent-level: 4
122 * c-brace-imaginary-offset: 0
123 * c-brace-offset: -4
124 * c-argdecl-indent: 4
125 * c-label-offset: -4
126 * c-continued-statement-offset: 4
127 * c-continued-brace-offset: 0
128 * indent-tabs-mode: nil
129 * tab-width: 8
130 * End:
131 */
diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c
new file mode 100644
index 00000000000..d59dcbf2bd4
--- /dev/null
+++ b/fs/partitions/ibm.c
@@ -0,0 +1,191 @@
1/*
2 * File...........: linux/fs/partitions/ibm.c
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 * Volker Sameske <sameske@de.ibm.com>
5 * Bugreports.to..: <Linux390@de.ibm.com>
6 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
7
8 * History of changes (starts July 2000)
9 * 07/10/00 Fixed detection of CMS formatted disks
10 * 02/13/00 VTOC partition support added
11 * 12/27/01 fixed PL030593 (CMS reserved minidisk not detected on 64 bit)
12 * 07/24/03 no longer using contents of freed page for CMS label recognition (BZ3611)
13 */
14
15#include <linux/config.h>
16#include <linux/buffer_head.h>
17#include <linux/hdreg.h>
18#include <linux/slab.h>
19#include <asm/dasd.h>
20#include <asm/ebcdic.h>
21#include <asm/uaccess.h>
22#include <asm/vtoc.h>
23
24#include "check.h"
25#include "ibm.h"
26
27/*
28 * compute the block number from a
29 * cyl-cyl-head-head structure
30 */
31static inline int
32cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
33 return ptr->cc * geo->heads * geo->sectors +
34 ptr->hh * geo->sectors;
35}
36
37
38/*
39 * compute the block number from a
40 * cyl-cyl-head-head-block structure
41 */
42static inline int
43cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
44 return ptr->cc * geo->heads * geo->sectors +
45 ptr->hh * geo->sectors +
46 ptr->b;
47}
48
49/*
50 */
51int
52ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
53{
54 int blocksize, offset, size;
55 dasd_information_t *info;
56 struct hd_geometry *geo;
57 char type[5] = {0,};
58 char name[7] = {0,};
59 volume_label_t *vlabel;
60 unsigned char *data;
61 Sector sect;
62
63 if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
64 goto out_noinfo;
65 if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
66 goto out_nogeo;
67 if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
68 goto out_novlab;
69
70 if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
71 ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
72 goto out_noioctl;
73
74 if ((blocksize = bdev_hardsect_size(bdev)) <= 0)
75 goto out_badsect;
76
77 /*
78 * Get volume label, extract name and type.
79 */
80 data = read_dev_sector(bdev, info->label_block*(blocksize/512), &sect);
81 if (data == NULL)
82 goto out_readerr;
83
84 strncpy (type, data, 4);
85 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD")))
86 strncpy(name, data + 8, 6);
87 else
88 strncpy(name, data + 4, 6);
89 memcpy (vlabel, data, sizeof(volume_label_t));
90 put_dev_sector(sect);
91
92 EBCASC(type, 4);
93 EBCASC(name, 6);
94
95 /*
96 * Three different types: CMS1, VOL1 and LNX1/unlabeled
97 */
98 if (strncmp(type, "CMS1", 4) == 0) {
99 /*
100 * VM style CMS1 labeled disk
101 */
102 int *label = (int *) vlabel;
103
104 if (label[13] != 0) {
105 printk("CMS1/%8s(MDSK):", name);
106 /* disk is reserved minidisk */
107 blocksize = label[3];
108 offset = label[13];
109 size = (label[7] - 1)*(blocksize >> 9);
110 } else {
111 printk("CMS1/%8s:", name);
112 offset = (info->label_block + 1);
113 size = bdev->bd_inode->i_size >> 9;
114 }
115 put_partition(state, 1, offset*(blocksize >> 9),
116 size-offset*(blocksize >> 9));
117 } else if ((strncmp(type, "VOL1", 4) == 0) &&
118 (!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
119 /*
120 * New style VOL1 labeled disk
121 */
122 unsigned int blk;
123 int counter;
124
125 printk("VOL1/%8s:", name);
126
127 /* get block number and read then go through format1 labels */
128 blk = cchhb2blk(&vlabel->vtoc, geo) + 1;
129 counter = 0;
130 while ((data = read_dev_sector(bdev, blk*(blocksize/512),
131 &sect)) != NULL) {
132 format1_label_t f1;
133
134 memcpy(&f1, data, sizeof(format1_label_t));
135 put_dev_sector(sect);
136
137 /* skip FMT4 / FMT5 / FMT7 labels */
138 if (f1.DS1FMTID == _ascebc['4']
139 || f1.DS1FMTID == _ascebc['5']
140 || f1.DS1FMTID == _ascebc['7']) {
141 blk++;
142 continue;
143 }
144
145 /* only FMT1 valid at this point */
146 if (f1.DS1FMTID != _ascebc['1'])
147 break;
148
149 /* OK, we got valid partition data */
150 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
151 size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
152 offset + geo->sectors;
153 if (counter >= state->limit)
154 break;
155 put_partition(state, counter + 1,
156 offset * (blocksize >> 9),
157 size * (blocksize >> 9));
158 counter++;
159 blk++;
160 }
161 } else {
162 /*
163 * Old style LNX1 or unlabeled disk
164 */
165 if (strncmp(type, "LNX1", 4) == 0)
166 printk ("LNX1/%8s:", name);
167 else
168 printk("(nonl)/%8s:", name);
169 offset = (info->label_block + 1);
170 size = (bdev->bd_inode->i_size >> 9);
171 put_partition(state, 1, offset*(blocksize >> 9),
172 size-offset*(blocksize >> 9));
173 }
174
175 printk("\n");
176 kfree(vlabel);
177 kfree(geo);
178 kfree(info);
179 return 1;
180
181out_readerr:
182out_badsect:
183out_noioctl:
184 kfree(vlabel);
185out_novlab:
186 kfree(geo);
187out_nogeo:
188 kfree(info);
189out_noinfo:
190 return 0;
191}
diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h
new file mode 100644
index 00000000000..31f85a6ac45
--- /dev/null
+++ b/fs/partitions/ibm.h
@@ -0,0 +1 @@
int ibm_partition(struct parsed_partitions *, struct block_device *);
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
new file mode 100644
index 00000000000..7ab1c11dca4
--- /dev/null
+++ b/fs/partitions/ldm.c
@@ -0,0 +1,1483 @@
1/**
2 * ldm - Support for Windows Logical Disk Manager (Dynamic Disks)
3 *
4 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
5 * Copyright (c) 2001-2004 Anton Altaparmakov
6 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
7 *
8 * Documentation is available at http://linux-ntfs.sf.net/ldm
9 *
10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free Software
12 * Foundation; either version 2 of the License, or (at your option) any later
13 * version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program (in the main directory of the source in the file COPYING); if
22 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23 * Boston, MA 02111-1307 USA
24 */
25
26#include <linux/slab.h>
27#include <linux/pagemap.h>
28#include <linux/stringify.h>
29#include "ldm.h"
30#include "check.h"
31#include "msdos.h"
32
33typedef enum {
34 FALSE = 0,
35 TRUE = 1
36} BOOL;
37
38/**
39 * ldm_debug/info/error/crit - Output an error message
40 * @f: A printf format string containing the message
41 * @...: Variables to substitute into @f
42 *
43 * ldm_debug() writes a DEBUG level message to the syslog but only if the
44 * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
45 */
46#ifndef CONFIG_LDM_DEBUG
47#define ldm_debug(...) do {} while (0)
48#else
49#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __FUNCTION__, f, ##a)
50#endif
51
52#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __FUNCTION__, f, ##a)
53#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __FUNCTION__, f, ##a)
54#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __FUNCTION__, f, ##a)
55
56__attribute__ ((format (printf, 3, 4)))
57static void _ldm_printk (const char *level, const char *function,
58 const char *fmt, ...)
59{
60 static char buf[128];
61 va_list args;
62
63 va_start (args, fmt);
64 vsnprintf (buf, sizeof (buf), fmt, args);
65 va_end (args);
66
67 printk ("%s%s(): %s\n", level, function, buf);
68}
69
70
71/**
72 * ldm_parse_hexbyte - Convert a ASCII hex number to a byte
73 * @src: Pointer to at least 2 characters to convert.
74 *
75 * Convert a two character ASCII hex string to a number.
76 *
77 * Return: 0-255 Success, the byte was parsed correctly
78 * -1 Error, an invalid character was supplied
79 */
80static int ldm_parse_hexbyte (const u8 *src)
81{
82 unsigned int x; /* For correct wrapping */
83 int h;
84
85 /* high part */
86 if ((x = src[0] - '0') <= '9'-'0') h = x;
87 else if ((x = src[0] - 'a') <= 'f'-'a') h = x+10;
88 else if ((x = src[0] - 'A') <= 'F'-'A') h = x+10;
89 else return -1;
90 h <<= 4;
91
92 /* low part */
93 if ((x = src[1] - '0') <= '9'-'0') return h | x;
94 if ((x = src[1] - 'a') <= 'f'-'a') return h | (x+10);
95 if ((x = src[1] - 'A') <= 'F'-'A') return h | (x+10);
96 return -1;
97}
98
99/**
100 * ldm_parse_guid - Convert GUID from ASCII to binary
101 * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
102 * @dest: Memory block to hold binary GUID (16 bytes)
103 *
104 * N.B. The GUID need not be NULL terminated.
105 *
106 * Return: TRUE @dest contains binary GUID
107 * FALSE @dest contents are undefined
108 */
109static BOOL ldm_parse_guid (const u8 *src, u8 *dest)
110{
111 static const int size[] = { 4, 2, 2, 2, 6 };
112 int i, j, v;
113
114 if (src[8] != '-' || src[13] != '-' ||
115 src[18] != '-' || src[23] != '-')
116 return FALSE;
117
118 for (j = 0; j < 5; j++, src++)
119 for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
120 if ((v = ldm_parse_hexbyte (src)) < 0)
121 return FALSE;
122
123 return TRUE;
124}
125
126
127/**
128 * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure
129 * @data: Raw database PRIVHEAD structure loaded from the device
130 * @ph: In-memory privhead structure in which to return parsed information
131 *
132 * This parses the LDM database PRIVHEAD structure supplied in @data and
133 * sets up the in-memory privhead structure @ph with the obtained information.
134 *
135 * Return: TRUE @ph contains the PRIVHEAD data
136 * FALSE @ph contents are undefined
137 */
138static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
139{
140 BUG_ON (!data || !ph);
141
142 if (MAGIC_PRIVHEAD != BE64 (data)) {
143 ldm_error ("Cannot find PRIVHEAD structure. LDM database is"
144 " corrupt. Aborting.");
145 return FALSE;
146 }
147
148 ph->ver_major = BE16 (data + 0x000C);
149 ph->ver_minor = BE16 (data + 0x000E);
150 ph->logical_disk_start = BE64 (data + 0x011B);
151 ph->logical_disk_size = BE64 (data + 0x0123);
152 ph->config_start = BE64 (data + 0x012B);
153 ph->config_size = BE64 (data + 0x0133);
154
155 if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
156 ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d."
157 " Aborting.", 2, 11, ph->ver_major, ph->ver_minor);
158 return FALSE;
159 }
160 if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
161 /* Warn the user and continue, carefully */
162 ldm_info ("Database is normally %u bytes, it claims to "
163 "be %llu bytes.", LDM_DB_SIZE,
164 (unsigned long long)ph->config_size );
165 }
166 if ((ph->logical_disk_size == 0) ||
167 (ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) {
168 ldm_error ("PRIVHEAD disk size doesn't match real disk size");
169 return FALSE;
170 }
171
172 if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) {
173 ldm_error ("PRIVHEAD contains an invalid GUID.");
174 return FALSE;
175 }
176
177 ldm_debug ("Parsed PRIVHEAD successfully.");
178 return TRUE;
179}
180
181/**
182 * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure
183 * @data: Raw database TOCBLOCK structure loaded from the device
184 * @toc: In-memory toc structure in which to return parsed information
185 *
186 * This parses the LDM Database TOCBLOCK (table of contents) structure supplied
187 * in @data and sets up the in-memory tocblock structure @toc with the obtained
188 * information.
189 *
190 * N.B. The *_start and *_size values returned in @toc are not range-checked.
191 *
192 * Return: TRUE @toc contains the TOCBLOCK data
193 * FALSE @toc contents are undefined
194 */
195static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
196{
197 BUG_ON (!data || !toc);
198
199 if (MAGIC_TOCBLOCK != BE64 (data)) {
200 ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
201 return FALSE;
202 }
203 strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
204 toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
205 toc->bitmap1_start = BE64 (data + 0x2E);
206 toc->bitmap1_size = BE64 (data + 0x36);
207
208 if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
209 sizeof (toc->bitmap1_name)) != 0) {
210 ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
211 TOC_BITMAP1, toc->bitmap1_name);
212 return FALSE;
213 }
214 strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
215 toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
216 toc->bitmap2_start = BE64 (data + 0x50);
217 toc->bitmap2_size = BE64 (data + 0x58);
218 if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
219 sizeof (toc->bitmap2_name)) != 0) {
220 ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
221 TOC_BITMAP2, toc->bitmap2_name);
222 return FALSE;
223 }
224 ldm_debug ("Parsed TOCBLOCK successfully.");
225 return TRUE;
226}
227
228/**
229 * ldm_parse_vmdb - Read the LDM Database VMDB structure
230 * @data: Raw database VMDB structure loaded from the device
231 * @vm: In-memory vmdb structure in which to return parsed information
232 *
233 * This parses the LDM Database VMDB structure supplied in @data and sets up
234 * the in-memory vmdb structure @vm with the obtained information.
235 *
236 * N.B. The *_start, *_size and *_seq values will be range-checked later.
237 *
238 * Return: TRUE @vm contains VMDB info
239 * FALSE @vm contents are undefined
240 */
241static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
242{
243 BUG_ON (!data || !vm);
244
245 if (MAGIC_VMDB != BE32 (data)) {
246 ldm_crit ("Cannot find the VMDB, database may be corrupt.");
247 return FALSE;
248 }
249
250 vm->ver_major = BE16 (data + 0x12);
251 vm->ver_minor = BE16 (data + 0x14);
252 if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
253 ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
254 "Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
255 return FALSE;
256 }
257
258 vm->vblk_size = BE32 (data + 0x08);
259 vm->vblk_offset = BE32 (data + 0x0C);
260 vm->last_vblk_seq = BE32 (data + 0x04);
261
262 ldm_debug ("Parsed VMDB successfully.");
263 return TRUE;
264}
265
266/**
267 * ldm_compare_privheads - Compare two privhead objects
268 * @ph1: First privhead
269 * @ph2: Second privhead
270 *
271 * This compares the two privhead structures @ph1 and @ph2.
272 *
273 * Return: TRUE Identical
274 * FALSE Different
275 */
276static BOOL ldm_compare_privheads (const struct privhead *ph1,
277 const struct privhead *ph2)
278{
279 BUG_ON (!ph1 || !ph2);
280
281 return ((ph1->ver_major == ph2->ver_major) &&
282 (ph1->ver_minor == ph2->ver_minor) &&
283 (ph1->logical_disk_start == ph2->logical_disk_start) &&
284 (ph1->logical_disk_size == ph2->logical_disk_size) &&
285 (ph1->config_start == ph2->config_start) &&
286 (ph1->config_size == ph2->config_size) &&
287 !memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE));
288}
289
290/**
291 * ldm_compare_tocblocks - Compare two tocblock objects
292 * @toc1: First toc
293 * @toc2: Second toc
294 *
295 * This compares the two tocblock structures @toc1 and @toc2.
296 *
297 * Return: TRUE Identical
298 * FALSE Different
299 */
300static BOOL ldm_compare_tocblocks (const struct tocblock *toc1,
301 const struct tocblock *toc2)
302{
303 BUG_ON (!toc1 || !toc2);
304
305 return ((toc1->bitmap1_start == toc2->bitmap1_start) &&
306 (toc1->bitmap1_size == toc2->bitmap1_size) &&
307 (toc1->bitmap2_start == toc2->bitmap2_start) &&
308 (toc1->bitmap2_size == toc2->bitmap2_size) &&
309 !strncmp (toc1->bitmap1_name, toc2->bitmap1_name,
310 sizeof (toc1->bitmap1_name)) &&
311 !strncmp (toc1->bitmap2_name, toc2->bitmap2_name,
312 sizeof (toc1->bitmap2_name)));
313}
314
315/**
316 * ldm_validate_privheads - Compare the primary privhead with its backups
317 * @bdev: Device holding the LDM Database
318 * @ph1: Memory struct to fill with ph contents
319 *
320 * Read and compare all three privheads from disk.
321 *
322 * The privheads on disk show the size and location of the main disk area and
323 * the configuration area (the database). The values are range-checked against
324 * @hd, which contains the real size of the disk.
325 *
326 * Return: TRUE Success
327 * FALSE Error
328 */
329static BOOL ldm_validate_privheads (struct block_device *bdev,
330 struct privhead *ph1)
331{
332 static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
333 struct privhead *ph[3] = { ph1 };
334 Sector sect;
335 u8 *data;
336 BOOL result = FALSE;
337 long num_sects;
338 int i;
339
340 BUG_ON (!bdev || !ph1);
341
342 ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL);
343 ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL);
344 if (!ph[1] || !ph[2]) {
345 ldm_crit ("Out of memory.");
346 goto out;
347 }
348
349 /* off[1 & 2] are relative to ph[0]->config_start */
350 ph[0]->config_start = 0;
351
352 /* Read and parse privheads */
353 for (i = 0; i < 3; i++) {
354 data = read_dev_sector (bdev,
355 ph[0]->config_start + off[i], &sect);
356 if (!data) {
357 ldm_crit ("Disk read failed.");
358 goto out;
359 }
360 result = ldm_parse_privhead (data, ph[i]);
361 put_dev_sector (sect);
362 if (!result) {
363 ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */
364 if (i < 2)
365 goto out; /* Already logged */
366 else
367 break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */
368 }
369 }
370
371 num_sects = bdev->bd_inode->i_size >> 9;
372
373 if ((ph[0]->config_start > num_sects) ||
374 ((ph[0]->config_start + ph[0]->config_size) > num_sects)) {
375 ldm_crit ("Database extends beyond the end of the disk.");
376 goto out;
377 }
378
379 if ((ph[0]->logical_disk_start > ph[0]->config_start) ||
380 ((ph[0]->logical_disk_start + ph[0]->logical_disk_size)
381 > ph[0]->config_start)) {
382 ldm_crit ("Disk and database overlap.");
383 goto out;
384 }
385
386 if (!ldm_compare_privheads (ph[0], ph[1])) {
387 ldm_crit ("Primary and backup PRIVHEADs don't match.");
388 goto out;
389 }
390 /* FIXME ignore this for now
391 if (!ldm_compare_privheads (ph[0], ph[2])) {
392 ldm_crit ("Primary and backup PRIVHEADs don't match.");
393 goto out;
394 }*/
395 ldm_debug ("Validated PRIVHEADs successfully.");
396 result = TRUE;
397out:
398 kfree (ph[1]);
399 kfree (ph[2]);
400 return result;
401}
402
403/**
404 * ldm_validate_tocblocks - Validate the table of contents and its backups
405 * @bdev: Device holding the LDM Database
406 * @base: Offset, into @bdev, of the database
407 * @ldb: Cache of the database structures
408 *
409 * Find and compare the four tables of contents of the LDM Database stored on
410 * @bdev and return the parsed information into @toc1.
411 *
412 * The offsets and sizes of the configs are range-checked against a privhead.
413 *
414 * Return: TRUE @toc1 contains validated TOCBLOCK info
415 * FALSE @toc1 contents are undefined
416 */
417static BOOL ldm_validate_tocblocks (struct block_device *bdev,
418 unsigned long base, struct ldmdb *ldb)
419{
420 static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
421 struct tocblock *tb[4];
422 struct privhead *ph;
423 Sector sect;
424 u8 *data;
425 BOOL result = FALSE;
426 int i;
427
428 BUG_ON (!bdev || !ldb);
429
430 ph = &ldb->ph;
431 tb[0] = &ldb->toc;
432 tb[1] = kmalloc (sizeof (*tb[1]), GFP_KERNEL);
433 tb[2] = kmalloc (sizeof (*tb[2]), GFP_KERNEL);
434 tb[3] = kmalloc (sizeof (*tb[3]), GFP_KERNEL);
435 if (!tb[1] || !tb[2] || !tb[3]) {
436 ldm_crit ("Out of memory.");
437 goto out;
438 }
439
440 for (i = 0; i < 4; i++) /* Read and parse all four toc's. */
441 {
442 data = read_dev_sector (bdev, base + off[i], &sect);
443 if (!data) {
444 ldm_crit ("Disk read failed.");
445 goto out;
446 }
447 result = ldm_parse_tocblock (data, tb[i]);
448 put_dev_sector (sect);
449 if (!result)
450 goto out; /* Already logged */
451 }
452
453 /* Range check the toc against a privhead. */
454 if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
455 ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > ph->config_size)) {
456 ldm_crit ("The bitmaps are out of range. Giving up.");
457 goto out;
458 }
459
460 if (!ldm_compare_tocblocks (tb[0], tb[1]) || /* Compare all tocs. */
461 !ldm_compare_tocblocks (tb[0], tb[2]) ||
462 !ldm_compare_tocblocks (tb[0], tb[3])) {
463 ldm_crit ("The TOCBLOCKs don't match.");
464 goto out;
465 }
466
467 ldm_debug ("Validated TOCBLOCKs successfully.");
468 result = TRUE;
469out:
470 kfree (tb[1]);
471 kfree (tb[2]);
472 kfree (tb[3]);
473 return result;
474}
475
476/**
477 * ldm_validate_vmdb - Read the VMDB and validate it
478 * @bdev: Device holding the LDM Database
479 * @base: Offset, into @bdev, of the database
480 * @ldb: Cache of the database structures
481 *
482 * Find the vmdb of the LDM Database stored on @bdev and return the parsed
483 * information in @ldb.
484 *
485 * Return: TRUE @ldb contains validated VBDB info
486 * FALSE @ldb contents are undefined
487 */
488static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
489 struct ldmdb *ldb)
490{
491 Sector sect;
492 u8 *data;
493 BOOL result = FALSE;
494 struct vmdb *vm;
495 struct tocblock *toc;
496
497 BUG_ON (!bdev || !ldb);
498
499 vm = &ldb->vm;
500 toc = &ldb->toc;
501
502 data = read_dev_sector (bdev, base + OFF_VMDB, &sect);
503 if (!data) {
504 ldm_crit ("Disk read failed.");
505 return FALSE;
506 }
507
508 if (!ldm_parse_vmdb (data, vm))
509 goto out; /* Already logged */
510
511 /* Are there uncommitted transactions? */
512 if (BE16(data + 0x10) != 0x01) {
513 ldm_crit ("Database is not in a consistent state. Aborting.");
514 goto out;
515 }
516
517 if (vm->vblk_offset != 512)
518 ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
519
520 /*
521 * The last_vblkd_seq can be before the end of the vmdb, just make sure
522 * it is not out of bounds.
523 */
524 if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) {
525 ldm_crit ("VMDB exceeds allowed size specified by TOCBLOCK. "
526 "Database is corrupt. Aborting.");
527 goto out;
528 }
529
530 result = TRUE;
531out:
532 put_dev_sector (sect);
533 return result;
534}
535
536
537/**
538 * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk
539 * @bdev: Device holding the LDM Database
540 *
541 * This function provides a weak test to decide whether the device is a dynamic
542 * disk or not. It looks for an MS-DOS-style partition table containing at
543 * least one partition of type 0x42 (formerly SFS, now used by Windows for
544 * dynamic disks).
545 *
546 * N.B. The only possible error can come from the read_dev_sector and that is
547 * only likely to happen if the underlying device is strange. If that IS
548 * the case we should return zero to let someone else try.
549 *
550 * Return: TRUE @bdev is a dynamic disk
551 * FALSE @bdev is not a dynamic disk, or an error occurred
552 */
553static BOOL ldm_validate_partition_table (struct block_device *bdev)
554{
555 Sector sect;
556 u8 *data;
557 struct partition *p;
558 int i;
559 BOOL result = FALSE;
560
561 BUG_ON (!bdev);
562
563 data = read_dev_sector (bdev, 0, &sect);
564 if (!data) {
565 ldm_crit ("Disk read failed.");
566 return FALSE;
567 }
568
569 if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
570 goto out;
571
572 p = (struct partition*)(data + 0x01BE);
573 for (i = 0; i < 4; i++, p++)
574 if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) {
575 result = TRUE;
576 break;
577 }
578
579 if (result)
580 ldm_debug ("Found W2K dynamic disk partition type.");
581
582out:
583 put_dev_sector (sect);
584 return result;
585}
586
587/**
588 * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id
589 * @ldb: Cache of the database structures
590 *
591 * The LDM Database contains a list of all partitions on all dynamic disks.
592 * The primary PRIVHEAD, at the beginning of the physical disk, tells us
593 * the GUID of this disk. This function searches for the GUID in a linked
594 * list of vblk's.
595 *
596 * Return: Pointer, A matching vblk was found
597 * NULL, No match, or an error
598 */
599static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
600{
601 struct list_head *item;
602
603 BUG_ON (!ldb);
604
605 list_for_each (item, &ldb->v_disk) {
606 struct vblk *v = list_entry (item, struct vblk, list);
607 if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
608 return v;
609 }
610
611 return NULL;
612}
613
614/**
615 * ldm_create_data_partitions - Create data partitions for this device
616 * @pp: List of the partitions parsed so far
617 * @ldb: Cache of the database structures
618 *
619 * The database contains ALL the partitions for ALL disk groups, so we need to
620 * filter out this specific disk. Using the disk's object id, we can find all
621 * the partitions in the database that belong to this disk.
622 *
623 * Add each partition in our database, to the parsed_partitions structure.
624 *
625 * N.B. This function creates the partitions in the order it finds partition
626 * objects in the linked list.
627 *
628 * Return: TRUE Partition created
629 * FALSE Error, probably a range checking problem
630 */
631static BOOL ldm_create_data_partitions (struct parsed_partitions *pp,
632 const struct ldmdb *ldb)
633{
634 struct list_head *item;
635 struct vblk *vb;
636 struct vblk *disk;
637 struct vblk_part *part;
638 int part_num = 1;
639
640 BUG_ON (!pp || !ldb);
641
642 disk = ldm_get_disk_objid (ldb);
643 if (!disk) {
644 ldm_crit ("Can't find the ID of this disk in the database.");
645 return FALSE;
646 }
647
648 printk (" [LDM]");
649
650 /* Create the data partitions */
651 list_for_each (item, &ldb->v_part) {
652 vb = list_entry (item, struct vblk, list);
653 part = &vb->vblk.part;
654
655 if (part->disk_id != disk->obj_id)
656 continue;
657
658 put_partition (pp, part_num, ldb->ph.logical_disk_start +
659 part->start, part->size);
660 part_num++;
661 }
662
663 printk ("\n");
664 return TRUE;
665}
666
667
668/**
669 * ldm_relative - Calculate the next relative offset
670 * @buffer: Block of data being worked on
671 * @buflen: Size of the block of data
672 * @base: Size of the previous fixed width fields
673 * @offset: Cumulative size of the previous variable-width fields
674 *
675 * Because many of the VBLK fields are variable-width, it's necessary
676 * to calculate each offset based on the previous one and the length
677 * of the field it pointed to.
678 *
679 * Return: -1 Error, the calculated offset exceeded the size of the buffer
680 * n OK, a range-checked offset into buffer
681 */
682static int ldm_relative (const u8 *buffer, int buflen, int base, int offset)
683{
684
685 base += offset;
686 if ((!buffer) || (offset < 0) || (base > buflen))
687 return -1;
688 if ((base + buffer[base]) >= buflen)
689 return -1;
690
691 return buffer[base] + offset + 1;
692}
693
694/**
695 * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order
696 * @block: Pointer to the variable-width number to convert
697 *
698 * Large numbers in the LDM Database are often stored in a packed format. Each
699 * number is prefixed by a one byte width marker. All numbers in the database
700 * are stored in big-endian byte order. This function reads one of these
701 * numbers and returns the result
702 *
703 * N.B. This function DOES NOT perform any range checking, though the most
704 * it will read is eight bytes.
705 *
706 * Return: n A number
707 * 0 Zero, or an error occurred
708 */
709static u64 ldm_get_vnum (const u8 *block)
710{
711 u64 tmp = 0;
712 u8 length;
713
714 BUG_ON (!block);
715
716 length = *block++;
717
718 if (length && length <= 8)
719 while (length--)
720 tmp = (tmp << 8) | *block++;
721 else
722 ldm_error ("Illegal length %d.", length);
723
724 return tmp;
725}
726
727/**
728 * ldm_get_vstr - Read a length-prefixed string into a buffer
729 * @block: Pointer to the length marker
730 * @buffer: Location to copy string to
731 * @buflen: Size of the output buffer
732 *
733 * Many of the strings in the LDM Database are not NULL terminated. Instead
734 * they are prefixed by a one byte length marker. This function copies one of
735 * these strings into a buffer.
736 *
737 * N.B. This function DOES NOT perform any range checking on the input.
738 * If the buffer is too small, the output will be truncated.
739 *
740 * Return: 0, Error and @buffer contents are undefined
741 * n, String length in characters (excluding NULL)
742 * buflen-1, String was truncated.
743 */
744static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
745{
746 int length;
747
748 BUG_ON (!block || !buffer);
749
750 length = block[0];
751 if (length >= buflen) {
752 ldm_error ("Truncating string %d -> %d.", length, buflen);
753 length = buflen - 1;
754 }
755 memcpy (buffer, block + 1, length);
756 buffer[length] = 0;
757 return length;
758}
759
760
761/**
762 * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure
763 * @buffer: Block of data being worked on
764 * @buflen: Size of the block of data
765 * @vb: In-memory vblk in which to return information
766 *
767 * Read a raw VBLK Component object (version 3) into a vblk structure.
768 *
769 * Return: TRUE @vb contains a Component VBLK
770 * FALSE @vb contents are not defined
771 */
772static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
773{
774 int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
775 struct vblk_comp *comp;
776
777 BUG_ON (!buffer || !vb);
778
779 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
780 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
781 r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
782 r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate);
783 r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
784
785 if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
786 r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
787 r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe);
788 len = r_cols;
789 } else {
790 r_stripe = 0;
791 r_cols = 0;
792 len = r_parent;
793 }
794 if (len < 0)
795 return FALSE;
796
797 len += VBLK_SIZE_CMP3;
798 if (len != BE32 (buffer + 0x14))
799 return FALSE;
800
801 comp = &vb->vblk.comp;
802 ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
803 sizeof (comp->state));
804 comp->type = buffer[0x18 + r_vstate];
805 comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate);
806 comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
807 comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
808
809 return TRUE;
810}
811
812/**
813 * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure
814 * @buffer: Block of data being worked on
815 * @buflen: Size of the block of data
816 * @vb: In-memory vblk in which to return information
817 *
818 * Read a raw VBLK Disk Group object (version 3) into a vblk structure.
819 *
820 * Return: TRUE @vb contains a Disk Group VBLK
821 * FALSE @vb contents are not defined
822 */
823static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
824{
825 int r_objid, r_name, r_diskid, r_id1, r_id2, len;
826 struct vblk_dgrp *dgrp;
827
828 BUG_ON (!buffer || !vb);
829
830 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
831 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
832 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
833
834 if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
835 r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
836 r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
837 len = r_id2;
838 } else {
839 r_id1 = 0;
840 r_id2 = 0;
841 len = r_diskid;
842 }
843 if (len < 0)
844 return FALSE;
845
846 len += VBLK_SIZE_DGR3;
847 if (len != BE32 (buffer + 0x14))
848 return FALSE;
849
850 dgrp = &vb->vblk.dgrp;
851 ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
852 sizeof (dgrp->disk_id));
853 return TRUE;
854}
855
856/**
857 * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure
858 * @buffer: Block of data being worked on
859 * @buflen: Size of the block of data
860 * @vb: In-memory vblk in which to return information
861 *
862 * Read a raw VBLK Disk Group object (version 4) into a vblk structure.
863 *
864 * Return: TRUE @vb contains a Disk Group VBLK
865 * FALSE @vb contents are not defined
866 */
867static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
868{
869 char buf[64];
870 int r_objid, r_name, r_id1, r_id2, len;
871 struct vblk_dgrp *dgrp;
872
873 BUG_ON (!buffer || !vb);
874
875 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
876 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
877
878 if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
879 r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
880 r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
881 len = r_id2;
882 } else {
883 r_id1 = 0;
884 r_id2 = 0;
885 len = r_name;
886 }
887 if (len < 0)
888 return FALSE;
889
890 len += VBLK_SIZE_DGR4;
891 if (len != BE32 (buffer + 0x14))
892 return FALSE;
893
894 dgrp = &vb->vblk.dgrp;
895
896 ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
897 return TRUE;
898}
899
900/**
901 * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure
902 * @buffer: Block of data being worked on
903 * @buflen: Size of the block of data
904 * @vb: In-memory vblk in which to return information
905 *
906 * Read a raw VBLK Disk object (version 3) into a vblk structure.
907 *
908 * Return: TRUE @vb contains a Disk VBLK
909 * FALSE @vb contents are not defined
910 */
911static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
912{
913 int r_objid, r_name, r_diskid, r_altname, len;
914 struct vblk_disk *disk;
915
916 BUG_ON (!buffer || !vb);
917
918 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
919 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
920 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
921 r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
922 len = r_altname;
923 if (len < 0)
924 return FALSE;
925
926 len += VBLK_SIZE_DSK3;
927 if (len != BE32 (buffer + 0x14))
928 return FALSE;
929
930 disk = &vb->vblk.disk;
931 ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
932 sizeof (disk->alt_name));
933 if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
934 return FALSE;
935
936 return TRUE;
937}
938
939/**
940 * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure
941 * @buffer: Block of data being worked on
942 * @buflen: Size of the block of data
943 * @vb: In-memory vblk in which to return information
944 *
945 * Read a raw VBLK Disk object (version 4) into a vblk structure.
946 *
947 * Return: TRUE @vb contains a Disk VBLK
948 * FALSE @vb contents are not defined
949 */
950static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
951{
952 int r_objid, r_name, len;
953 struct vblk_disk *disk;
954
955 BUG_ON (!buffer || !vb);
956
957 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
958 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
959 len = r_name;
960 if (len < 0)
961 return FALSE;
962
963 len += VBLK_SIZE_DSK4;
964 if (len != BE32 (buffer + 0x14))
965 return FALSE;
966
967 disk = &vb->vblk.disk;
968 memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
969 return TRUE;
970}
971
972/**
973 * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure
974 * @buffer: Block of data being worked on
975 * @buflen: Size of the block of data
976 * @vb: In-memory vblk in which to return information
977 *
978 * Read a raw VBLK Partition object (version 3) into a vblk structure.
979 *
980 * Return: TRUE @vb contains a Partition VBLK
981 * FALSE @vb contents are not defined
982 */
983static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
984{
985 int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
986 struct vblk_part *part;
987
988 BUG_ON (!buffer || !vb);
989
990 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
991 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
992 r_size = ldm_relative (buffer, buflen, 0x34, r_name);
993 r_parent = ldm_relative (buffer, buflen, 0x34, r_size);
994 r_diskid = ldm_relative (buffer, buflen, 0x34, r_parent);
995
996 if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
997 r_index = ldm_relative (buffer, buflen, 0x34, r_diskid);
998 len = r_index;
999 } else {
1000 r_index = 0;
1001 len = r_diskid;
1002 }
1003 if (len < 0)
1004 return FALSE;
1005
1006 len += VBLK_SIZE_PRT3;
1007 if (len != BE32 (buffer + 0x14))
1008 return FALSE;
1009
1010 part = &vb->vblk.part;
1011 part->start = BE64 (buffer + 0x24 + r_name);
1012 part->volume_offset = BE64 (buffer + 0x2C + r_name);
1013 part->size = ldm_get_vnum (buffer + 0x34 + r_name);
1014 part->parent_id = ldm_get_vnum (buffer + 0x34 + r_size);
1015 part->disk_id = ldm_get_vnum (buffer + 0x34 + r_parent);
1016 if (vb->flags & VBLK_FLAG_PART_INDEX)
1017 part->partnum = buffer[0x35 + r_diskid];
1018 else
1019 part->partnum = 0;
1020
1021 return TRUE;
1022}
1023
1024/**
1025 * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure
1026 * @buffer: Block of data being worked on
1027 * @buflen: Size of the block of data
1028 * @vb: In-memory vblk in which to return information
1029 *
1030 * Read a raw VBLK Volume object (version 5) into a vblk structure.
1031 *
1032 * Return: TRUE @vb contains a Volume VBLK
1033 * FALSE @vb contents are not defined
1034 */
1035static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
1036{
1037 int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2;
1038 int r_drive, len;
1039 struct vblk_volu *volu;
1040
1041 BUG_ON (!buffer || !vb);
1042
1043 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
1044 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
1045 r_vtype = ldm_relative (buffer, buflen, 0x18, r_name);
1046 r_child = ldm_relative (buffer, buflen, 0x2E, r_vtype);
1047 r_size = ldm_relative (buffer, buflen, 0x3E, r_child);
1048
1049 if (buffer[0x12] & VBLK_FLAG_VOLU_ID1)
1050 r_id1 = ldm_relative (buffer, buflen, 0x53, r_size);
1051 else
1052 r_id1 = r_size;
1053
1054 if (buffer[0x12] & VBLK_FLAG_VOLU_ID2)
1055 r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1);
1056 else
1057 r_id2 = r_id1;
1058
1059 if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE)
1060 r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2);
1061 else
1062 r_size2 = r_id2;
1063
1064 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE)
1065 r_drive = ldm_relative (buffer, buflen, 0x53, r_size2);
1066 else
1067 r_drive = r_size2;
1068
1069 len = r_drive;
1070 if (len < 0)
1071 return FALSE;
1072
1073 len += VBLK_SIZE_VOL5;
1074 if (len != BE32 (buffer + 0x14))
1075 return FALSE;
1076
1077 volu = &vb->vblk.volu;
1078
1079 ldm_get_vstr (buffer + 0x18 + r_name, volu->volume_type,
1080 sizeof (volu->volume_type));
1081 memcpy (volu->volume_state, buffer + 0x19 + r_vtype,
1082 sizeof (volu->volume_state));
1083 volu->size = ldm_get_vnum (buffer + 0x3E + r_child);
1084 volu->partition_type = buffer[0x42 + r_size];
1085 memcpy (volu->guid, buffer + 0x43 + r_size, sizeof (volu->guid));
1086 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1087 ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint,
1088 sizeof (volu->drive_hint));
1089 }
1090 return TRUE;
1091}
1092
1093/**
1094 * ldm_parse_vblk - Read a raw VBLK object into a vblk structure
1095 * @buf: Block of data being worked on
1096 * @len: Size of the block of data
1097 * @vb: In-memory vblk in which to return information
1098 *
1099 * Read a raw VBLK object into a vblk structure. This function just reads the
1100 * information common to all VBLK types, then delegates the rest of the work to
1101 * helper functions: ldm_parse_*.
1102 *
1103 * Return: TRUE @vb contains a VBLK
1104 * FALSE @vb contents are not defined
1105 */
1106static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
1107{
1108 BOOL result = FALSE;
1109 int r_objid;
1110
1111 BUG_ON (!buf || !vb);
1112
1113 r_objid = ldm_relative (buf, len, 0x18, 0);
1114 if (r_objid < 0) {
1115 ldm_error ("VBLK header is corrupt.");
1116 return FALSE;
1117 }
1118
1119 vb->flags = buf[0x12];
1120 vb->type = buf[0x13];
1121 vb->obj_id = ldm_get_vnum (buf + 0x18);
1122 ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
1123
1124 switch (vb->type) {
1125 case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break;
1126 case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break;
1127 case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break;
1128 case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break;
1129 case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break;
1130 case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break;
1131 case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break;
1132 }
1133
1134 if (result)
1135 ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
1136 (unsigned long long) vb->obj_id, vb->type);
1137 else
1138 ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
1139 (unsigned long long) vb->obj_id, vb->type);
1140
1141 return result;
1142}
1143
1144
1145/**
1146 * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database
1147 * @data: Raw VBLK to add to the database
1148 * @len: Size of the raw VBLK
1149 * @ldb: Cache of the database structures
1150 *
1151 * The VBLKs are sorted into categories. Partitions are also sorted by offset.
1152 *
1153 * N.B. This function does not check the validity of the VBLKs.
1154 *
1155 * Return: TRUE The VBLK was added
1156 * FALSE An error occurred
1157 */
1158static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
1159{
1160 struct vblk *vb;
1161 struct list_head *item;
1162
1163 BUG_ON (!data || !ldb);
1164
1165 vb = kmalloc (sizeof (*vb), GFP_KERNEL);
1166 if (!vb) {
1167 ldm_crit ("Out of memory.");
1168 return FALSE;
1169 }
1170
1171 if (!ldm_parse_vblk (data, len, vb)) {
1172 kfree(vb);
1173 return FALSE; /* Already logged */
1174 }
1175
1176 /* Put vblk into the correct list. */
1177 switch (vb->type) {
1178 case VBLK_DGR3:
1179 case VBLK_DGR4:
1180 list_add (&vb->list, &ldb->v_dgrp);
1181 break;
1182 case VBLK_DSK3:
1183 case VBLK_DSK4:
1184 list_add (&vb->list, &ldb->v_disk);
1185 break;
1186 case VBLK_VOL5:
1187 list_add (&vb->list, &ldb->v_volu);
1188 break;
1189 case VBLK_CMP3:
1190 list_add (&vb->list, &ldb->v_comp);
1191 break;
1192 case VBLK_PRT3:
1193 /* Sort by the partition's start sector. */
1194 list_for_each (item, &ldb->v_part) {
1195 struct vblk *v = list_entry (item, struct vblk, list);
1196 if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
1197 (v->vblk.part.start > vb->vblk.part.start)) {
1198 list_add_tail (&vb->list, &v->list);
1199 return TRUE;
1200 }
1201 }
1202 list_add_tail (&vb->list, &ldb->v_part);
1203 break;
1204 }
1205 return TRUE;
1206}
1207
1208/**
1209 * ldm_frag_add - Add a VBLK fragment to a list
1210 * @data: Raw fragment to be added to the list
1211 * @size: Size of the raw fragment
1212 * @frags: Linked list of VBLK fragments
1213 *
1214 * Fragmented VBLKs may not be consecutive in the database, so they are placed
1215 * in a list so they can be pieced together later.
1216 *
1217 * Return: TRUE Success, the VBLK was added to the list
1218 * FALSE Error, a problem occurred
1219 */
1220static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
1221{
1222 struct frag *f;
1223 struct list_head *item;
1224 int rec, num, group;
1225
1226 BUG_ON (!data || !frags);
1227
1228 group = BE32 (data + 0x08);
1229 rec = BE16 (data + 0x0C);
1230 num = BE16 (data + 0x0E);
1231 if ((num < 1) || (num > 4)) {
1232 ldm_error ("A VBLK claims to have %d parts.", num);
1233 return FALSE;
1234 }
1235
1236 list_for_each (item, frags) {
1237 f = list_entry (item, struct frag, list);
1238 if (f->group == group)
1239 goto found;
1240 }
1241
1242 f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
1243 if (!f) {
1244 ldm_crit ("Out of memory.");
1245 return FALSE;
1246 }
1247
1248 f->group = group;
1249 f->num = num;
1250 f->rec = rec;
1251 f->map = 0xFF << num;
1252
1253 list_add_tail (&f->list, frags);
1254found:
1255 if (f->map & (1 << rec)) {
1256 ldm_error ("Duplicate VBLK, part %d.", rec);
1257 f->map &= 0x7F; /* Mark the group as broken */
1258 return FALSE;
1259 }
1260
1261 f->map |= (1 << rec);
1262
1263 if (num > 0) {
1264 data += VBLK_SIZE_HEAD;
1265 size -= VBLK_SIZE_HEAD;
1266 }
1267 memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
1268
1269 return TRUE;
1270}
1271
1272/**
1273 * ldm_frag_free - Free a linked list of VBLK fragments
1274 * @list: Linked list of fragments
1275 *
1276 * Free a linked list of VBLK fragments
1277 *
1278 * Return: none
1279 */
1280static void ldm_frag_free (struct list_head *list)
1281{
1282 struct list_head *item, *tmp;
1283
1284 BUG_ON (!list);
1285
1286 list_for_each_safe (item, tmp, list)
1287 kfree (list_entry (item, struct frag, list));
1288}
1289
1290/**
1291 * ldm_frag_commit - Validate fragmented VBLKs and add them to the database
1292 * @frags: Linked list of VBLK fragments
1293 * @ldb: Cache of the database structures
1294 *
1295 * Now that all the fragmented VBLKs have been collected, they must be added to
1296 * the database for later use.
1297 *
1298 * Return: TRUE All the fragments we added successfully
1299 * FALSE One or more of the fragments we invalid
1300 */
1301static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
1302{
1303 struct frag *f;
1304 struct list_head *item;
1305
1306 BUG_ON (!frags || !ldb);
1307
1308 list_for_each (item, frags) {
1309 f = list_entry (item, struct frag, list);
1310
1311 if (f->map != 0xFF) {
1312 ldm_error ("VBLK group %d is incomplete (0x%02x).",
1313 f->group, f->map);
1314 return FALSE;
1315 }
1316
1317 if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
1318 return FALSE; /* Already logged */
1319 }
1320 return TRUE;
1321}
1322
1323/**
1324 * ldm_get_vblks - Read the on-disk database of VBLKs into memory
1325 * @bdev: Device holding the LDM Database
1326 * @base: Offset, into @bdev, of the database
1327 * @ldb: Cache of the database structures
1328 *
1329 * To use the information from the VBLKs, they need to be read from the disk,
1330 * unpacked and validated. We cache them in @ldb according to their type.
1331 *
1332 * Return: TRUE All the VBLKs were read successfully
1333 * FALSE An error occurred
1334 */
1335static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base,
1336 struct ldmdb *ldb)
1337{
1338 int size, perbuf, skip, finish, s, v, recs;
1339 u8 *data = NULL;
1340 Sector sect;
1341 BOOL result = FALSE;
1342 LIST_HEAD (frags);
1343
1344 BUG_ON (!bdev || !ldb);
1345
1346 size = ldb->vm.vblk_size;
1347 perbuf = 512 / size;
1348 skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */
1349 finish = (size * ldb->vm.last_vblk_seq) >> 9;
1350
1351 for (s = skip; s < finish; s++) { /* For each sector */
1352 data = read_dev_sector (bdev, base + OFF_VMDB + s, &sect);
1353 if (!data) {
1354 ldm_crit ("Disk read failed.");
1355 goto out;
1356 }
1357
1358 for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */
1359 if (MAGIC_VBLK != BE32 (data)) {
1360 ldm_error ("Expected to find a VBLK.");
1361 goto out;
1362 }
1363
1364 recs = BE16 (data + 0x0E); /* Number of records */
1365 if (recs == 1) {
1366 if (!ldm_ldmdb_add (data, size, ldb))
1367 goto out; /* Already logged */
1368 } else if (recs > 1) {
1369 if (!ldm_frag_add (data, size, &frags))
1370 goto out; /* Already logged */
1371 }
1372 /* else Record is not in use, ignore it. */
1373 }
1374 put_dev_sector (sect);
1375 data = NULL;
1376 }
1377
1378 result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */
1379out:
1380 if (data)
1381 put_dev_sector (sect);
1382 ldm_frag_free (&frags);
1383
1384 return result;
1385}
1386
1387/**
1388 * ldm_free_vblks - Free a linked list of vblk's
1389 * @lh: Head of a linked list of struct vblk
1390 *
1391 * Free a list of vblk's and free the memory used to maintain the list.
1392 *
1393 * Return: none
1394 */
1395static void ldm_free_vblks (struct list_head *lh)
1396{
1397 struct list_head *item, *tmp;
1398
1399 BUG_ON (!lh);
1400
1401 list_for_each_safe (item, tmp, lh)
1402 kfree (list_entry (item, struct vblk, list));
1403}
1404
1405
1406/**
1407 * ldm_partition - Find out whether a device is a dynamic disk and handle it
1408 * @pp: List of the partitions parsed so far
1409 * @bdev: Device holding the LDM Database
1410 *
1411 * This determines whether the device @bdev is a dynamic disk and if so creates
1412 * the partitions necessary in the gendisk structure pointed to by @hd.
1413 *
1414 * We create a dummy device 1, which contains the LDM database, and then create
1415 * each partition described by the LDM database in sequence as devices 2+. For
1416 * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3,
1417 * and so on: the actual data containing partitions.
1418 *
1419 * Return: 1 Success, @bdev is a dynamic disk and we handled it
1420 * 0 Success, @bdev is not a dynamic disk
1421 * -1 An error occurred before enough information had been read
1422 * Or @bdev is a dynamic disk, but it may be corrupted
1423 */
1424int ldm_partition (struct parsed_partitions *pp, struct block_device *bdev)
1425{
1426 struct ldmdb *ldb;
1427 unsigned long base;
1428 int result = -1;
1429
1430 BUG_ON (!pp || !bdev);
1431
1432 /* Look for signs of a Dynamic Disk */
1433 if (!ldm_validate_partition_table (bdev))
1434 return 0;
1435
1436 ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
1437 if (!ldb) {
1438 ldm_crit ("Out of memory.");
1439 goto out;
1440 }
1441
1442 /* Parse and check privheads. */
1443 if (!ldm_validate_privheads (bdev, &ldb->ph))
1444 goto out; /* Already logged */
1445
1446 /* All further references are relative to base (database start). */
1447 base = ldb->ph.config_start;
1448
1449 /* Parse and check tocs and vmdb. */
1450 if (!ldm_validate_tocblocks (bdev, base, ldb) ||
1451 !ldm_validate_vmdb (bdev, base, ldb))
1452 goto out; /* Already logged */
1453
1454 /* Initialize vblk lists in ldmdb struct */
1455 INIT_LIST_HEAD (&ldb->v_dgrp);
1456 INIT_LIST_HEAD (&ldb->v_disk);
1457 INIT_LIST_HEAD (&ldb->v_volu);
1458 INIT_LIST_HEAD (&ldb->v_comp);
1459 INIT_LIST_HEAD (&ldb->v_part);
1460
1461 if (!ldm_get_vblks (bdev, base, ldb)) {
1462 ldm_crit ("Failed to read the VBLKs from the database.");
1463 goto cleanup;
1464 }
1465
1466 /* Finally, create the data partition devices. */
1467 if (ldm_create_data_partitions (pp, ldb)) {
1468 ldm_debug ("Parsed LDM database successfully.");
1469 result = 1;
1470 }
1471 /* else Already logged */
1472
1473cleanup:
1474 ldm_free_vblks (&ldb->v_dgrp);
1475 ldm_free_vblks (&ldb->v_disk);
1476 ldm_free_vblks (&ldb->v_volu);
1477 ldm_free_vblks (&ldb->v_comp);
1478 ldm_free_vblks (&ldb->v_part);
1479out:
1480 kfree (ldb);
1481 return result;
1482}
1483
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h
new file mode 100644
index 00000000000..6e8d7952b8b
--- /dev/null
+++ b/fs/partitions/ldm.h
@@ -0,0 +1,220 @@
1/**
2 * ldm - Part of the Linux-NTFS project.
3 *
4 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
5 * Copyright (C) 2001 Anton Altaparmakov <aia21@cantab.net>
6 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
7 *
8 * Documentation is available at http://linux-ntfs.sf.net/ldm
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program (in the main directory of the Linux-NTFS source
22 * in the file COPYING); if not, write to the Free Software Foundation,
23 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#ifndef _FS_PT_LDM_H_
27#define _FS_PT_LDM_H_
28
29#include <linux/types.h>
30#include <linux/list.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <asm/unaligned.h>
34#include <asm/byteorder.h>
35
36struct parsed_partitions;
37
38/* Magic numbers in CPU format. */
39#define MAGIC_VMDB 0x564D4442 /* VMDB */
40#define MAGIC_VBLK 0x56424C4B /* VBLK */
41#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */
42#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */
43
44/* The defined vblk types. */
45#define VBLK_VOL5 0x51 /* Volume, version 5 */
46#define VBLK_CMP3 0x32 /* Component, version 3 */
47#define VBLK_PRT3 0x33 /* Partition, version 3 */
48#define VBLK_DSK3 0x34 /* Disk, version 3 */
49#define VBLK_DSK4 0x44 /* Disk, version 4 */
50#define VBLK_DGR3 0x35 /* Disk Group, version 3 */
51#define VBLK_DGR4 0x45 /* Disk Group, version 4 */
52
53/* vblk flags indicating extra information will be present */
54#define VBLK_FLAG_COMP_STRIPE 0x10
55#define VBLK_FLAG_PART_INDEX 0x08
56#define VBLK_FLAG_DGR3_IDS 0x08
57#define VBLK_FLAG_DGR4_IDS 0x08
58#define VBLK_FLAG_VOLU_ID1 0x08
59#define VBLK_FLAG_VOLU_ID2 0x20
60#define VBLK_FLAG_VOLU_SIZE 0x80
61#define VBLK_FLAG_VOLU_DRIVE 0x02
62
63/* size of a vblk's static parts */
64#define VBLK_SIZE_HEAD 16
65#define VBLK_SIZE_CMP3 22 /* Name and version */
66#define VBLK_SIZE_DGR3 12
67#define VBLK_SIZE_DGR4 44
68#define VBLK_SIZE_DSK3 12
69#define VBLK_SIZE_DSK4 45
70#define VBLK_SIZE_PRT3 28
71#define VBLK_SIZE_VOL5 59
72
73/* component types */
74#define COMP_STRIPE 0x01 /* Stripe-set */
75#define COMP_BASIC 0x02 /* Basic disk */
76#define COMP_RAID 0x03 /* Raid-set */
77
78/* Other constants. */
79#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */
80
81#define OFF_PRIV1 6 /* Offset of the first privhead
82 relative to the start of the
83 device in sectors */
84
85/* Offsets to structures within the LDM Database in sectors. */
86#define OFF_PRIV2 1856 /* Backup private headers. */
87#define OFF_PRIV3 2047
88
89#define OFF_TOCB1 1 /* Tables of contents. */
90#define OFF_TOCB2 2
91#define OFF_TOCB3 2045
92#define OFF_TOCB4 2046
93
94#define OFF_VMDB 17 /* List of partitions. */
95
96#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */
97
98#define TOC_BITMAP1 "config" /* Names of the two defined */
99#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
100
101/* Most numbers we deal with are big-endian and won't be aligned. */
102#define BE16(x) ((u16)be16_to_cpu(get_unaligned((__be16*)(x))))
103#define BE32(x) ((u32)be32_to_cpu(get_unaligned((__be32*)(x))))
104#define BE64(x) ((u64)be64_to_cpu(get_unaligned((__be64*)(x))))
105
106/* Borrowed from msdos.c */
107#define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
108
109struct frag { /* VBLK Fragment handling */
110 struct list_head list;
111 u32 group;
112 u8 num; /* Total number of records */
113 u8 rec; /* This is record number n */
114 u8 map; /* Which portions are in use */
115 u8 data[0];
116};
117
118/* In memory LDM database structures. */
119
120#define GUID_SIZE 16
121
122struct privhead { /* Offsets and sizes are in sectors. */
123 u16 ver_major;
124 u16 ver_minor;
125 u64 logical_disk_start;
126 u64 logical_disk_size;
127 u64 config_start;
128 u64 config_size;
129 u8 disk_id[GUID_SIZE];
130};
131
132struct tocblock { /* We have exactly two bitmaps. */
133 u8 bitmap1_name[16];
134 u64 bitmap1_start;
135 u64 bitmap1_size;
136 u8 bitmap2_name[16];
137 u64 bitmap2_start;
138 u64 bitmap2_size;
139};
140
141struct vmdb { /* VMDB: The database header */
142 u16 ver_major;
143 u16 ver_minor;
144 u32 vblk_size;
145 u32 vblk_offset;
146 u32 last_vblk_seq;
147};
148
149struct vblk_comp { /* VBLK Component */
150 u8 state[16];
151 u64 parent_id;
152 u8 type;
153 u8 children;
154 u16 chunksize;
155};
156
157struct vblk_dgrp { /* VBLK Disk Group */
158 u8 disk_id[64];
159};
160
161struct vblk_disk { /* VBLK Disk */
162 u8 disk_id[GUID_SIZE];
163 u8 alt_name[128];
164};
165
166struct vblk_part { /* VBLK Partition */
167 u64 start;
168 u64 size; /* start, size and vol_off in sectors */
169 u64 volume_offset;
170 u64 parent_id;
171 u64 disk_id;
172 u8 partnum;
173};
174
175struct vblk_volu { /* VBLK Volume */
176 u8 volume_type[16];
177 u8 volume_state[16];
178 u8 guid[16];
179 u8 drive_hint[4];
180 u64 size;
181 u8 partition_type;
182};
183
184struct vblk_head { /* VBLK standard header */
185 u32 group;
186 u16 rec;
187 u16 nrec;
188};
189
190struct vblk { /* Generalised VBLK */
191 u8 name[64];
192 u64 obj_id;
193 u32 sequence;
194 u8 flags;
195 u8 type;
196 union {
197 struct vblk_comp comp;
198 struct vblk_dgrp dgrp;
199 struct vblk_disk disk;
200 struct vblk_part part;
201 struct vblk_volu volu;
202 } vblk;
203 struct list_head list;
204};
205
206struct ldmdb { /* Cache of the database */
207 struct privhead ph;
208 struct tocblock toc;
209 struct vmdb vm;
210 struct list_head v_dgrp;
211 struct list_head v_disk;
212 struct list_head v_volu;
213 struct list_head v_comp;
214 struct list_head v_part;
215};
216
217int ldm_partition (struct parsed_partitions *state, struct block_device *bdev);
218
219#endif /* _FS_PT_LDM_H_ */
220
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
new file mode 100644
index 00000000000..bb22cdd0cb1
--- /dev/null
+++ b/fs/partitions/mac.c
@@ -0,0 +1,130 @@
1/*
2 * fs/partitions/mac.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
6 * Re-organised Feb 1998 Russell King
7 */
8
9#include <linux/config.h>
10#include <linux/ctype.h>
11#include "check.h"
12#include "mac.h"
13
14#ifdef CONFIG_PPC_PMAC
15extern void note_bootable_part(dev_t dev, int part, int goodness);
16#endif
17
18/*
19 * Code to understand MacOS partition tables.
20 */
21
22static inline void mac_fix_string(char *stg, int len)
23{
24 int i;
25
26 for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
27 stg[i] = 0;
28}
29
30int mac_partition(struct parsed_partitions *state, struct block_device *bdev)
31{
32 int slot = 1;
33 Sector sect;
34 unsigned char *data;
35 int blk, blocks_in_map;
36 unsigned secsize;
37#ifdef CONFIG_PPC_PMAC
38 int found_root = 0;
39 int found_root_goodness = 0;
40#endif
41 struct mac_partition *part;
42 struct mac_driver_desc *md;
43
44 /* Get 0th block and look at the first partition map entry. */
45 md = (struct mac_driver_desc *) read_dev_sector(bdev, 0, &sect);
46 if (!md)
47 return -1;
48 if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
49 put_dev_sector(sect);
50 return 0;
51 }
52 secsize = be16_to_cpu(md->block_size);
53 put_dev_sector(sect);
54 data = read_dev_sector(bdev, secsize/512, &sect);
55 if (!data)
56 return -1;
57 part = (struct mac_partition *) (data + secsize%512);
58 if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
59 put_dev_sector(sect);
60 return 0; /* not a MacOS disk */
61 }
62 printk(" [mac]");
63 blocks_in_map = be32_to_cpu(part->map_count);
64 for (blk = 1; blk <= blocks_in_map; ++blk) {
65 int pos = blk * secsize;
66 put_dev_sector(sect);
67 data = read_dev_sector(bdev, pos/512, &sect);
68 if (!data)
69 return -1;
70 part = (struct mac_partition *) (data + pos%512);
71 if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
72 break;
73 put_partition(state, slot,
74 be32_to_cpu(part->start_block) * (secsize/512),
75 be32_to_cpu(part->block_count) * (secsize/512));
76
77#ifdef CONFIG_PPC_PMAC
78 /*
79 * If this is the first bootable partition, tell the
80 * setup code, in case it wants to make this the root.
81 */
82 if (_machine == _MACH_Pmac) {
83 int goodness = 0;
84
85 mac_fix_string(part->processor, 16);
86 mac_fix_string(part->name, 32);
87 mac_fix_string(part->type, 32);
88
89 if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
90 && strcasecmp(part->processor, "powerpc") == 0)
91 goodness++;
92
93 if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
94 || (strnicmp(part->type, "Linux", 5) == 0
95 && strcasecmp(part->type, "Linux_swap") != 0)) {
96 int i, l;
97
98 goodness++;
99 l = strlen(part->name);
100 if (strcmp(part->name, "/") == 0)
101 goodness++;
102 for (i = 0; i <= l - 4; ++i) {
103 if (strnicmp(part->name + i, "root",
104 4) == 0) {
105 goodness += 2;
106 break;
107 }
108 }
109 if (strnicmp(part->name, "swap", 4) == 0)
110 goodness--;
111 }
112
113 if (goodness > found_root_goodness) {
114 found_root = blk;
115 found_root_goodness = goodness;
116 }
117 }
118#endif /* CONFIG_PPC_PMAC */
119
120 ++slot;
121 }
122#ifdef CONFIG_PPC_PMAC
123 if (found_root_goodness)
124 note_bootable_part(bdev->bd_dev, found_root, found_root_goodness);
125#endif
126
127 put_dev_sector(sect);
128 printk("\n");
129 return 1;
130}
diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h
new file mode 100644
index 00000000000..bbf26e1386f
--- /dev/null
+++ b/fs/partitions/mac.h
@@ -0,0 +1,44 @@
1/*
2 * fs/partitions/mac.h
3 */
4
5#define MAC_PARTITION_MAGIC 0x504d
6
7/* type field value for A/UX or other Unix partitions */
8#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
9
10struct mac_partition {
11 __be16 signature; /* expected to be MAC_PARTITION_MAGIC */
12 __be16 res1;
13 __be32 map_count; /* # blocks in partition map */
14 __be32 start_block; /* absolute starting block # of partition */
15 __be32 block_count; /* number of blocks in partition */
16 char name[32]; /* partition name */
17 char type[32]; /* string type description */
18 __be32 data_start; /* rel block # of first data block */
19 __be32 data_count; /* number of data blocks */
20 __be32 status; /* partition status bits */
21 __be32 boot_start;
22 __be32 boot_size;
23 __be32 boot_load;
24 __be32 boot_load2;
25 __be32 boot_entry;
26 __be32 boot_entry2;
27 __be32 boot_cksum;
28 char processor[16]; /* identifies ISA of boot */
29 /* there is more stuff after this that we don't need */
30};
31
32#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
33
34#define MAC_DRIVER_MAGIC 0x4552
35
36/* Driver descriptor structure, in block 0 */
37struct mac_driver_desc {
38 __be16 signature; /* expected to be MAC_DRIVER_MAGIC */
39 __be16 block_size;
40 __be32 block_count;
41 /* ... more stuff */
42};
43
44int mac_partition(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
new file mode 100644
index 00000000000..17ee1b4ff08
--- /dev/null
+++ b/fs/partitions/msdos.c
@@ -0,0 +1,479 @@
1/*
2 * fs/partitions/msdos.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
6 *
7 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
8 * in the early extended-partition checks and added DM partitions
9 *
10 * Support for DiskManager v6.0x added by Mark Lord,
11 * with information provided by OnTrack. This now works for linux fdisk
12 * and LILO, as well as loadlin and bootln. Note that disks other than
13 * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
14 *
15 * More flexible handling of extended partitions - aeb, 950831
16 *
17 * Check partition table on IDE disks for common CHS translations
18 *
19 * Re-organised Feb 1998 Russell King
20 */
21
22#include <linux/config.h>
23
24#include "check.h"
25#include "msdos.h"
26#include "efi.h"
27
28/*
29 * Many architectures don't like unaligned accesses, while
30 * the nr_sects and start_sect partition table entries are
31 * at a 2 (mod 4) address.
32 */
33#include <asm/unaligned.h>
34
35#define SYS_IND(p) (get_unaligned(&p->sys_ind))
36#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
37 get_unaligned(&p->nr_sects); \
38 le32_to_cpu(__a); \
39 })
40
41#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
42 get_unaligned(&p->start_sect); \
43 le32_to_cpu(__a); \
44 })
45
46static inline int is_extended_partition(struct partition *p)
47{
48 return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
49 SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
50 SYS_IND(p) == LINUX_EXTENDED_PARTITION);
51}
52
53#define MSDOS_LABEL_MAGIC1 0x55
54#define MSDOS_LABEL_MAGIC2 0xAA
55
56static inline int
57msdos_magic_present(unsigned char *p)
58{
59 return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
60}
61
62/*
63 * Create devices for each logical partition in an extended partition.
64 * The logical partitions form a linked list, with each entry being
65 * a partition table with two entries. The first entry
66 * is the real data partition (with a start relative to the partition
67 * table start). The second is a pointer to the next logical partition
68 * (with a start relative to the entire extended partition).
69 * We do not create a Linux partition for the partition tables, but
70 * only for the actual data partitions.
71 */
72
73static void
74parse_extended(struct parsed_partitions *state, struct block_device *bdev,
75 u32 first_sector, u32 first_size)
76{
77 struct partition *p;
78 Sector sect;
79 unsigned char *data;
80 u32 this_sector, this_size;
81 int sector_size = bdev_hardsect_size(bdev) / 512;
82 int loopct = 0; /* number of links followed
83 without finding a data partition */
84 int i;
85
86 this_sector = first_sector;
87 this_size = first_size;
88
89 while (1) {
90 if (++loopct > 100)
91 return;
92 if (state->next == state->limit)
93 return;
94 data = read_dev_sector(bdev, this_sector, &sect);
95 if (!data)
96 return;
97
98 if (!msdos_magic_present(data + 510))
99 goto done;
100
101 p = (struct partition *) (data + 0x1be);
102
103 /*
104 * Usually, the first entry is the real data partition,
105 * the 2nd entry is the next extended partition, or empty,
106 * and the 3rd and 4th entries are unused.
107 * However, DRDOS sometimes has the extended partition as
108 * the first entry (when the data partition is empty),
109 * and OS/2 seems to use all four entries.
110 */
111
112 /*
113 * First process the data partition(s)
114 */
115 for (i=0; i<4; i++, p++) {
116 u32 offs, size, next;
117
118 if (SYS_IND(p) == 0)
119 continue;
120 if (!NR_SECTS(p) || is_extended_partition(p))
121 continue;
122
123 /* Check the 3rd and 4th entries -
124 these sometimes contain random garbage */
125 offs = START_SECT(p)*sector_size;
126 size = NR_SECTS(p)*sector_size;
127 next = this_sector + offs;
128 if (i >= 2) {
129 if (offs + size > this_size)
130 continue;
131 if (next < first_sector)
132 continue;
133 if (next + size > first_sector + first_size)
134 continue;
135 }
136
137 put_partition(state, state->next, next, size);
138 if (SYS_IND(p) == LINUX_RAID_PARTITION)
139 state->parts[state->next].flags = 1;
140 loopct = 0;
141 if (++state->next == state->limit)
142 goto done;
143 }
144 /*
145 * Next, process the (first) extended partition, if present.
146 * (So far, there seems to be no reason to make
147 * parse_extended() recursive and allow a tree
148 * of extended partitions.)
149 * It should be a link to the next logical partition.
150 */
151 p -= 4;
152 for (i=0; i<4; i++, p++)
153 if (NR_SECTS(p) && is_extended_partition(p))
154 break;
155 if (i == 4)
156 goto done; /* nothing left to do */
157
158 this_sector = first_sector + START_SECT(p) * sector_size;
159 this_size = NR_SECTS(p) * sector_size;
160 put_dev_sector(sect);
161 }
162done:
163 put_dev_sector(sect);
164}
165
166/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
167 indicates linux swap. Be careful before believing this is Solaris. */
168
169static void
170parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev,
171 u32 offset, u32 size, int origin)
172{
173#ifdef CONFIG_SOLARIS_X86_PARTITION
174 Sector sect;
175 struct solaris_x86_vtoc *v;
176 int i;
177
178 v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, &sect);
179 if (!v)
180 return;
181 if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
182 put_dev_sector(sect);
183 return;
184 }
185 printk(" %s%d: <solaris:", state->name, origin);
186 if (le32_to_cpu(v->v_version) != 1) {
187 printk(" cannot handle version %d vtoc>\n",
188 le32_to_cpu(v->v_version));
189 put_dev_sector(sect);
190 return;
191 }
192 for (i=0; i<SOLARIS_X86_NUMSLICE && state->next<state->limit; i++) {
193 struct solaris_x86_slice *s = &v->v_slice[i];
194 if (s->s_size == 0)
195 continue;
196 printk(" [s%d]", i);
197 /* solaris partitions are relative to current MS-DOS
198 * one; must add the offset of the current partition */
199 put_partition(state, state->next++,
200 le32_to_cpu(s->s_start)+offset,
201 le32_to_cpu(s->s_size));
202 }
203 put_dev_sector(sect);
204 printk(" >\n");
205#endif
206}
207
208#if defined(CONFIG_BSD_DISKLABEL) || defined(CONFIG_NEC98_PARTITION)
209/*
210 * Create devices for BSD partitions listed in a disklabel, under a
211 * dos-like partition. See parse_extended() for more information.
212 */
213void
214parse_bsd(struct parsed_partitions *state, struct block_device *bdev,
215 u32 offset, u32 size, int origin, char *flavour,
216 int max_partitions)
217{
218 Sector sect;
219 struct bsd_disklabel *l;
220 struct bsd_partition *p;
221
222 l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, &sect);
223 if (!l)
224 return;
225 if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
226 put_dev_sector(sect);
227 return;
228 }
229 printk(" %s%d: <%s:", state->name, origin, flavour);
230
231 if (le16_to_cpu(l->d_npartitions) < max_partitions)
232 max_partitions = le16_to_cpu(l->d_npartitions);
233 for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
234 u32 bsd_start, bsd_size;
235
236 if (state->next == state->limit)
237 break;
238 if (p->p_fstype == BSD_FS_UNUSED)
239 continue;
240 bsd_start = le32_to_cpu(p->p_offset);
241 bsd_size = le32_to_cpu(p->p_size);
242 if (offset == bsd_start && size == bsd_size)
243 /* full parent partition, we have it already */
244 continue;
245 if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
246 printk("bad subpartition - ignored\n");
247 continue;
248 }
249 put_partition(state, state->next++, bsd_start, bsd_size);
250 }
251 put_dev_sector(sect);
252 if (le16_to_cpu(l->d_npartitions) > max_partitions)
253 printk(" (ignored %d more)",
254 le16_to_cpu(l->d_npartitions) - max_partitions);
255 printk(" >\n");
256}
257#endif
258
259static void
260parse_freebsd(struct parsed_partitions *state, struct block_device *bdev,
261 u32 offset, u32 size, int origin)
262{
263#ifdef CONFIG_BSD_DISKLABEL
264 parse_bsd(state, bdev, offset, size, origin,
265 "bsd", BSD_MAXPARTITIONS);
266#endif
267}
268
269static void
270parse_netbsd(struct parsed_partitions *state, struct block_device *bdev,
271 u32 offset, u32 size, int origin)
272{
273#ifdef CONFIG_BSD_DISKLABEL
274 parse_bsd(state, bdev, offset, size, origin,
275 "netbsd", BSD_MAXPARTITIONS);
276#endif
277}
278
279static void
280parse_openbsd(struct parsed_partitions *state, struct block_device *bdev,
281 u32 offset, u32 size, int origin)
282{
283#ifdef CONFIG_BSD_DISKLABEL
284 parse_bsd(state, bdev, offset, size, origin,
285 "openbsd", OPENBSD_MAXPARTITIONS);
286#endif
287}
288
289/*
290 * Create devices for Unixware partitions listed in a disklabel, under a
291 * dos-like partition. See parse_extended() for more information.
292 */
293static void
294parse_unixware(struct parsed_partitions *state, struct block_device *bdev,
295 u32 offset, u32 size, int origin)
296{
297#ifdef CONFIG_UNIXWARE_DISKLABEL
298 Sector sect;
299 struct unixware_disklabel *l;
300 struct unixware_slice *p;
301
302 l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, &sect);
303 if (!l)
304 return;
305 if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
306 le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
307 put_dev_sector(sect);
308 return;
309 }
310 printk(" %s%d: <unixware:", state->name, origin);
311 p = &l->vtoc.v_slice[1];
312 /* I omit the 0th slice as it is the same as whole disk. */
313 while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
314 if (state->next == state->limit)
315 break;
316
317 if (p->s_label != UNIXWARE_FS_UNUSED)
318 put_partition(state, state->next++,
319 START_SECT(p), NR_SECTS(p));
320 p++;
321 }
322 put_dev_sector(sect);
323 printk(" >\n");
324#endif
325}
326
327/*
328 * Minix 2.0.0/2.0.2 subpartition support.
329 * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
330 * Rajeev V. Pillai <rajeevvp@yahoo.com>
331 */
332static void
333parse_minix(struct parsed_partitions *state, struct block_device *bdev,
334 u32 offset, u32 size, int origin)
335{
336#ifdef CONFIG_MINIX_SUBPARTITION
337 Sector sect;
338 unsigned char *data;
339 struct partition *p;
340 int i;
341
342 data = read_dev_sector(bdev, offset, &sect);
343 if (!data)
344 return;
345
346 p = (struct partition *)(data + 0x1be);
347
348 /* The first sector of a Minix partition can have either
349 * a secondary MBR describing its subpartitions, or
350 * the normal boot sector. */
351 if (msdos_magic_present (data + 510) &&
352 SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
353
354 printk(" %s%d: <minix:", state->name, origin);
355 for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
356 if (state->next == state->limit)
357 break;
358 /* add each partition in use */
359 if (SYS_IND(p) == MINIX_PARTITION)
360 put_partition(state, state->next++,
361 START_SECT(p), NR_SECTS(p));
362 }
363 printk(" >\n");
364 }
365 put_dev_sector(sect);
366#endif /* CONFIG_MINIX_SUBPARTITION */
367}
368
369static struct {
370 unsigned char id;
371 void (*parse)(struct parsed_partitions *, struct block_device *,
372 u32, u32, int);
373} subtypes[] = {
374 {FREEBSD_PARTITION, parse_freebsd},
375 {NETBSD_PARTITION, parse_netbsd},
376 {OPENBSD_PARTITION, parse_openbsd},
377 {MINIX_PARTITION, parse_minix},
378 {UNIXWARE_PARTITION, parse_unixware},
379 {SOLARIS_X86_PARTITION, parse_solaris_x86},
380 {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
381 {0, NULL},
382};
383
384int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
385{
386 int sector_size = bdev_hardsect_size(bdev) / 512;
387 Sector sect;
388 unsigned char *data;
389 struct partition *p;
390 int slot;
391
392 data = read_dev_sector(bdev, 0, &sect);
393 if (!data)
394 return -1;
395 if (!msdos_magic_present(data + 510)) {
396 put_dev_sector(sect);
397 return 0;
398 }
399
400 /*
401 * Now that the 55aa signature is present, this is probably
402 * either the boot sector of a FAT filesystem or a DOS-type
403 * partition table. Reject this in case the boot indicator
404 * is not 0 or 0x80.
405 */
406 p = (struct partition *) (data + 0x1be);
407 for (slot = 1; slot <= 4; slot++, p++) {
408 if (p->boot_ind != 0 && p->boot_ind != 0x80) {
409 put_dev_sector(sect);
410 return 0;
411 }
412 }
413
414#ifdef CONFIG_EFI_PARTITION
415 p = (struct partition *) (data + 0x1be);
416 for (slot = 1 ; slot <= 4 ; slot++, p++) {
417 /* If this is an EFI GPT disk, msdos should ignore it. */
418 if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
419 put_dev_sector(sect);
420 return 0;
421 }
422 }
423#endif
424 p = (struct partition *) (data + 0x1be);
425
426 /*
427 * Look for partitions in two passes:
428 * First find the primary and DOS-type extended partitions.
429 * On the second pass look inside *BSD, Unixware and Solaris partitions.
430 */
431
432 state->next = 5;
433 for (slot = 1 ; slot <= 4 ; slot++, p++) {
434 u32 start = START_SECT(p)*sector_size;
435 u32 size = NR_SECTS(p)*sector_size;
436 if (SYS_IND(p) == 0)
437 continue;
438 if (!size)
439 continue;
440 if (is_extended_partition(p)) {
441 /* prevent someone doing mkfs or mkswap on an
442 extended partition, but leave room for LILO */
443 put_partition(state, slot, start, size == 1 ? 1 : 2);
444 printk(" <");
445 parse_extended(state, bdev, start, size);
446 printk(" >");
447 continue;
448 }
449 put_partition(state, slot, start, size);
450 if (SYS_IND(p) == LINUX_RAID_PARTITION)
451 state->parts[slot].flags = 1;
452 if (SYS_IND(p) == DM6_PARTITION)
453 printk("[DM]");
454 if (SYS_IND(p) == EZD_PARTITION)
455 printk("[EZD]");
456 }
457
458 printk("\n");
459
460 /* second pass - output for each on a separate line */
461 p = (struct partition *) (0x1be + data);
462 for (slot = 1 ; slot <= 4 ; slot++, p++) {
463 unsigned char id = SYS_IND(p);
464 int n;
465
466 if (!NR_SECTS(p))
467 continue;
468
469 for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
470 ;
471
472 if (!subtypes[n].parse)
473 continue;
474 subtypes[n].parse(state, bdev, START_SECT(p)*sector_size,
475 NR_SECTS(p)*sector_size, slot);
476 }
477 put_dev_sector(sect);
478 return 1;
479}
diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h
new file mode 100644
index 00000000000..01e5e0b6902
--- /dev/null
+++ b/fs/partitions/msdos.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/msdos.h
3 */
4
5#define MSDOS_LABEL_MAGIC 0xAA55
6
7int msdos_partition(struct parsed_partitions *state, struct block_device *bdev);
8
diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c
new file mode 100644
index 00000000000..c05c17bc5df
--- /dev/null
+++ b/fs/partitions/osf.c
@@ -0,0 +1,78 @@
1/*
2 * fs/partitions/osf.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include "check.h"
11#include "osf.h"
12
13int osf_partition(struct parsed_partitions *state, struct block_device *bdev)
14{
15 int i;
16 int slot = 1;
17 Sector sect;
18 unsigned char *data;
19 struct disklabel {
20 __le32 d_magic;
21 __le16 d_type,d_subtype;
22 u8 d_typename[16];
23 u8 d_packname[16];
24 __le32 d_secsize;
25 __le32 d_nsectors;
26 __le32 d_ntracks;
27 __le32 d_ncylinders;
28 __le32 d_secpercyl;
29 __le32 d_secprtunit;
30 __le16 d_sparespertrack;
31 __le16 d_sparespercyl;
32 __le32 d_acylinders;
33 __le16 d_rpm, d_interleave, d_trackskew, d_cylskew;
34 __le32 d_headswitch, d_trkseek, d_flags;
35 __le32 d_drivedata[5];
36 __le32 d_spare[5];
37 __le32 d_magic2;
38 __le16 d_checksum;
39 __le16 d_npartitions;
40 __le32 d_bbsize, d_sbsize;
41 struct d_partition {
42 __le32 p_size;
43 __le32 p_offset;
44 __le32 p_fsize;
45 u8 p_fstype;
46 u8 p_frag;
47 __le16 p_cpg;
48 } d_partitions[8];
49 } * label;
50 struct d_partition * partition;
51
52 data = read_dev_sector(bdev, 0, &sect);
53 if (!data)
54 return -1;
55
56 label = (struct disklabel *) (data+64);
57 partition = label->d_partitions;
58 if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
59 put_dev_sector(sect);
60 return 0;
61 }
62 if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
63 put_dev_sector(sect);
64 return 0;
65 }
66 for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) {
67 if (slot == state->limit)
68 break;
69 if (le32_to_cpu(partition->p_size))
70 put_partition(state, slot,
71 le32_to_cpu(partition->p_offset),
72 le32_to_cpu(partition->p_size));
73 slot++;
74 }
75 printk("\n");
76 put_dev_sector(sect);
77 return 1;
78}
diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h
new file mode 100644
index 00000000000..427b8eab314
--- /dev/null
+++ b/fs/partitions/osf.h
@@ -0,0 +1,7 @@
1/*
2 * fs/partitions/osf.h
3 */
4
5#define DISKLABELMAGIC (0x82564557UL)
6
7int osf_partition(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c
new file mode 100644
index 00000000000..6fa4ff89510
--- /dev/null
+++ b/fs/partitions/sgi.c
@@ -0,0 +1,82 @@
1/*
2 * fs/partitions/sgi.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 */
6
7#include "check.h"
8#include "sgi.h"
9
10struct sgi_disklabel {
11 __be32 magic_mushroom; /* Big fat spliff... */
12 __be16 root_part_num; /* Root partition number */
13 __be16 swap_part_num; /* Swap partition number */
14 s8 boot_file[16]; /* Name of boot file for ARCS */
15 u8 _unused0[48]; /* Device parameter useless crapola.. */
16 struct sgi_volume {
17 s8 name[8]; /* Name of volume */
18 __be32 block_num; /* Logical block number */
19 __be32 num_bytes; /* How big, in bytes */
20 } volume[15];
21 struct sgi_partition {
22 __be32 num_blocks; /* Size in logical blocks */
23 __be32 first_block; /* First logical block */
24 __be32 type; /* Type of this partition */
25 } partitions[16];
26 __be32 csum; /* Disk label checksum */
27 __be32 _unused1; /* Padding */
28};
29
30int sgi_partition(struct parsed_partitions *state, struct block_device *bdev)
31{
32 int i, csum;
33 __be32 magic;
34 int slot = 1;
35 unsigned int start, blocks;
36 __be32 *ui, cs;
37 Sector sect;
38 struct sgi_disklabel *label;
39 struct sgi_partition *p;
40 char b[BDEVNAME_SIZE];
41
42 label = (struct sgi_disklabel *) read_dev_sector(bdev, 0, &sect);
43 if (!label)
44 return -1;
45 p = &label->partitions[0];
46 magic = label->magic_mushroom;
47 if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
48 /*printk("Dev %s SGI disklabel: bad magic %08x\n",
49 bdevname(bdev, b), be32_to_cpu(magic));*/
50 put_dev_sector(sect);
51 return 0;
52 }
53 ui = ((__be32 *) (label + 1)) - 1;
54 for(csum = 0; ui >= ((__be32 *) label);) {
55 cs = *ui--;
56 csum += be32_to_cpu(cs);
57 }
58 if(csum) {
59 printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
60 bdevname(bdev, b));
61 put_dev_sector(sect);
62 return 0;
63 }
64 /* All SGI disk labels have 16 partitions, disks under Linux only
65 * have 15 minor's. Luckily there are always a few zero length
66 * partitions which we don't care about so we never overflow the
67 * current_minor.
68 */
69 for(i = 0; i < 16; i++, p++) {
70 blocks = be32_to_cpu(p->num_blocks);
71 start = be32_to_cpu(p->first_block);
72 if (blocks) {
73 put_partition(state, slot, start, blocks);
74 if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION)
75 state->parts[slot].flags = 1;
76 }
77 slot++;
78 }
79 printk("\n");
80 put_dev_sector(sect);
81 return 1;
82}
diff --git a/fs/partitions/sgi.h b/fs/partitions/sgi.h
new file mode 100644
index 00000000000..5d5595c0992
--- /dev/null
+++ b/fs/partitions/sgi.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/sgi.h
3 */
4
5extern int sgi_partition(struct parsed_partitions *state, struct block_device *bdev);
6
7#define SGI_LABEL_MAGIC 0x0be5a941
8
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c
new file mode 100644
index 00000000000..abe91ca03ed
--- /dev/null
+++ b/fs/partitions/sun.c
@@ -0,0 +1,91 @@
1/*
2 * fs/partitions/sun.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include "check.h"
11#include "sun.h"
12
13int sun_partition(struct parsed_partitions *state, struct block_device *bdev)
14{
15 int i;
16 __be16 csum;
17 int slot = 1;
18 __be16 *ush;
19 Sector sect;
20 struct sun_disklabel {
21 unsigned char info[128]; /* Informative text string */
22 unsigned char spare0[14];
23 struct sun_info {
24 unsigned char spare1;
25 unsigned char id;
26 unsigned char spare2;
27 unsigned char flags;
28 } infos[8];
29 unsigned char spare[246]; /* Boot information etc. */
30 __be16 rspeed; /* Disk rotational speed */
31 __be16 pcylcount; /* Physical cylinder count */
32 __be16 sparecyl; /* extra sects per cylinder */
33 unsigned char spare2[4]; /* More magic... */
34 __be16 ilfact; /* Interleave factor */
35 __be16 ncyl; /* Data cylinder count */
36 __be16 nacyl; /* Alt. cylinder count */
37 __be16 ntrks; /* Tracks per cylinder */
38 __be16 nsect; /* Sectors per track */
39 unsigned char spare3[4]; /* Even more magic... */
40 struct sun_partition {
41 __be32 start_cylinder;
42 __be32 num_sectors;
43 } partitions[8];
44 __be16 magic; /* Magic number */
45 __be16 csum; /* Label xor'd checksum */
46 } * label;
47 struct sun_partition *p;
48 unsigned long spc;
49 char b[BDEVNAME_SIZE];
50
51 label = (struct sun_disklabel *)read_dev_sector(bdev, 0, &sect);
52 if (!label)
53 return -1;
54
55 p = label->partitions;
56 if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
57/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
58 bdevname(bdev, b), be16_to_cpu(label->magic)); */
59 put_dev_sector(sect);
60 return 0;
61 }
62 /* Look at the checksum */
63 ush = ((__be16 *) (label+1)) - 1;
64 for (csum = 0; ush >= ((__be16 *) label);)
65 csum ^= *ush--;
66 if (csum) {
67 printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
68 bdevname(bdev, b));
69 put_dev_sector(sect);
70 return 0;
71 }
72
73 /* All Sun disks have 8 partition entries */
74 spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
75 for (i = 0; i < 8; i++, p++) {
76 unsigned long st_sector;
77 int num_sectors;
78
79 st_sector = be32_to_cpu(p->start_cylinder) * spc;
80 num_sectors = be32_to_cpu(p->num_sectors);
81 if (num_sectors) {
82 put_partition(state, slot, st_sector, num_sectors);
83 if (label->infos[i].id == LINUX_RAID_PARTITION)
84 state->parts[slot].flags = 1;
85 }
86 slot++;
87 }
88 printk("\n");
89 put_dev_sector(sect);
90 return 1;
91}
diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h
new file mode 100644
index 00000000000..b1b19fda7b2
--- /dev/null
+++ b/fs/partitions/sun.h
@@ -0,0 +1,7 @@
1/*
2 * fs/partitions/sun.h
3 */
4
5#define SUN_LABEL_MAGIC 0xDABE
6
7int sun_partition(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c
new file mode 100644
index 00000000000..8a8d4d9db31
--- /dev/null
+++ b/fs/partitions/ultrix.c
@@ -0,0 +1,47 @@
1/*
2 * fs/partitions/ultrix.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Re-organised Jul 1999 Russell King
7 */
8
9#include "check.h"
10
11int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev)
12{
13 int i;
14 Sector sect;
15 unsigned char *data;
16 struct ultrix_disklabel {
17 s32 pt_magic; /* magic no. indicating part. info exits */
18 s32 pt_valid; /* set by driver if pt is current */
19 struct pt_info {
20 s32 pi_nblocks; /* no. of sectors */
21 u32 pi_blkoff; /* block offset for start */
22 } pt_part[8];
23 } *label;
24
25#define PT_MAGIC 0x032957 /* Partition magic number */
26#define PT_VALID 1 /* Indicates if struct is valid */
27
28 data = read_dev_sector(bdev, (16384 - sizeof(*label))/512, &sect);
29 if (!data)
30 return -1;
31
32 label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
33
34 if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
35 for (i=0; i<8; i++)
36 if (label->pt_part[i].pi_nblocks)
37 put_partition(state, i+1,
38 label->pt_part[i].pi_blkoff,
39 label->pt_part[i].pi_nblocks);
40 put_dev_sector(sect);
41 printk ("\n");
42 return 1;
43 } else {
44 put_dev_sector(sect);
45 return 0;
46 }
47}
diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h
new file mode 100644
index 00000000000..a74bf8e2d37
--- /dev/null
+++ b/fs/partitions/ultrix.h
@@ -0,0 +1,5 @@
1/*
2 * fs/partitions/ultrix.h
3 */
4
5int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev);