aboutsummaryrefslogtreecommitdiffstats
path: root/fs/partitions
diff options
context:
space:
mode:
Diffstat (limited to 'fs/partitions')
-rw-r--r--fs/partitions/Kconfig251
-rw-r--r--fs/partitions/Makefile20
-rw-r--r--fs/partitions/acorn.c556
-rw-r--r--fs/partitions/acorn.h14
-rw-r--r--fs/partitions/amiga.c139
-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.c698
-rw-r--r--fs/partitions/check.h49
-rw-r--r--fs/partitions/efi.c686
-rw-r--r--fs/partitions/efi.h134
-rw-r--r--fs/partitions/ibm.c275
-rw-r--r--fs/partitions/ibm.h1
-rw-r--r--fs/partitions/karma.c57
-rw-r--r--fs/partitions/karma.h8
-rw-r--r--fs/partitions/ldm.c1568
-rw-r--r--fs/partitions/ldm.h215
-rw-r--r--fs/partitions/mac.c134
-rw-r--r--fs/partitions/mac.h44
-rw-r--r--fs/partitions/msdos.c552
-rw-r--r--fs/partitions/msdos.h8
-rw-r--r--fs/partitions/osf.c86
-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.c122
-rw-r--r--fs/partitions/sun.h8
-rw-r--r--fs/partitions/sysv68.c95
-rw-r--r--fs/partitions/sysv68.h1
-rw-r--r--fs/partitions/ultrix.c48
-rw-r--r--fs/partitions/ultrix.h5
32 files changed, 6060 insertions, 0 deletions
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
new file mode 100644
index 00000000000..cb5f0a3f1b0
--- /dev/null
+++ b/fs/partitions/Kconfig
@@ -0,0 +1,251 @@
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
25 default y if ARCH_ACORN
26 depends on ACORN_PARTITION
27 help
28 Say Y here if you would like to use hard disks under Linux which
29 were partitioned using the Cumana interface on Acorn machines.
30
31config ACORN_PARTITION_EESOX
32 bool "EESOX partition support" if PARTITION_ADVANCED
33 default y if ARCH_ACORN
34 depends on ACORN_PARTITION
35
36config ACORN_PARTITION_ICS
37 bool "ICS partition support" if PARTITION_ADVANCED
38 default y if ARCH_ACORN
39 depends on ACORN_PARTITION
40 help
41 Say Y here if you would like to use hard disks under Linux which
42 were partitioned using the ICS interface on Acorn machines.
43
44config ACORN_PARTITION_ADFS
45 bool "Native filecore partition support" if PARTITION_ADVANCED
46 default y if ARCH_ACORN
47 depends on ACORN_PARTITION
48 help
49 The Acorn Disc Filing System is the standard file system of the
50 RiscOS operating system which runs on Acorn's ARM-based Risc PC
51 systems and the Acorn Archimedes range of machines. If you say
52 `Y' here, Linux will support disk partitions created under ADFS.
53
54config ACORN_PARTITION_POWERTEC
55 bool "PowerTec partition support" if PARTITION_ADVANCED
56 default y if ARCH_ACORN
57 depends on ACORN_PARTITION
58 help
59 Support reading partition tables created on Acorn machines using
60 the PowerTec SCSI drive.
61
62config ACORN_PARTITION_RISCIX
63 bool "RISCiX partition support" if PARTITION_ADVANCED
64 default y if ARCH_ACORN
65 depends on ACORN_PARTITION
66 help
67 Once upon a time, there was a native Unix port for the Acorn series
68 of machines called RISCiX. If you say 'Y' here, Linux will be able
69 to read disks partitioned under RISCiX.
70
71config OSF_PARTITION
72 bool "Alpha OSF partition support" if PARTITION_ADVANCED
73 default y if ALPHA
74 help
75 Say Y here if you would like to use hard disks under Linux which
76 were partitioned on an Alpha machine.
77
78config AMIGA_PARTITION
79 bool "Amiga partition table support" if PARTITION_ADVANCED
80 default y if (AMIGA || AFFS_FS=y)
81 help
82 Say Y here if you would like to use hard disks under Linux which
83 were partitioned under AmigaOS.
84
85config ATARI_PARTITION
86 bool "Atari partition table support" if PARTITION_ADVANCED
87 default y if ATARI
88 help
89 Say Y here if you would like to use hard disks under Linux which
90 were partitioned under the Atari OS.
91
92config IBM_PARTITION
93 bool "IBM disk label and partition support"
94 depends on PARTITION_ADVANCED && S390
95 help
96 Say Y here if you would like to be able to read the hard disk
97 partition table format used by IBM DASD disks operating under CMS.
98 Otherwise, say N.
99
100config MAC_PARTITION
101 bool "Macintosh partition map support" if PARTITION_ADVANCED
102 default y if (MAC || PPC_PMAC)
103 help
104 Say Y here if you would like to use hard disks under Linux which
105 were partitioned on a Macintosh.
106
107config MSDOS_PARTITION
108 bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED
109 default y
110 help
111 Say Y here.
112
113config BSD_DISKLABEL
114 bool "BSD disklabel (FreeBSD partition tables) support"
115 depends on PARTITION_ADVANCED && MSDOS_PARTITION
116 help
117 FreeBSD uses its own hard disk partition scheme on your PC. It
118 requires only one entry in the primary partition table of your disk
119 and manages it similarly to DOS extended partitions, putting in its
120 first sector a new partition table in BSD disklabel format. Saying Y
121 here allows you to read these disklabels and further mount FreeBSD
122 partitions from within Linux if you have also said Y to "UFS
123 file system support", above. If you don't know what all this is
124 about, say N.
125
126config MINIX_SUBPARTITION
127 bool "Minix subpartition support"
128 depends on PARTITION_ADVANCED && MSDOS_PARTITION
129 help
130 Minix 2.0.0/2.0.2 subpartition table support for Linux.
131 Say Y here if you want to mount and use Minix 2.0.0/2.0.2
132 subpartitions.
133
134config SOLARIS_X86_PARTITION
135 bool "Solaris (x86) partition table support"
136 depends on PARTITION_ADVANCED && MSDOS_PARTITION
137 help
138 Like most systems, Solaris x86 uses its own hard disk partition
139 table format, incompatible with all others. Saying Y here allows you
140 to read these partition tables and further mount Solaris x86
141 partitions from within Linux if you have also said Y to "UFS
142 file system support", above.
143
144config UNIXWARE_DISKLABEL
145 bool "Unixware slices support"
146 depends on PARTITION_ADVANCED && MSDOS_PARTITION
147 ---help---
148 Like some systems, UnixWare uses its own slice table inside a
149 partition (VTOC - Virtual Table of Contents). Its format is
150 incompatible with all other OSes. Saying Y here allows you to read
151 VTOC and further mount UnixWare partitions read-only from within
152 Linux if you have also said Y to "UFS file system support" or
153 "System V and Coherent file system support", above.
154
155 This is mainly used to carry data from a UnixWare box to your
156 Linux box via a removable medium like magneto-optical, ZIP or
157 removable IDE drives. Note, however, that a good portable way to
158 transport files and directories between unixes (and even other
159 operating systems) is given by the tar program ("man tar" or
160 preferably "info tar").
161
162 If you don't know what all this is about, say N.
163
164config LDM_PARTITION
165 bool "Windows Logical Disk Manager (Dynamic Disk) support"
166 depends on PARTITION_ADVANCED
167 ---help---
168 Say Y here if you would like to use hard disks under Linux which
169 were partitioned using Windows 2000's/XP's or Vista's Logical Disk
170 Manager. They are also known as "Dynamic Disks".
171
172 Note this driver only supports Dynamic Disks with a protective MBR
173 label, i.e. DOS partition table. It does not support GPT labelled
174 Dynamic Disks yet as can be created with Vista.
175
176 Windows 2000 introduced the concept of Dynamic Disks to get around
177 the limitations of the PC's partitioning scheme. The Logical Disk
178 Manager allows the user to repartition a disk and create spanned,
179 mirrored, striped or RAID volumes, all without the need for
180 rebooting.
181
182 Normal partitions are now called Basic Disks under Windows 2000, XP,
183 and Vista.
184
185 For a fuller description read <file:Documentation/ldm.txt>.
186
187 If unsure, say N.
188
189config LDM_DEBUG
190 bool "Windows LDM extra logging"
191 depends on LDM_PARTITION
192 help
193 Say Y here if you would like LDM to log verbosely. This could be
194 helpful if the driver doesn't work as expected and you'd like to
195 report a bug.
196
197 If unsure, say N.
198
199config SGI_PARTITION
200 bool "SGI partition support" if PARTITION_ADVANCED
201 default y if DEFAULT_SGI_PARTITION
202 help
203 Say Y here if you would like to be able to read the hard disk
204 partition table format used by SGI machines.
205
206config ULTRIX_PARTITION
207 bool "Ultrix partition table support" if PARTITION_ADVANCED
208 default y if MACH_DECSTATION
209 help
210 Say Y here if you would like to be able to read the hard disk
211 partition table format used by DEC (now Compaq) Ultrix machines.
212 Otherwise, say N.
213
214config SUN_PARTITION
215 bool "Sun partition tables support" if PARTITION_ADVANCED
216 default y if (SPARC || SUN3 || SUN3X)
217 ---help---
218 Like most systems, SunOS uses its own hard disk partition table
219 format, incompatible with all others. Saying Y here allows you to
220 read these partition tables and further mount SunOS partitions from
221 within Linux if you have also said Y to "UFS file system support",
222 above. This is mainly used to carry data from a SPARC under SunOS to
223 your Linux box via a removable medium like magneto-optical or ZIP
224 drives; note however that a good portable way to transport files and
225 directories between unixes (and even other operating systems) is
226 given by the tar program ("man tar" or preferably "info tar"). If
227 you don't know what all this is about, say N.
228
229config KARMA_PARTITION
230 bool "Karma Partition support"
231 depends on PARTITION_ADVANCED
232 help
233 Say Y here if you would like to mount the Rio Karma MP3 player, as it
234 uses a proprietary partition table.
235
236config EFI_PARTITION
237 bool "EFI GUID Partition support"
238 depends on PARTITION_ADVANCED
239 select CRC32
240 help
241 Say Y here if you would like to use hard disks under Linux which
242 were partitioned using EFI GPT.
243
244config SYSV68_PARTITION
245 bool "SYSV68 partition table support" if PARTITION_ADVANCED
246 default y if VME
247 help
248 Say Y here if you would like to be able to read the hard disk
249 partition table format used by Motorola Delta machines (using
250 sysv68).
251 Otherwise, say N.
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
new file mode 100644
index 00000000000..03af8eac51d
--- /dev/null
+++ b/fs/partitions/Makefile
@@ -0,0 +1,20 @@
1#
2# Makefile for the linux kernel.
3#
4
5obj-$(CONFIG_BLOCK) := check.o
6
7obj-$(CONFIG_ACORN_PARTITION) += acorn.o
8obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
9obj-$(CONFIG_ATARI_PARTITION) += atari.o
10obj-$(CONFIG_MAC_PARTITION) += mac.o
11obj-$(CONFIG_LDM_PARTITION) += ldm.o
12obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
13obj-$(CONFIG_OSF_PARTITION) += osf.o
14obj-$(CONFIG_SGI_PARTITION) += sgi.o
15obj-$(CONFIG_SUN_PARTITION) += sun.o
16obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
17obj-$(CONFIG_IBM_PARTITION) += ibm.o
18obj-$(CONFIG_EFI_PARTITION) += efi.o
19obj-$(CONFIG_KARMA_PARTITION) += karma.o
20obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
new file mode 100644
index 00000000000..fbeb697374d
--- /dev/null
+++ b/fs/partitions/acorn.c
@@ -0,0 +1,556 @@
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/buffer_head.h>
16#include <linux/adfs_fs.h>
17
18#include "check.h"
19#include "acorn.h"
20
21/*
22 * Partition types. (Oh for reusability)
23 */
24#define PARTITION_RISCIX_MFM 1
25#define PARTITION_RISCIX_SCSI 2
26#define PARTITION_LINUX 9
27
28#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
29 defined(CONFIG_ACORN_PARTITION_ADFS)
30static struct adfs_discrecord *
31adfs_partition(struct parsed_partitions *state, char *name, char *data,
32 unsigned long first_sector, int slot)
33{
34 struct adfs_discrecord *dr;
35 unsigned int nr_sects;
36
37 if (adfs_checkbblk(data))
38 return NULL;
39
40 dr = (struct adfs_discrecord *)(data + 0x1c0);
41
42 if (dr->disc_size == 0 && dr->disc_size_high == 0)
43 return NULL;
44
45 nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
46 (le32_to_cpu(dr->disc_size) >> 9);
47
48 if (name) {
49 strlcat(state->pp_buf, " [", PAGE_SIZE);
50 strlcat(state->pp_buf, name, PAGE_SIZE);
51 strlcat(state->pp_buf, "]", PAGE_SIZE);
52 }
53 put_partition(state, slot, first_sector, nr_sects);
54 return dr;
55}
56#endif
57
58#ifdef CONFIG_ACORN_PARTITION_RISCIX
59
60struct riscix_part {
61 __le32 start;
62 __le32 length;
63 __le32 one;
64 char name[16];
65};
66
67struct riscix_record {
68 __le32 magic;
69#define RISCIX_MAGIC cpu_to_le32(0x4a657320)
70 __le32 date;
71 struct riscix_part part[8];
72};
73
74#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
75 defined(CONFIG_ACORN_PARTITION_ADFS)
76static int riscix_partition(struct parsed_partitions *state,
77 unsigned long first_sect, int slot,
78 unsigned long nr_sects)
79{
80 Sector sect;
81 struct riscix_record *rr;
82
83 rr = read_part_sector(state, first_sect, &sect);
84 if (!rr)
85 return -1;
86
87 strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
88
89
90 if (rr->magic == RISCIX_MAGIC) {
91 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
92 int part;
93
94 strlcat(state->pp_buf, " <", PAGE_SIZE);
95
96 put_partition(state, slot++, first_sect, size);
97 for (part = 0; part < 8; part++) {
98 if (rr->part[part].one &&
99 memcmp(rr->part[part].name, "All\0", 4)) {
100 put_partition(state, slot++,
101 le32_to_cpu(rr->part[part].start),
102 le32_to_cpu(rr->part[part].length));
103 strlcat(state->pp_buf, "(", PAGE_SIZE);
104 strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
105 strlcat(state->pp_buf, ")", PAGE_SIZE);
106 }
107 }
108
109 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
110 } else {
111 put_partition(state, slot++, first_sect, nr_sects);
112 }
113
114 put_dev_sector(sect);
115 return slot;
116}
117#endif
118#endif
119
120#define LINUX_NATIVE_MAGIC 0xdeafa1de
121#define LINUX_SWAP_MAGIC 0xdeafab1e
122
123struct linux_part {
124 __le32 magic;
125 __le32 start_sect;
126 __le32 nr_sects;
127};
128
129#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
130 defined(CONFIG_ACORN_PARTITION_ADFS)
131static int linux_partition(struct parsed_partitions *state,
132 unsigned long first_sect, int slot,
133 unsigned long nr_sects)
134{
135 Sector sect;
136 struct linux_part *linuxp;
137 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
138
139 strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
140
141 put_partition(state, slot++, first_sect, size);
142
143 linuxp = read_part_sector(state, first_sect, &sect);
144 if (!linuxp)
145 return -1;
146
147 strlcat(state->pp_buf, " <", PAGE_SIZE);
148 while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
149 linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
150 if (slot == state->limit)
151 break;
152 put_partition(state, slot++, first_sect +
153 le32_to_cpu(linuxp->start_sect),
154 le32_to_cpu(linuxp->nr_sects));
155 linuxp ++;
156 }
157 strlcat(state->pp_buf, " >", PAGE_SIZE);
158
159 put_dev_sector(sect);
160 return slot;
161}
162#endif
163
164#ifdef CONFIG_ACORN_PARTITION_CUMANA
165int adfspart_check_CUMANA(struct parsed_partitions *state)
166{
167 unsigned long first_sector = 0;
168 unsigned int start_blk = 0;
169 Sector sect;
170 unsigned char *data;
171 char *name = "CUMANA/ADFS";
172 int first = 1;
173 int slot = 1;
174
175 /*
176 * Try Cumana style partitions - sector 6 contains ADFS boot block
177 * with pointer to next 'drive'.
178 *
179 * There are unknowns in this code - is the 'cylinder number' of the
180 * next partition relative to the start of this one - I'm assuming
181 * it is.
182 *
183 * Also, which ID did Cumana use?
184 *
185 * This is totally unfinished, and will require more work to get it
186 * going. Hence it is totally untested.
187 */
188 do {
189 struct adfs_discrecord *dr;
190 unsigned int nr_sects;
191
192 data = read_part_sector(state, start_blk * 2 + 6, &sect);
193 if (!data)
194 return -1;
195
196 if (slot == state->limit)
197 break;
198
199 dr = adfs_partition(state, name, data, first_sector, slot++);
200 if (!dr)
201 break;
202
203 name = NULL;
204
205 nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
206 (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
207 dr->secspertrack;
208
209 if (!nr_sects)
210 break;
211
212 first = 0;
213 first_sector += nr_sects;
214 start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
215 nr_sects = 0; /* hmm - should be partition size */
216
217 switch (data[0x1fc] & 15) {
218 case 0: /* No partition / ADFS? */
219 break;
220
221#ifdef CONFIG_ACORN_PARTITION_RISCIX
222 case PARTITION_RISCIX_SCSI:
223 /* RISCiX - we don't know how to find the next one. */
224 slot = riscix_partition(state, first_sector, slot,
225 nr_sects);
226 break;
227#endif
228
229 case PARTITION_LINUX:
230 slot = linux_partition(state, first_sector, slot,
231 nr_sects);
232 break;
233 }
234 put_dev_sector(sect);
235 if (slot == -1)
236 return -1;
237 } while (1);
238 put_dev_sector(sect);
239 return first ? 0 : 1;
240}
241#endif
242
243#ifdef CONFIG_ACORN_PARTITION_ADFS
244/*
245 * Purpose: allocate ADFS partitions.
246 *
247 * Params : hd - pointer to gendisk structure to store partition info.
248 * dev - device number to access.
249 *
250 * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
251 *
252 * Alloc : hda = whole drive
253 * hda1 = ADFS partition on first drive.
254 * hda2 = non-ADFS partition.
255 */
256int adfspart_check_ADFS(struct parsed_partitions *state)
257{
258 unsigned long start_sect, nr_sects, sectscyl, heads;
259 Sector sect;
260 unsigned char *data;
261 struct adfs_discrecord *dr;
262 unsigned char id;
263 int slot = 1;
264
265 data = read_part_sector(state, 6, &sect);
266 if (!data)
267 return -1;
268
269 dr = adfs_partition(state, "ADFS", data, 0, slot++);
270 if (!dr) {
271 put_dev_sector(sect);
272 return 0;
273 }
274
275 heads = dr->heads + ((dr->lowsector >> 6) & 1);
276 sectscyl = dr->secspertrack * heads;
277 start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
278 id = data[0x1fc] & 15;
279 put_dev_sector(sect);
280
281 /*
282 * Work out start of non-adfs partition.
283 */
284 nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect;
285
286 if (start_sect) {
287 switch (id) {
288#ifdef CONFIG_ACORN_PARTITION_RISCIX
289 case PARTITION_RISCIX_SCSI:
290 case PARTITION_RISCIX_MFM:
291 slot = riscix_partition(state, start_sect, slot,
292 nr_sects);
293 break;
294#endif
295
296 case PARTITION_LINUX:
297 slot = linux_partition(state, start_sect, slot,
298 nr_sects);
299 break;
300 }
301 }
302 strlcat(state->pp_buf, "\n", PAGE_SIZE);
303 return 1;
304}
305#endif
306
307#ifdef CONFIG_ACORN_PARTITION_ICS
308
309struct ics_part {
310 __le32 start;
311 __le32 size;
312};
313
314static int adfspart_check_ICSLinux(struct parsed_partitions *state,
315 unsigned long block)
316{
317 Sector sect;
318 unsigned char *data = read_part_sector(state, block, &sect);
319 int result = 0;
320
321 if (data) {
322 if (memcmp(data, "LinuxPart", 9) == 0)
323 result = 1;
324 put_dev_sector(sect);
325 }
326
327 return result;
328}
329
330/*
331 * Check for a valid ICS partition using the checksum.
332 */
333static inline int valid_ics_sector(const unsigned char *data)
334{
335 unsigned long sum;
336 int i;
337
338 for (i = 0, sum = 0x50617274; i < 508; i++)
339 sum += data[i];
340
341 sum -= le32_to_cpu(*(__le32 *)(&data[508]));
342
343 return sum == 0;
344}
345
346/*
347 * Purpose: allocate ICS partitions.
348 * Params : hd - pointer to gendisk structure to store partition info.
349 * dev - device number to access.
350 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
351 * Alloc : hda = whole drive
352 * hda1 = ADFS partition 0 on first drive.
353 * hda2 = ADFS partition 1 on first drive.
354 * ..etc..
355 */
356int adfspart_check_ICS(struct parsed_partitions *state)
357{
358 const unsigned char *data;
359 const struct ics_part *p;
360 int slot;
361 Sector sect;
362
363 /*
364 * Try ICS style partitions - sector 0 contains partition info.
365 */
366 data = read_part_sector(state, 0, &sect);
367 if (!data)
368 return -1;
369
370 if (!valid_ics_sector(data)) {
371 put_dev_sector(sect);
372 return 0;
373 }
374
375 strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
376
377 for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
378 u32 start = le32_to_cpu(p->start);
379 s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
380
381 if (slot == state->limit)
382 break;
383
384 /*
385 * Negative sizes tell the RISC OS ICS driver to ignore
386 * this partition - in effect it says that this does not
387 * contain an ADFS filesystem.
388 */
389 if (size < 0) {
390 size = -size;
391
392 /*
393 * Our own extension - We use the first sector
394 * of the partition to identify what type this
395 * partition is. We must not make this visible
396 * to the filesystem.
397 */
398 if (size > 1 && adfspart_check_ICSLinux(state, start)) {
399 start += 1;
400 size -= 1;
401 }
402 }
403
404 if (size)
405 put_partition(state, slot++, start, size);
406 }
407
408 put_dev_sector(sect);
409 strlcat(state->pp_buf, "\n", PAGE_SIZE);
410 return 1;
411}
412#endif
413
414#ifdef CONFIG_ACORN_PARTITION_POWERTEC
415struct ptec_part {
416 __le32 unused1;
417 __le32 unused2;
418 __le32 start;
419 __le32 size;
420 __le32 unused5;
421 char type[8];
422};
423
424static inline int valid_ptec_sector(const unsigned char *data)
425{
426 unsigned char checksum = 0x2a;
427 int i;
428
429 /*
430 * If it looks like a PC/BIOS partition, then it
431 * probably isn't PowerTec.
432 */
433 if (data[510] == 0x55 && data[511] == 0xaa)
434 return 0;
435
436 for (i = 0; i < 511; i++)
437 checksum += data[i];
438
439 return checksum == data[511];
440}
441
442/*
443 * Purpose: allocate ICS partitions.
444 * Params : hd - pointer to gendisk structure to store partition info.
445 * dev - device number to access.
446 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
447 * Alloc : hda = whole drive
448 * hda1 = ADFS partition 0 on first drive.
449 * hda2 = ADFS partition 1 on first drive.
450 * ..etc..
451 */
452int adfspart_check_POWERTEC(struct parsed_partitions *state)
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_part_sector(state, 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 strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
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 strlcat(state->pp_buf, "\n", PAGE_SIZE);
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 adfspart_check_EESOX(struct parsed_partitions *state)
514{
515 Sector sect;
516 const unsigned char *data;
517 unsigned char buffer[256];
518 struct eesox_part *p;
519 sector_t start = 0;
520 int i, slot = 1;
521
522 data = read_part_sector(state, 7, &sect);
523 if (!data)
524 return -1;
525
526 /*
527 * "Decrypt" the partition table. God knows why...
528 */
529 for (i = 0; i < 256; i++)
530 buffer[i] = data[i] ^ eesox_name[i & 15];
531
532 put_dev_sector(sect);
533
534 for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
535 sector_t next;
536
537 if (memcmp(p->magic, "Eesox", 6))
538 break;
539
540 next = le32_to_cpu(p->start);
541 if (i)
542 put_partition(state, slot++, start, next - start);
543 start = next;
544 }
545
546 if (i != 0) {
547 sector_t size;
548
549 size = get_capacity(state->bdev->bd_disk);
550 put_partition(state, slot++, start, size - start);
551 strlcat(state->pp_buf, "\n", PAGE_SIZE);
552 }
553
554 return i ? 1 : 0;
555}
556#endif
diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h
new file mode 100644
index 00000000000..ede82852969
--- /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);
11int adfspart_check_ADFS(struct parsed_partitions *state);
12int adfspart_check_ICS(struct parsed_partitions *state);
13int adfspart_check_POWERTEC(struct parsed_partitions *state);
14int adfspart_check_EESOX(struct parsed_partitions *state);
diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c
new file mode 100644
index 00000000000..70cbf44a156
--- /dev/null
+++ b/fs/partitions/amiga.c
@@ -0,0 +1,139 @@
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 amiga_partition(struct parsed_partitions *state)
27{
28 Sector sect;
29 unsigned char *data;
30 struct RigidDiskBlock *rdb;
31 struct PartitionBlock *pb;
32 int start_sect, nr_sects, blk, part, res = 0;
33 int blksize = 1; /* Multiplier for disk block size */
34 int slot = 1;
35 char b[BDEVNAME_SIZE];
36
37 for (blk = 0; ; blk++, put_dev_sector(sect)) {
38 if (blk == RDB_ALLOCATION_LIMIT)
39 goto rdb_done;
40 data = read_part_sector(state, blk, &sect);
41 if (!data) {
42 if (warn_no_part)
43 printk("Dev %s: unable to read RDB block %d\n",
44 bdevname(state->bdev, b), blk);
45 res = -1;
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(state->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 {
73 char tmp[7 + 10 + 1 + 1];
74
75 /* Be more informative */
76 snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512);
77 strlcat(state->pp_buf, tmp, PAGE_SIZE);
78 }
79 blk = be32_to_cpu(rdb->rdb_PartitionList);
80 put_dev_sector(sect);
81 for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
82 blk *= blksize; /* Read in terms partition table understands */
83 data = read_part_sector(state, blk, &sect);
84 if (!data) {
85 if (warn_no_part)
86 printk("Dev %s: unable to read partition block %d\n",
87 bdevname(state->bdev, b), blk);
88 res = -1;
89 goto rdb_done;
90 }
91 pb = (struct PartitionBlock *)data;
92 blk = be32_to_cpu(pb->pb_Next);
93 if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
94 continue;
95 if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
96 continue;
97
98 /* Tell Kernel about it */
99
100 nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
101 be32_to_cpu(pb->pb_Environment[9])) *
102 be32_to_cpu(pb->pb_Environment[3]) *
103 be32_to_cpu(pb->pb_Environment[5]) *
104 blksize;
105 if (!nr_sects)
106 continue;
107 start_sect = be32_to_cpu(pb->pb_Environment[9]) *
108 be32_to_cpu(pb->pb_Environment[3]) *
109 be32_to_cpu(pb->pb_Environment[5]) *
110 blksize;
111 put_partition(state,slot++,start_sect,nr_sects);
112 {
113 /* Be even more informative to aid mounting */
114 char dostype[4];
115 char tmp[42];
116
117 __be32 *dt = (__be32 *)dostype;
118 *dt = pb->pb_Environment[16];
119 if (dostype[3] < ' ')
120 snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)",
121 dostype[0], dostype[1],
122 dostype[2], dostype[3] + '@' );
123 else
124 snprintf(tmp, sizeof(tmp), " (%c%c%c%c)",
125 dostype[0], dostype[1],
126 dostype[2], dostype[3]);
127 strlcat(state->pp_buf, tmp, PAGE_SIZE);
128 snprintf(tmp, sizeof(tmp), "(res %d spb %d)",
129 be32_to_cpu(pb->pb_Environment[6]),
130 be32_to_cpu(pb->pb_Environment[4]));
131 strlcat(state->pp_buf, tmp, PAGE_SIZE);
132 }
133 res = 1;
134 }
135 strlcat(state->pp_buf, "\n", PAGE_SIZE);
136
137rdb_done:
138 return res;
139}
diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h
new file mode 100644
index 00000000000..d094585cada
--- /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);
6
diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c
new file mode 100644
index 00000000000..9875b05e80a
--- /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)
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 = read_part_sector(state, 0, &sect);
46 if (!rs)
47 return -1;
48
49 /* Verify this is an Atari rootsector: */
50 hd_size = state->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 strlcat(state->pp_buf, " AHDI", PAGE_SIZE);
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 strlcat(state->pp_buf, " XGM<", PAGE_SIZE);
85 partsect = extensect = be32_to_cpu(pi->st);
86 while (1) {
87 xrs = read_part_sector(state, partsect, &sect2);
88 if (!xrs) {
89 printk (" block %ld read failed\n", partsect);
90 put_dev_sector(sect);
91 return -1;
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 strlcat(state->pp_buf, " >", PAGE_SIZE);
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 strlcat(state->pp_buf, " ICD<", PAGE_SIZE);
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 strlcat(state->pp_buf, " >", PAGE_SIZE);
141 }
142 }
143#endif
144 put_dev_sector(sect);
145
146 strlcat(state->pp_buf, "\n", PAGE_SIZE);
147
148 return 1;
149}
diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h
new file mode 100644
index 00000000000..fe2d32a89f3
--- /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);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
new file mode 100644
index 00000000000..b4095cc7343
--- /dev/null
+++ b/fs/partitions/check.c
@@ -0,0 +1,698 @@
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/slab.h>
20#include <linux/kmod.h>
21#include <linux/ctype.h>
22#include <linux/genhd.h>
23#include <linux/blktrace_api.h>
24
25#include "check.h"
26
27#include "acorn.h"
28#include "amiga.h"
29#include "atari.h"
30#include "ldm.h"
31#include "mac.h"
32#include "msdos.h"
33#include "osf.h"
34#include "sgi.h"
35#include "sun.h"
36#include "ibm.h"
37#include "ultrix.h"
38#include "efi.h"
39#include "karma.h"
40#include "sysv68.h"
41
42#ifdef CONFIG_BLK_DEV_MD
43extern void md_autodetect_dev(dev_t dev);
44#endif
45
46int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
47
48static int (*check_part[])(struct parsed_partitions *) = {
49 /*
50 * Probe partition formats with tables at disk address 0
51 * that also have an ADFS boot block at 0xdc0.
52 */
53#ifdef CONFIG_ACORN_PARTITION_ICS
54 adfspart_check_ICS,
55#endif
56#ifdef CONFIG_ACORN_PARTITION_POWERTEC
57 adfspart_check_POWERTEC,
58#endif
59#ifdef CONFIG_ACORN_PARTITION_EESOX
60 adfspart_check_EESOX,
61#endif
62
63 /*
64 * Now move on to formats that only have partition info at
65 * disk address 0xdc0. Since these may also have stale
66 * PC/BIOS partition tables, they need to come before
67 * the msdos entry.
68 */
69#ifdef CONFIG_ACORN_PARTITION_CUMANA
70 adfspart_check_CUMANA,
71#endif
72#ifdef CONFIG_ACORN_PARTITION_ADFS
73 adfspart_check_ADFS,
74#endif
75
76#ifdef CONFIG_EFI_PARTITION
77 efi_partition, /* this must come before msdos */
78#endif
79#ifdef CONFIG_SGI_PARTITION
80 sgi_partition,
81#endif
82#ifdef CONFIG_LDM_PARTITION
83 ldm_partition, /* this must come before msdos */
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#ifdef CONFIG_KARMA_PARTITION
110 karma_partition,
111#endif
112#ifdef CONFIG_SYSV68_PARTITION
113 sysv68_partition,
114#endif
115 NULL
116};
117
118/*
119 * disk_name() is used by partition check code and the genhd driver.
120 * It formats the devicename of the indicated disk into
121 * the supplied buffer (of size at least 32), and returns
122 * a pointer to that same buffer (for convenience).
123 */
124
125char *disk_name(struct gendisk *hd, int partno, char *buf)
126{
127 if (!partno)
128 snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
129 else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
130 snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
131 else
132 snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
133
134 return buf;
135}
136
137const char *bdevname(struct block_device *bdev, char *buf)
138{
139 return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
140}
141
142EXPORT_SYMBOL(bdevname);
143
144/*
145 * There's very little reason to use this, you should really
146 * have a struct block_device just about everywhere and use
147 * bdevname() instead.
148 */
149const char *__bdevname(dev_t dev, char *buffer)
150{
151 scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)",
152 MAJOR(dev), MINOR(dev));
153 return buffer;
154}
155
156EXPORT_SYMBOL(__bdevname);
157
158static struct parsed_partitions *
159check_partition(struct gendisk *hd, struct block_device *bdev)
160{
161 struct parsed_partitions *state;
162 int i, res, err;
163
164 state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
165 if (!state)
166 return NULL;
167 state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
168 if (!state->pp_buf) {
169 kfree(state);
170 return NULL;
171 }
172 state->pp_buf[0] = '\0';
173
174 state->bdev = bdev;
175 disk_name(hd, 0, state->name);
176 snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
177 if (isdigit(state->name[strlen(state->name)-1]))
178 sprintf(state->name, "p");
179
180 state->limit = disk_max_parts(hd);
181 i = res = err = 0;
182 while (!res && check_part[i]) {
183 memset(&state->parts, 0, sizeof(state->parts));
184 res = check_part[i++](state);
185 if (res < 0) {
186 /* We have hit an I/O error which we don't report now.
187 * But record it, and let the others do their job.
188 */
189 err = res;
190 res = 0;
191 }
192
193 }
194 if (res > 0) {
195 printk(KERN_INFO "%s", state->pp_buf);
196
197 free_page((unsigned long)state->pp_buf);
198 return state;
199 }
200 if (state->access_beyond_eod)
201 err = -ENOSPC;
202 if (err)
203 /* The partition is unrecognized. So report I/O errors if there were any */
204 res = err;
205 if (!res)
206 strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE);
207 else if (warn_no_part)
208 strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE);
209
210 printk(KERN_INFO "%s", state->pp_buf);
211
212 free_page((unsigned long)state->pp_buf);
213 kfree(state);
214 return ERR_PTR(res);
215}
216
217static ssize_t part_partition_show(struct device *dev,
218 struct device_attribute *attr, char *buf)
219{
220 struct hd_struct *p = dev_to_part(dev);
221
222 return sprintf(buf, "%d\n", p->partno);
223}
224
225static ssize_t part_start_show(struct device *dev,
226 struct device_attribute *attr, char *buf)
227{
228 struct hd_struct *p = dev_to_part(dev);
229
230 return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
231}
232
233ssize_t part_size_show(struct device *dev,
234 struct device_attribute *attr, char *buf)
235{
236 struct hd_struct *p = dev_to_part(dev);
237 return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
238}
239
240static ssize_t part_ro_show(struct device *dev,
241 struct device_attribute *attr, char *buf)
242{
243 struct hd_struct *p = dev_to_part(dev);
244 return sprintf(buf, "%d\n", p->policy ? 1 : 0);
245}
246
247static ssize_t part_alignment_offset_show(struct device *dev,
248 struct device_attribute *attr, char *buf)
249{
250 struct hd_struct *p = dev_to_part(dev);
251 return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
252}
253
254static ssize_t part_discard_alignment_show(struct device *dev,
255 struct device_attribute *attr, char *buf)
256{
257 struct hd_struct *p = dev_to_part(dev);
258 return sprintf(buf, "%u\n", p->discard_alignment);
259}
260
261ssize_t part_stat_show(struct device *dev,
262 struct device_attribute *attr, char *buf)
263{
264 struct hd_struct *p = dev_to_part(dev);
265 int cpu;
266
267 cpu = part_stat_lock();
268 part_round_stats(cpu, p);
269 part_stat_unlock();
270 return sprintf(buf,
271 "%8lu %8lu %8llu %8u "
272 "%8lu %8lu %8llu %8u "
273 "%8u %8u %8u"
274 "\n",
275 part_stat_read(p, ios[READ]),
276 part_stat_read(p, merges[READ]),
277 (unsigned long long)part_stat_read(p, sectors[READ]),
278 jiffies_to_msecs(part_stat_read(p, ticks[READ])),
279 part_stat_read(p, ios[WRITE]),
280 part_stat_read(p, merges[WRITE]),
281 (unsigned long long)part_stat_read(p, sectors[WRITE]),
282 jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
283 part_in_flight(p),
284 jiffies_to_msecs(part_stat_read(p, io_ticks)),
285 jiffies_to_msecs(part_stat_read(p, time_in_queue)));
286}
287
288ssize_t part_inflight_show(struct device *dev,
289 struct device_attribute *attr, char *buf)
290{
291 struct hd_struct *p = dev_to_part(dev);
292
293 return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]),
294 atomic_read(&p->in_flight[1]));
295}
296
297#ifdef CONFIG_FAIL_MAKE_REQUEST
298ssize_t part_fail_show(struct device *dev,
299 struct device_attribute *attr, char *buf)
300{
301 struct hd_struct *p = dev_to_part(dev);
302
303 return sprintf(buf, "%d\n", p->make_it_fail);
304}
305
306ssize_t part_fail_store(struct device *dev,
307 struct device_attribute *attr,
308 const char *buf, size_t count)
309{
310 struct hd_struct *p = dev_to_part(dev);
311 int i;
312
313 if (count > 0 && sscanf(buf, "%d", &i) > 0)
314 p->make_it_fail = (i == 0) ? 0 : 1;
315
316 return count;
317}
318#endif
319
320static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
321static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
322static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
323static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL);
324static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
325static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
326 NULL);
327static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
328static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
329#ifdef CONFIG_FAIL_MAKE_REQUEST
330static struct device_attribute dev_attr_fail =
331 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
332#endif
333
334static struct attribute *part_attrs[] = {
335 &dev_attr_partition.attr,
336 &dev_attr_start.attr,
337 &dev_attr_size.attr,
338 &dev_attr_ro.attr,
339 &dev_attr_alignment_offset.attr,
340 &dev_attr_discard_alignment.attr,
341 &dev_attr_stat.attr,
342 &dev_attr_inflight.attr,
343#ifdef CONFIG_FAIL_MAKE_REQUEST
344 &dev_attr_fail.attr,
345#endif
346 NULL
347};
348
349static struct attribute_group part_attr_group = {
350 .attrs = part_attrs,
351};
352
353static const struct attribute_group *part_attr_groups[] = {
354 &part_attr_group,
355#ifdef CONFIG_BLK_DEV_IO_TRACE
356 &blk_trace_attr_group,
357#endif
358 NULL
359};
360
361static void part_release(struct device *dev)
362{
363 struct hd_struct *p = dev_to_part(dev);
364 free_part_stats(p);
365 free_part_info(p);
366 kfree(p);
367}
368
369static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
370{
371 struct hd_struct *part = dev_to_part(dev);
372
373 add_uevent_var(env, "PARTN=%u", part->partno);
374 if (part->info && part->info->volname[0])
375 add_uevent_var(env, "PARTNAME=%s", part->info->volname);
376 return 0;
377}
378
379struct device_type part_type = {
380 .name = "partition",
381 .groups = part_attr_groups,
382 .release = part_release,
383 .uevent = part_uevent,
384};
385
386static void delete_partition_rcu_cb(struct rcu_head *head)
387{
388 struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
389
390 part->start_sect = 0;
391 part->nr_sects = 0;
392 part_stat_set_all(part, 0);
393 put_device(part_to_dev(part));
394}
395
396void __delete_partition(struct hd_struct *part)
397{
398 call_rcu(&part->rcu_head, delete_partition_rcu_cb);
399}
400
401void delete_partition(struct gendisk *disk, int partno)
402{
403 struct disk_part_tbl *ptbl = disk->part_tbl;
404 struct hd_struct *part;
405
406 if (partno >= ptbl->len)
407 return;
408
409 part = ptbl->part[partno];
410 if (!part)
411 return;
412
413 blk_free_devt(part_devt(part));
414 rcu_assign_pointer(ptbl->part[partno], NULL);
415 rcu_assign_pointer(ptbl->last_lookup, NULL);
416 kobject_put(part->holder_dir);
417 device_del(part_to_dev(part));
418
419 hd_struct_put(part);
420}
421
422static ssize_t whole_disk_show(struct device *dev,
423 struct device_attribute *attr, char *buf)
424{
425 return 0;
426}
427static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
428 whole_disk_show, NULL);
429
430struct hd_struct *add_partition(struct gendisk *disk, int partno,
431 sector_t start, sector_t len, int flags,
432 struct partition_meta_info *info)
433{
434 struct hd_struct *p;
435 dev_t devt = MKDEV(0, 0);
436 struct device *ddev = disk_to_dev(disk);
437 struct device *pdev;
438 struct disk_part_tbl *ptbl;
439 const char *dname;
440 int err;
441
442 err = disk_expand_part_tbl(disk, partno);
443 if (err)
444 return ERR_PTR(err);
445 ptbl = disk->part_tbl;
446
447 if (ptbl->part[partno])
448 return ERR_PTR(-EBUSY);
449
450 p = kzalloc(sizeof(*p), GFP_KERNEL);
451 if (!p)
452 return ERR_PTR(-EBUSY);
453
454 if (!init_part_stats(p)) {
455 err = -ENOMEM;
456 goto out_free;
457 }
458 pdev = part_to_dev(p);
459
460 p->start_sect = start;
461 p->alignment_offset =
462 queue_limit_alignment_offset(&disk->queue->limits, start);
463 p->discard_alignment =
464 queue_limit_discard_alignment(&disk->queue->limits, start);
465 p->nr_sects = len;
466 p->partno = partno;
467 p->policy = get_disk_ro(disk);
468
469 if (info) {
470 struct partition_meta_info *pinfo = alloc_part_info(disk);
471 if (!pinfo)
472 goto out_free_stats;
473 memcpy(pinfo, info, sizeof(*info));
474 p->info = pinfo;
475 }
476
477 dname = dev_name(ddev);
478 if (isdigit(dname[strlen(dname) - 1]))
479 dev_set_name(pdev, "%sp%d", dname, partno);
480 else
481 dev_set_name(pdev, "%s%d", dname, partno);
482
483 device_initialize(pdev);
484 pdev->class = &block_class;
485 pdev->type = &part_type;
486 pdev->parent = ddev;
487
488 err = blk_alloc_devt(p, &devt);
489 if (err)
490 goto out_free_info;
491 pdev->devt = devt;
492
493 /* delay uevent until 'holders' subdir is created */
494 dev_set_uevent_suppress(pdev, 1);
495 err = device_add(pdev);
496 if (err)
497 goto out_put;
498
499 err = -ENOMEM;
500 p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
501 if (!p->holder_dir)
502 goto out_del;
503
504 dev_set_uevent_suppress(pdev, 0);
505 if (flags & ADDPART_FLAG_WHOLEDISK) {
506 err = device_create_file(pdev, &dev_attr_whole_disk);
507 if (err)
508 goto out_del;
509 }
510
511 /* everything is up and running, commence */
512 rcu_assign_pointer(ptbl->part[partno], p);
513
514 /* suppress uevent if the disk suppresses it */
515 if (!dev_get_uevent_suppress(ddev))
516 kobject_uevent(&pdev->kobj, KOBJ_ADD);
517
518 hd_ref_init(p);
519 return p;
520
521out_free_info:
522 free_part_info(p);
523out_free_stats:
524 free_part_stats(p);
525out_free:
526 kfree(p);
527 return ERR_PTR(err);
528out_del:
529 kobject_put(p->holder_dir);
530 device_del(pdev);
531out_put:
532 put_device(pdev);
533 blk_free_devt(devt);
534 return ERR_PTR(err);
535}
536
537static bool disk_unlock_native_capacity(struct gendisk *disk)
538{
539 const struct block_device_operations *bdops = disk->fops;
540
541 if (bdops->unlock_native_capacity &&
542 !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) {
543 printk(KERN_CONT "enabling native capacity\n");
544 bdops->unlock_native_capacity(disk);
545 disk->flags |= GENHD_FL_NATIVE_CAPACITY;
546 return true;
547 } else {
548 printk(KERN_CONT "truncated\n");
549 return false;
550 }
551}
552
553int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
554{
555 struct parsed_partitions *state = NULL;
556 struct disk_part_iter piter;
557 struct hd_struct *part;
558 int p, highest, res;
559rescan:
560 if (state && !IS_ERR(state)) {
561 kfree(state);
562 state = NULL;
563 }
564
565 if (bdev->bd_part_count)
566 return -EBUSY;
567 res = invalidate_partition(disk, 0);
568 if (res)
569 return res;
570
571 disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
572 while ((part = disk_part_iter_next(&piter)))
573 delete_partition(disk, part->partno);
574 disk_part_iter_exit(&piter);
575
576 if (disk->fops->revalidate_disk)
577 disk->fops->revalidate_disk(disk);
578 check_disk_size_change(disk, bdev);
579 bdev->bd_invalidated = 0;
580 if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
581 return 0;
582 if (IS_ERR(state)) {
583 /*
584 * I/O error reading the partition table. If any
585 * partition code tried to read beyond EOD, retry
586 * after unlocking native capacity.
587 */
588 if (PTR_ERR(state) == -ENOSPC) {
589 printk(KERN_WARNING "%s: partition table beyond EOD, ",
590 disk->disk_name);
591 if (disk_unlock_native_capacity(disk))
592 goto rescan;
593 }
594 return -EIO;
595 }
596 /*
597 * If any partition code tried to read beyond EOD, try
598 * unlocking native capacity even if partition table is
599 * successfully read as we could be missing some partitions.
600 */
601 if (state->access_beyond_eod) {
602 printk(KERN_WARNING
603 "%s: partition table partially beyond EOD, ",
604 disk->disk_name);
605 if (disk_unlock_native_capacity(disk))
606 goto rescan;
607 }
608
609 /* tell userspace that the media / partition table may have changed */
610 kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
611
612 /* Detect the highest partition number and preallocate
613 * disk->part_tbl. This is an optimization and not strictly
614 * necessary.
615 */
616 for (p = 1, highest = 0; p < state->limit; p++)
617 if (state->parts[p].size)
618 highest = p;
619
620 disk_expand_part_tbl(disk, highest);
621
622 /* add partitions */
623 for (p = 1; p < state->limit; p++) {
624 sector_t size, from;
625 struct partition_meta_info *info = NULL;
626
627 size = state->parts[p].size;
628 if (!size)
629 continue;
630
631 from = state->parts[p].from;
632 if (from >= get_capacity(disk)) {
633 printk(KERN_WARNING
634 "%s: p%d start %llu is beyond EOD, ",
635 disk->disk_name, p, (unsigned long long) from);
636 if (disk_unlock_native_capacity(disk))
637 goto rescan;
638 continue;
639 }
640
641 if (from + size > get_capacity(disk)) {
642 printk(KERN_WARNING
643 "%s: p%d size %llu extends beyond EOD, ",
644 disk->disk_name, p, (unsigned long long) size);
645
646 if (disk_unlock_native_capacity(disk)) {
647 /* free state and restart */
648 goto rescan;
649 } else {
650 /*
651 * we can not ignore partitions of broken tables
652 * created by for example camera firmware, but
653 * we limit them to the end of the disk to avoid
654 * creating invalid block devices
655 */
656 size = get_capacity(disk) - from;
657 }
658 }
659
660 if (state->parts[p].has_info)
661 info = &state->parts[p].info;
662 part = add_partition(disk, p, from, size,
663 state->parts[p].flags,
664 &state->parts[p].info);
665 if (IS_ERR(part)) {
666 printk(KERN_ERR " %s: p%d could not be added: %ld\n",
667 disk->disk_name, p, -PTR_ERR(part));
668 continue;
669 }
670#ifdef CONFIG_BLK_DEV_MD
671 if (state->parts[p].flags & ADDPART_FLAG_RAID)
672 md_autodetect_dev(part_to_dev(part)->devt);
673#endif
674 }
675 kfree(state);
676 return 0;
677}
678
679unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
680{
681 struct address_space *mapping = bdev->bd_inode->i_mapping;
682 struct page *page;
683
684 page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
685 NULL);
686 if (!IS_ERR(page)) {
687 if (PageError(page))
688 goto fail;
689 p->v = page;
690 return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9);
691fail:
692 page_cache_release(page);
693 }
694 p->v = NULL;
695 return NULL;
696}
697
698EXPORT_SYMBOL(read_dev_sector);
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
new file mode 100644
index 00000000000..d68bf4dc3bc
--- /dev/null
+++ b/fs/partitions/check.h
@@ -0,0 +1,49 @@
1#include <linux/pagemap.h>
2#include <linux/blkdev.h>
3#include <linux/genhd.h>
4
5/*
6 * add_gd_partition adds a partitions details to the devices partition
7 * description.
8 */
9struct parsed_partitions {
10 struct block_device *bdev;
11 char name[BDEVNAME_SIZE];
12 struct {
13 sector_t from;
14 sector_t size;
15 int flags;
16 bool has_info;
17 struct partition_meta_info info;
18 } parts[DISK_MAX_PARTS];
19 int next;
20 int limit;
21 bool access_beyond_eod;
22 char *pp_buf;
23};
24
25static inline void *read_part_sector(struct parsed_partitions *state,
26 sector_t n, Sector *p)
27{
28 if (n >= get_capacity(state->bdev->bd_disk)) {
29 state->access_beyond_eod = true;
30 return NULL;
31 }
32 return read_dev_sector(state->bdev, n, p);
33}
34
35static inline void
36put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
37{
38 if (n < p->limit) {
39 char tmp[1 + BDEVNAME_SIZE + 10 + 1];
40
41 p->parts[n].from = from;
42 p->parts[n].size = size;
43 snprintf(tmp, sizeof(tmp), " %s%d", p->name, n);
44 strlcat(p->pp_buf, tmp, PAGE_SIZE);
45 }
46}
47
48extern int warn_no_part;
49
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
new file mode 100644
index 00000000000..30546cc8d03
--- /dev/null
+++ b/fs/partitions/efi.c
@@ -0,0 +1,686 @@
1/************************************************************
2 * EFI GUID Partition Table handling
3 *
4 * http://www.uefi.org/specs/
5 * http://www.intel.com/technology/efi/
6 *
7 * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
8 * Copyright 2000,2001,2002,2004 Dell Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) 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; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 *
25 * TODO:
26 *
27 * Changelog:
28 * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
29 * - test for valid PMBR and valid PGPT before ever reading
30 * AGPT, allow override with 'gpt' kernel command line option.
31 * - check for first/last_usable_lba outside of size of disk
32 *
33 * Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
34 * - Ported to 2.5.7-pre1 and 2.5.7-dj2
35 * - Applied patch to avoid fault in alternate header handling
36 * - cleaned up find_valid_gpt
37 * - On-disk structure and copy in memory is *always* LE now -
38 * swab fields as needed
39 * - remove print_gpt_header()
40 * - only use first max_p partition entries, to keep the kernel minor number
41 * and partition numbers tied.
42 *
43 * Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com>
44 * - Removed __PRIPTR_PREFIX - not being used
45 *
46 * Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
47 * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
48 *
49 * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
50 * - Added compare_gpts().
51 * - moved le_efi_guid_to_cpus() back into this file. GPT is the only
52 * thing that keeps EFI GUIDs on disk.
53 * - Changed gpt structure names and members to be simpler and more Linux-like.
54 *
55 * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
56 * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
57 *
58 * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
59 * - Changed function comments to DocBook style per Andreas Dilger suggestion.
60 *
61 * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
62 * - Change read_lba() to use the page cache per Al Viro's work.
63 * - print u64s properly on all architectures
64 * - fixed debug_printk(), now Dprintk()
65 *
66 * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
67 * - Style cleanups
68 * - made most functions static
69 * - Endianness addition
70 * - remove test for second alternate header, as it's not per spec,
71 * and is unnecessary. There's now a method to read/write the last
72 * sector of an odd-sized disk from user space. No tools have ever
73 * been released which used this code, so it's effectively dead.
74 * - Per Asit Mallick of Intel, added a test for a valid PMBR.
75 * - Added kernel command line option 'gpt' to override valid PMBR test.
76 *
77 * Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
78 * - added devfs volume UUID support (/dev/volumes/uuids) for
79 * mounting file systems by the partition GUID.
80 *
81 * Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com>
82 * - Moved crc32() to linux/lib, added efi_crc32().
83 *
84 * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
85 * - Replaced Intel's CRC32 function with an equivalent
86 * non-license-restricted version.
87 *
88 * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
89 * - Fixed the last_lba() call to return the proper last block
90 *
91 * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
92 * - Thanks to Andries Brouwer for his debugging assistance.
93 * - Code works, detects all the partitions.
94 *
95 ************************************************************/
96#include <linux/crc32.h>
97#include <linux/ctype.h>
98#include <linux/math64.h>
99#include <linux/slab.h>
100#include "check.h"
101#include "efi.h"
102
103/* This allows a kernel command line option 'gpt' to override
104 * the test for invalid PMBR. Not __initdata because reloading
105 * the partition tables happens after init too.
106 */
107static int force_gpt;
108static u64 force_gpt_sector;
109static int __init
110force_gpt_fn(char *str)
111{
112 force_gpt = 1;
113 return 1;
114}
115__setup("gpt", force_gpt_fn);
116
117static int __init force_gpt_sector_fn(char *str)
118{
119 force_gpt_sector = simple_strtoull(str, NULL, 0);
120 return 1;
121}
122__setup("gpt_sector=", force_gpt_sector_fn);
123
124
125/**
126 * efi_crc32() - EFI version of crc32 function
127 * @buf: buffer to calculate crc32 of
128 * @len - length of buf
129 *
130 * Description: Returns EFI-style CRC32 value for @buf
131 *
132 * This function uses the little endian Ethernet polynomial
133 * but seeds the function with ~0, and xor's with ~0 at the end.
134 * Note, the EFI Specification, v1.02, has a reference to
135 * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
136 */
137static inline u32
138efi_crc32(const void *buf, unsigned long len)
139{
140 return (crc32(~0L, buf, len) ^ ~0L);
141}
142
143/**
144 * last_lba(): return number of last logical block of device
145 * @bdev: block device
146 *
147 * Description: Returns last LBA value on success, 0 on error.
148 * This is stored (by sd and ide-geometry) in
149 * the part[0] entry for this disk, and is the number of
150 * physical sectors available on the disk.
151 */
152static u64 last_lba(struct block_device *bdev)
153{
154 if (!bdev || !bdev->bd_inode)
155 return 0;
156 return div_u64(bdev->bd_inode->i_size,
157 bdev_logical_block_size(bdev)) - 1ULL;
158}
159
160static inline int
161pmbr_part_valid(struct partition *part)
162{
163 if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
164 le32_to_cpu(part->start_sect) == 1UL)
165 return 1;
166 return 0;
167}
168
169/**
170 * is_pmbr_valid(): test Protective MBR for validity
171 * @mbr: pointer to a legacy mbr structure
172 *
173 * Description: Returns 1 if PMBR is valid, 0 otherwise.
174 * Validity depends on two things:
175 * 1) MSDOS signature is in the last two bytes of the MBR
176 * 2) One partition of type 0xEE is found
177 */
178static int
179is_pmbr_valid(legacy_mbr *mbr)
180{
181 int i;
182 if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
183 return 0;
184 for (i = 0; i < 4; i++)
185 if (pmbr_part_valid(&mbr->partition_record[i]))
186 return 1;
187 return 0;
188}
189
190/**
191 * read_lba(): Read bytes from disk, starting at given LBA
192 * @state
193 * @lba
194 * @buffer
195 * @size_t
196 *
197 * Description: Reads @count bytes from @state->bdev into @buffer.
198 * Returns number of bytes read on success, 0 on error.
199 */
200static size_t read_lba(struct parsed_partitions *state,
201 u64 lba, u8 *buffer, size_t count)
202{
203 size_t totalreadcount = 0;
204 struct block_device *bdev = state->bdev;
205 sector_t n = lba * (bdev_logical_block_size(bdev) / 512);
206
207 if (!buffer || lba > last_lba(bdev))
208 return 0;
209
210 while (count) {
211 int copied = 512;
212 Sector sect;
213 unsigned char *data = read_part_sector(state, n++, &sect);
214 if (!data)
215 break;
216 if (copied > count)
217 copied = count;
218 memcpy(buffer, data, copied);
219 put_dev_sector(sect);
220 buffer += copied;
221 totalreadcount +=copied;
222 count -= copied;
223 }
224 return totalreadcount;
225}
226
227/**
228 * alloc_read_gpt_entries(): reads partition entries from disk
229 * @state
230 * @gpt - GPT header
231 *
232 * Description: Returns ptes on success, NULL on error.
233 * Allocates space for PTEs based on information found in @gpt.
234 * Notes: remember to free pte when you're done!
235 */
236static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state,
237 gpt_header *gpt)
238{
239 size_t count;
240 gpt_entry *pte;
241
242 if (!gpt)
243 return NULL;
244
245 count = le32_to_cpu(gpt->num_partition_entries) *
246 le32_to_cpu(gpt->sizeof_partition_entry);
247 if (!count)
248 return NULL;
249 pte = kzalloc(count, GFP_KERNEL);
250 if (!pte)
251 return NULL;
252
253 if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba),
254 (u8 *) pte,
255 count) < count) {
256 kfree(pte);
257 pte=NULL;
258 return NULL;
259 }
260 return pte;
261}
262
263/**
264 * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
265 * @state
266 * @lba is the Logical Block Address of the partition table
267 *
268 * Description: returns GPT header on success, NULL on error. Allocates
269 * and fills a GPT header starting at @ from @state->bdev.
270 * Note: remember to free gpt when finished with it.
271 */
272static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state,
273 u64 lba)
274{
275 gpt_header *gpt;
276 unsigned ssz = bdev_logical_block_size(state->bdev);
277
278 gpt = kzalloc(ssz, GFP_KERNEL);
279 if (!gpt)
280 return NULL;
281
282 if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) {
283 kfree(gpt);
284 gpt=NULL;
285 return NULL;
286 }
287
288 return gpt;
289}
290
291/**
292 * is_gpt_valid() - tests one GPT header and PTEs for validity
293 * @state
294 * @lba is the logical block address of the GPT header to test
295 * @gpt is a GPT header ptr, filled on return.
296 * @ptes is a PTEs ptr, filled on return.
297 *
298 * Description: returns 1 if valid, 0 on error.
299 * If valid, returns pointers to newly allocated GPT header and PTEs.
300 */
301static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
302 gpt_header **gpt, gpt_entry **ptes)
303{
304 u32 crc, origcrc;
305 u64 lastlba;
306
307 if (!ptes)
308 return 0;
309 if (!(*gpt = alloc_read_gpt_header(state, lba)))
310 return 0;
311
312 /* Check the GUID Partition Table signature */
313 if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
314 pr_debug("GUID Partition Table Header signature is wrong:"
315 "%lld != %lld\n",
316 (unsigned long long)le64_to_cpu((*gpt)->signature),
317 (unsigned long long)GPT_HEADER_SIGNATURE);
318 goto fail;
319 }
320
321 /* Check the GUID Partition Table header size */
322 if (le32_to_cpu((*gpt)->header_size) >
323 bdev_logical_block_size(state->bdev)) {
324 pr_debug("GUID Partition Table Header size is wrong: %u > %u\n",
325 le32_to_cpu((*gpt)->header_size),
326 bdev_logical_block_size(state->bdev));
327 goto fail;
328 }
329
330 /* Check the GUID Partition Table CRC */
331 origcrc = le32_to_cpu((*gpt)->header_crc32);
332 (*gpt)->header_crc32 = 0;
333 crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
334
335 if (crc != origcrc) {
336 pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n",
337 crc, origcrc);
338 goto fail;
339 }
340 (*gpt)->header_crc32 = cpu_to_le32(origcrc);
341
342 /* Check that the my_lba entry points to the LBA that contains
343 * the GUID Partition Table */
344 if (le64_to_cpu((*gpt)->my_lba) != lba) {
345 pr_debug("GPT my_lba incorrect: %lld != %lld\n",
346 (unsigned long long)le64_to_cpu((*gpt)->my_lba),
347 (unsigned long long)lba);
348 goto fail;
349 }
350
351 /* Check the first_usable_lba and last_usable_lba are
352 * within the disk.
353 */
354 lastlba = last_lba(state->bdev);
355 if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
356 pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n",
357 (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
358 (unsigned long long)lastlba);
359 goto fail;
360 }
361 if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
362 pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
363 (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
364 (unsigned long long)lastlba);
365 goto fail;
366 }
367
368 /* Check that sizeof_partition_entry has the correct value */
369 if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
370 pr_debug("GUID Partitition Entry Size check failed.\n");
371 goto fail;
372 }
373
374 if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
375 goto fail;
376
377 /* Check the GUID Partition Entry Array CRC */
378 crc = efi_crc32((const unsigned char *) (*ptes),
379 le32_to_cpu((*gpt)->num_partition_entries) *
380 le32_to_cpu((*gpt)->sizeof_partition_entry));
381
382 if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
383 pr_debug("GUID Partitition Entry Array CRC check failed.\n");
384 goto fail_ptes;
385 }
386
387 /* We're done, all's well */
388 return 1;
389
390 fail_ptes:
391 kfree(*ptes);
392 *ptes = NULL;
393 fail:
394 kfree(*gpt);
395 *gpt = NULL;
396 return 0;
397}
398
399/**
400 * is_pte_valid() - tests one PTE for validity
401 * @pte is the pte to check
402 * @lastlba is last lba of the disk
403 *
404 * Description: returns 1 if valid, 0 on error.
405 */
406static inline int
407is_pte_valid(const gpt_entry *pte, const u64 lastlba)
408{
409 if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
410 le64_to_cpu(pte->starting_lba) > lastlba ||
411 le64_to_cpu(pte->ending_lba) > lastlba)
412 return 0;
413 return 1;
414}
415
416/**
417 * compare_gpts() - Search disk for valid GPT headers and PTEs
418 * @pgpt is the primary GPT header
419 * @agpt is the alternate GPT header
420 * @lastlba is the last LBA number
421 * Description: Returns nothing. Sanity checks pgpt and agpt fields
422 * and prints warnings on discrepancies.
423 *
424 */
425static void
426compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
427{
428 int error_found = 0;
429 if (!pgpt || !agpt)
430 return;
431 if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
432 printk(KERN_WARNING
433 "GPT:Primary header LBA != Alt. header alternate_lba\n");
434 printk(KERN_WARNING "GPT:%lld != %lld\n",
435 (unsigned long long)le64_to_cpu(pgpt->my_lba),
436 (unsigned long long)le64_to_cpu(agpt->alternate_lba));
437 error_found++;
438 }
439 if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
440 printk(KERN_WARNING
441 "GPT:Primary header alternate_lba != Alt. header my_lba\n");
442 printk(KERN_WARNING "GPT:%lld != %lld\n",
443 (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
444 (unsigned long long)le64_to_cpu(agpt->my_lba));
445 error_found++;
446 }
447 if (le64_to_cpu(pgpt->first_usable_lba) !=
448 le64_to_cpu(agpt->first_usable_lba)) {
449 printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
450 printk(KERN_WARNING "GPT:%lld != %lld\n",
451 (unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
452 (unsigned long long)le64_to_cpu(agpt->first_usable_lba));
453 error_found++;
454 }
455 if (le64_to_cpu(pgpt->last_usable_lba) !=
456 le64_to_cpu(agpt->last_usable_lba)) {
457 printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
458 printk(KERN_WARNING "GPT:%lld != %lld\n",
459 (unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
460 (unsigned long long)le64_to_cpu(agpt->last_usable_lba));
461 error_found++;
462 }
463 if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
464 printk(KERN_WARNING "GPT:disk_guids don't match.\n");
465 error_found++;
466 }
467 if (le32_to_cpu(pgpt->num_partition_entries) !=
468 le32_to_cpu(agpt->num_partition_entries)) {
469 printk(KERN_WARNING "GPT:num_partition_entries don't match: "
470 "0x%x != 0x%x\n",
471 le32_to_cpu(pgpt->num_partition_entries),
472 le32_to_cpu(agpt->num_partition_entries));
473 error_found++;
474 }
475 if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
476 le32_to_cpu(agpt->sizeof_partition_entry)) {
477 printk(KERN_WARNING
478 "GPT:sizeof_partition_entry values don't match: "
479 "0x%x != 0x%x\n",
480 le32_to_cpu(pgpt->sizeof_partition_entry),
481 le32_to_cpu(agpt->sizeof_partition_entry));
482 error_found++;
483 }
484 if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
485 le32_to_cpu(agpt->partition_entry_array_crc32)) {
486 printk(KERN_WARNING
487 "GPT:partition_entry_array_crc32 values don't match: "
488 "0x%x != 0x%x\n",
489 le32_to_cpu(pgpt->partition_entry_array_crc32),
490 le32_to_cpu(agpt->partition_entry_array_crc32));
491 error_found++;
492 }
493 if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
494 printk(KERN_WARNING
495 "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
496 printk(KERN_WARNING "GPT:%lld != %lld\n",
497 (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
498 (unsigned long long)lastlba);
499 error_found++;
500 }
501
502 if (le64_to_cpu(agpt->my_lba) != lastlba) {
503 printk(KERN_WARNING
504 "GPT:Alternate GPT header not at the end of the disk.\n");
505 printk(KERN_WARNING "GPT:%lld != %lld\n",
506 (unsigned long long)le64_to_cpu(agpt->my_lba),
507 (unsigned long long)lastlba);
508 error_found++;
509 }
510
511 if (error_found)
512 printk(KERN_WARNING
513 "GPT: Use GNU Parted to correct GPT errors.\n");
514 return;
515}
516
517/**
518 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
519 * @state
520 * @gpt is a GPT header ptr, filled on return.
521 * @ptes is a PTEs ptr, filled on return.
522 * Description: Returns 1 if valid, 0 on error.
523 * If valid, returns pointers to newly allocated GPT header and PTEs.
524 * Validity depends on PMBR being valid (or being overridden by the
525 * 'gpt' kernel command line option) and finding either the Primary
526 * GPT header and PTEs valid, or the Alternate GPT header and PTEs
527 * valid. If the Primary GPT header is not valid, the Alternate GPT header
528 * is not checked unless the 'gpt' kernel command line option is passed.
529 * This protects against devices which misreport their size, and forces
530 * the user to decide to use the Alternate GPT.
531 */
532static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
533 gpt_entry **ptes)
534{
535 int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
536 gpt_header *pgpt = NULL, *agpt = NULL;
537 gpt_entry *pptes = NULL, *aptes = NULL;
538 legacy_mbr *legacymbr;
539 u64 lastlba;
540
541 if (!ptes)
542 return 0;
543
544 lastlba = last_lba(state->bdev);
545 if (!force_gpt) {
546 /* This will be added to the EFI Spec. per Intel after v1.02. */
547 legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
548 if (legacymbr) {
549 read_lba(state, 0, (u8 *) legacymbr,
550 sizeof (*legacymbr));
551 good_pmbr = is_pmbr_valid(legacymbr);
552 kfree(legacymbr);
553 }
554 if (!good_pmbr)
555 goto fail;
556 }
557
558 good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
559 &pgpt, &pptes);
560 if (good_pgpt)
561 good_agpt = is_gpt_valid(state,
562 le64_to_cpu(pgpt->alternate_lba),
563 &agpt, &aptes);
564 if (!good_agpt && force_gpt)
565 good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
566
567 if (!good_agpt && force_gpt && force_gpt_sector)
568 good_agpt = is_gpt_valid(state, force_gpt_sector, &agpt, &aptes);
569
570 /* The obviously unsuccessful case */
571 if (!good_pgpt && !good_agpt)
572 goto fail;
573
574 compare_gpts(pgpt, agpt, lastlba);
575
576 /* The good cases */
577 if (good_pgpt) {
578 *gpt = pgpt;
579 *ptes = pptes;
580 kfree(agpt);
581 kfree(aptes);
582 if (!good_agpt) {
583 printk(KERN_WARNING
584 "Alternate GPT is invalid, "
585 "using primary GPT.\n");
586 }
587 return 1;
588 }
589 else if (good_agpt) {
590 *gpt = agpt;
591 *ptes = aptes;
592 kfree(pgpt);
593 kfree(pptes);
594 printk(KERN_WARNING
595 "Primary GPT is invalid, using alternate GPT.\n");
596 return 1;
597 }
598
599 fail:
600 kfree(pgpt);
601 kfree(agpt);
602 kfree(pptes);
603 kfree(aptes);
604 *gpt = NULL;
605 *ptes = NULL;
606 return 0;
607}
608
609/**
610 * efi_partition(struct parsed_partitions *state)
611 * @state
612 *
613 * Description: called from check.c, if the disk contains GPT
614 * partitions, sets up partition entries in the kernel.
615 *
616 * If the first block on the disk is a legacy MBR,
617 * it will get handled by msdos_partition().
618 * If it's a Protective MBR, we'll handle it here.
619 *
620 * We do not create a Linux partition for GPT, but
621 * only for the actual data partitions.
622 * Returns:
623 * -1 if unable to read the partition table
624 * 0 if this isn't our partition table
625 * 1 if successful
626 *
627 */
628int efi_partition(struct parsed_partitions *state)
629{
630 gpt_header *gpt = NULL;
631 gpt_entry *ptes = NULL;
632 u32 i;
633 unsigned ssz = bdev_logical_block_size(state->bdev) / 512;
634 u8 unparsed_guid[37];
635
636 if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) {
637 kfree(gpt);
638 kfree(ptes);
639 return 0;
640 }
641
642 pr_debug("GUID Partition Table is valid! Yea!\n");
643
644 for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
645 struct partition_meta_info *info;
646 unsigned label_count = 0;
647 unsigned label_max;
648 u64 start = le64_to_cpu(ptes[i].starting_lba);
649 u64 size = le64_to_cpu(ptes[i].ending_lba) -
650 le64_to_cpu(ptes[i].starting_lba) + 1ULL;
651
652 if (!is_pte_valid(&ptes[i], last_lba(state->bdev)))
653 continue;
654
655 put_partition(state, i+1, start * ssz, size * ssz);
656
657 /* If this is a RAID volume, tell md */
658 if (!efi_guidcmp(ptes[i].partition_type_guid,
659 PARTITION_LINUX_RAID_GUID))
660 state->parts[i + 1].flags = ADDPART_FLAG_RAID;
661
662 info = &state->parts[i + 1].info;
663 /* Instead of doing a manual swap to big endian, reuse the
664 * common ASCII hex format as the interim.
665 */
666 efi_guid_unparse(&ptes[i].unique_partition_guid, unparsed_guid);
667 part_pack_uuid(unparsed_guid, info->uuid);
668
669 /* Naively convert UTF16-LE to 7 bits. */
670 label_max = min(sizeof(info->volname) - 1,
671 sizeof(ptes[i].partition_name));
672 info->volname[label_max] = 0;
673 while (label_count < label_max) {
674 u8 c = ptes[i].partition_name[label_count] & 0xff;
675 if (c && !isprint(c))
676 c = '!';
677 info->volname[label_count] = c;
678 label_count++;
679 }
680 state->parts[i + 1].has_info = true;
681 }
682 kfree(ptes);
683 kfree(gpt);
684 strlcat(state->pp_buf, "\n", PAGE_SIZE);
685 return 1;
686}
diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h
new file mode 100644
index 00000000000..b69ab729558
--- /dev/null
+++ b/fs/partitions/efi.h
@@ -0,0 +1,134 @@
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/fs.h>
30#include <linux/genhd.h>
31#include <linux/kernel.h>
32#include <linux/major.h>
33#include <linux/string.h>
34#include <linux/efi.h>
35
36#define MSDOS_MBR_SIGNATURE 0xaa55
37#define EFI_PMBR_OSTYPE_EFI 0xEF
38#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
39
40#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
41#define GPT_HEADER_REVISION_V1 0x00010000
42#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
43
44#define PARTITION_SYSTEM_GUID \
45 EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
46 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
47#define LEGACY_MBR_PARTITION_GUID \
48 EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
49 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
50#define PARTITION_MSFT_RESERVED_GUID \
51 EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
52 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
53#define PARTITION_BASIC_DATA_GUID \
54 EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
55 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
56#define PARTITION_LINUX_RAID_GUID \
57 EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
58 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
59#define PARTITION_LINUX_SWAP_GUID \
60 EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
61 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
62#define PARTITION_LINUX_LVM_GUID \
63 EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
64 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
65
66typedef struct _gpt_header {
67 __le64 signature;
68 __le32 revision;
69 __le32 header_size;
70 __le32 header_crc32;
71 __le32 reserved1;
72 __le64 my_lba;
73 __le64 alternate_lba;
74 __le64 first_usable_lba;
75 __le64 last_usable_lba;
76 efi_guid_t disk_guid;
77 __le64 partition_entry_lba;
78 __le32 num_partition_entries;
79 __le32 sizeof_partition_entry;
80 __le32 partition_entry_array_crc32;
81
82 /* The rest of the logical block is reserved by UEFI and must be zero.
83 * EFI standard handles this by:
84 *
85 * uint8_t reserved2[ BlockSize - 92 ];
86 */
87} __attribute__ ((packed)) gpt_header;
88
89typedef struct _gpt_entry_attributes {
90 u64 required_to_function:1;
91 u64 reserved:47;
92 u64 type_guid_specific:16;
93} __attribute__ ((packed)) gpt_entry_attributes;
94
95typedef struct _gpt_entry {
96 efi_guid_t partition_type_guid;
97 efi_guid_t unique_partition_guid;
98 __le64 starting_lba;
99 __le64 ending_lba;
100 gpt_entry_attributes attributes;
101 efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
102} __attribute__ ((packed)) gpt_entry;
103
104typedef struct _legacy_mbr {
105 u8 boot_code[440];
106 __le32 unique_mbr_signature;
107 __le16 unknown;
108 struct partition partition_record[4];
109 __le16 signature;
110} __attribute__ ((packed)) legacy_mbr;
111
112/* Functions */
113extern int efi_partition(struct parsed_partitions *state);
114
115#endif
116
117/*
118 * Overrides for Emacs so that we follow Linus's tabbing style.
119 * Emacs will notice this stuff at the end of the file and automatically
120 * adjust the settings for this buffer only. This must remain at the end
121 * of the file.
122 * --------------------------------------------------------------------------
123 * Local variables:
124 * c-indent-level: 4
125 * c-brace-imaginary-offset: 0
126 * c-brace-offset: -4
127 * c-argdecl-indent: 4
128 * c-label-offset: -4
129 * c-continued-statement-offset: 4
130 * c-continued-brace-offset: 0
131 * indent-tabs-mode: nil
132 * tab-width: 8
133 * End:
134 */
diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c
new file mode 100644
index 00000000000..d513a07f44b
--- /dev/null
+++ b/fs/partitions/ibm.c
@@ -0,0 +1,275 @@
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
9#include <linux/buffer_head.h>
10#include <linux/hdreg.h>
11#include <linux/slab.h>
12#include <asm/dasd.h>
13#include <asm/ebcdic.h>
14#include <asm/uaccess.h>
15#include <asm/vtoc.h>
16
17#include "check.h"
18#include "ibm.h"
19
20/*
21 * compute the block number from a
22 * cyl-cyl-head-head structure
23 */
24static sector_t
25cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
26
27 sector_t cyl;
28 __u16 head;
29
30 /*decode cylinder and heads for large volumes */
31 cyl = ptr->hh & 0xFFF0;
32 cyl <<= 12;
33 cyl |= ptr->cc;
34 head = ptr->hh & 0x000F;
35 return cyl * geo->heads * geo->sectors +
36 head * geo->sectors;
37}
38
39/*
40 * compute the block number from a
41 * cyl-cyl-head-head-block structure
42 */
43static sector_t
44cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
45
46 sector_t cyl;
47 __u16 head;
48
49 /*decode cylinder and heads for large volumes */
50 cyl = ptr->hh & 0xFFF0;
51 cyl <<= 12;
52 cyl |= ptr->cc;
53 head = ptr->hh & 0x000F;
54 return cyl * geo->heads * geo->sectors +
55 head * geo->sectors +
56 ptr->b;
57}
58
59/*
60 */
61int ibm_partition(struct parsed_partitions *state)
62{
63 struct block_device *bdev = state->bdev;
64 int blocksize, res;
65 loff_t i_size, offset, size, fmt_size;
66 dasd_information2_t *info;
67 struct hd_geometry *geo;
68 char type[5] = {0,};
69 char name[7] = {0,};
70 union label_t {
71 struct vtoc_volume_label_cdl vol;
72 struct vtoc_volume_label_ldl lnx;
73 struct vtoc_cms_label cms;
74 } *label;
75 unsigned char *data;
76 Sector sect;
77 sector_t labelsect;
78 char tmp[64];
79
80 res = 0;
81 blocksize = bdev_logical_block_size(bdev);
82 if (blocksize <= 0)
83 goto out_exit;
84 i_size = i_size_read(bdev->bd_inode);
85 if (i_size == 0)
86 goto out_exit;
87
88 info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
89 if (info == NULL)
90 goto out_exit;
91 geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
92 if (geo == NULL)
93 goto out_nogeo;
94 label = kmalloc(sizeof(union label_t), GFP_KERNEL);
95 if (label == NULL)
96 goto out_nolab;
97
98 if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 ||
99 ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
100 goto out_freeall;
101
102 /*
103 * Special case for FBA disks: label sector does not depend on
104 * blocksize.
105 */
106 if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
107 (info->cu_type == 0x3880 && info->dev_type == 0x3370))
108 labelsect = info->label_block;
109 else
110 labelsect = info->label_block * (blocksize >> 9);
111
112 /*
113 * Get volume label, extract name and type.
114 */
115 data = read_part_sector(state, labelsect, &sect);
116 if (data == NULL)
117 goto out_readerr;
118
119 memcpy(label, data, sizeof(union label_t));
120 put_dev_sector(sect);
121
122 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
123 strncpy(type, label->vol.vollbl, 4);
124 strncpy(name, label->vol.volid, 6);
125 } else {
126 strncpy(type, label->lnx.vollbl, 4);
127 strncpy(name, label->lnx.volid, 6);
128 }
129 EBCASC(type, 4);
130 EBCASC(name, 6);
131
132 res = 1;
133
134 /*
135 * Three different formats: LDL, CDL and unformated disk
136 *
137 * identified by info->format
138 *
139 * unformated disks we do not have to care about
140 */
141 if (info->format == DASD_FORMAT_LDL) {
142 if (strncmp(type, "CMS1", 4) == 0) {
143 /*
144 * VM style CMS1 labeled disk
145 */
146 blocksize = label->cms.block_size;
147 if (label->cms.disk_offset != 0) {
148 snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
149 strlcat(state->pp_buf, tmp, PAGE_SIZE);
150 /* disk is reserved minidisk */
151 offset = label->cms.disk_offset;
152 size = (label->cms.block_count - 1)
153 * (blocksize >> 9);
154 } else {
155 snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
156 strlcat(state->pp_buf, tmp, PAGE_SIZE);
157 offset = (info->label_block + 1);
158 size = label->cms.block_count
159 * (blocksize >> 9);
160 }
161 put_partition(state, 1, offset*(blocksize >> 9),
162 size-offset*(blocksize >> 9));
163 } else {
164 if (strncmp(type, "LNX1", 4) == 0) {
165 snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
166 strlcat(state->pp_buf, tmp, PAGE_SIZE);
167 if (label->lnx.ldl_version == 0xf2) {
168 fmt_size = label->lnx.formatted_blocks
169 * (blocksize >> 9);
170 } else if (!strcmp(info->type, "ECKD")) {
171 /* formated w/o large volume support */
172 fmt_size = geo->cylinders * geo->heads
173 * geo->sectors * (blocksize >> 9);
174 } else {
175 /* old label and no usable disk geometry
176 * (e.g. DIAG) */
177 fmt_size = i_size >> 9;
178 }
179 size = i_size >> 9;
180 if (fmt_size < size)
181 size = fmt_size;
182 offset = (info->label_block + 1);
183 } else {
184 /* unlabeled disk */
185 strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
186 size = i_size >> 9;
187 offset = (info->label_block + 1);
188 }
189 put_partition(state, 1, offset*(blocksize >> 9),
190 size-offset*(blocksize >> 9));
191 }
192 } else if (info->format == DASD_FORMAT_CDL) {
193 /*
194 * New style CDL formatted disk
195 */
196 sector_t blk;
197 int counter;
198
199 /*
200 * check if VOL1 label is available
201 * if not, something is wrong, skipping partition detection
202 */
203 if (strncmp(type, "VOL1", 4) == 0) {
204 snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
205 strlcat(state->pp_buf, tmp, PAGE_SIZE);
206 /*
207 * get block number and read then go through format1
208 * labels
209 */
210 blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
211 counter = 0;
212 data = read_part_sector(state, blk * (blocksize/512),
213 &sect);
214 while (data != NULL) {
215 struct vtoc_format1_label f1;
216
217 memcpy(&f1, data,
218 sizeof(struct vtoc_format1_label));
219 put_dev_sector(sect);
220
221 /* skip FMT4 / FMT5 / FMT7 labels */
222 if (f1.DS1FMTID == _ascebc['4']
223 || f1.DS1FMTID == _ascebc['5']
224 || f1.DS1FMTID == _ascebc['7']
225 || f1.DS1FMTID == _ascebc['9']) {
226 blk++;
227 data = read_part_sector(state,
228 blk * (blocksize/512), &sect);
229 continue;
230 }
231
232 /* only FMT1 and 8 labels valid at this point */
233 if (f1.DS1FMTID != _ascebc['1'] &&
234 f1.DS1FMTID != _ascebc['8'])
235 break;
236
237 /* OK, we got valid partition data */
238 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
239 size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
240 offset + geo->sectors;
241 if (counter >= state->limit)
242 break;
243 put_partition(state, counter + 1,
244 offset * (blocksize >> 9),
245 size * (blocksize >> 9));
246 counter++;
247 blk++;
248 data = read_part_sector(state,
249 blk * (blocksize/512), &sect);
250 }
251
252 if (!data)
253 /* Are we not supposed to report this ? */
254 goto out_readerr;
255 } else
256 printk(KERN_WARNING "Warning, expected Label VOL1 not "
257 "found, treating as CDL formated Disk");
258
259 }
260
261 strlcat(state->pp_buf, "\n", PAGE_SIZE);
262 goto out_freeall;
263
264
265out_readerr:
266 res = -1;
267out_freeall:
268 kfree(label);
269out_nolab:
270 kfree(geo);
271out_nogeo:
272 kfree(info);
273out_exit:
274 return res;
275}
diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h
new file mode 100644
index 00000000000..08fb0804a81
--- /dev/null
+++ b/fs/partitions/ibm.h
@@ -0,0 +1 @@
int ibm_partition(struct parsed_partitions *);
diff --git a/fs/partitions/karma.c b/fs/partitions/karma.c
new file mode 100644
index 00000000000..0ea19312706
--- /dev/null
+++ b/fs/partitions/karma.c
@@ -0,0 +1,57 @@
1/*
2 * fs/partitions/karma.c
3 * Rio Karma partition info.
4 *
5 * Copyright (C) 2006 Bob Copeland (me@bobcopeland.com)
6 * based on osf.c
7 */
8
9#include "check.h"
10#include "karma.h"
11
12int karma_partition(struct parsed_partitions *state)
13{
14 int i;
15 int slot = 1;
16 Sector sect;
17 unsigned char *data;
18 struct disklabel {
19 u8 d_reserved[270];
20 struct d_partition {
21 __le32 p_res;
22 u8 p_fstype;
23 u8 p_res2[3];
24 __le32 p_offset;
25 __le32 p_size;
26 } d_partitions[2];
27 u8 d_blank[208];
28 __le16 d_magic;
29 } __attribute__((packed)) *label;
30 struct d_partition *p;
31
32 data = read_part_sector(state, 0, &sect);
33 if (!data)
34 return -1;
35
36 label = (struct disklabel *)data;
37 if (le16_to_cpu(label->d_magic) != KARMA_LABEL_MAGIC) {
38 put_dev_sector(sect);
39 return 0;
40 }
41
42 p = label->d_partitions;
43 for (i = 0 ; i < 2; i++, p++) {
44 if (slot == state->limit)
45 break;
46
47 if (p->p_fstype == 0x4d && le32_to_cpu(p->p_size)) {
48 put_partition(state, slot, le32_to_cpu(p->p_offset),
49 le32_to_cpu(p->p_size));
50 }
51 slot++;
52 }
53 strlcat(state->pp_buf, "\n", PAGE_SIZE);
54 put_dev_sector(sect);
55 return 1;
56}
57
diff --git a/fs/partitions/karma.h b/fs/partitions/karma.h
new file mode 100644
index 00000000000..c764b2e9df2
--- /dev/null
+++ b/fs/partitions/karma.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/karma.h
3 */
4
5#define KARMA_LABEL_MAGIC 0xAB56
6
7int karma_partition(struct parsed_partitions *state);
8
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
new file mode 100644
index 00000000000..af9fdf04676
--- /dev/null
+++ b/fs/partitions/ldm.c
@@ -0,0 +1,1568 @@
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-2007 Anton Altaparmakov
6 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
7 *
8 * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
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 <linux/kernel.h>
30#include "ldm.h"
31#include "check.h"
32#include "msdos.h"
33
34/**
35 * ldm_debug/info/error/crit - Output an error message
36 * @f: A printf format string containing the message
37 * @...: Variables to substitute into @f
38 *
39 * ldm_debug() writes a DEBUG level message to the syslog but only if the
40 * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
41 */
42#ifndef CONFIG_LDM_DEBUG
43#define ldm_debug(...) do {} while (0)
44#else
45#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __func__, f, ##a)
46#endif
47
48#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __func__, f, ##a)
49#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __func__, f, ##a)
50#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __func__, f, ##a)
51
52__attribute__ ((format (printf, 3, 4)))
53static void _ldm_printk (const char *level, const char *function,
54 const char *fmt, ...)
55{
56 static char buf[128];
57 va_list args;
58
59 va_start (args, fmt);
60 vsnprintf (buf, sizeof (buf), fmt, args);
61 va_end (args);
62
63 printk ("%s%s(): %s\n", level, function, buf);
64}
65
66/**
67 * ldm_parse_hexbyte - Convert a ASCII hex number to a byte
68 * @src: Pointer to at least 2 characters to convert.
69 *
70 * Convert a two character ASCII hex string to a number.
71 *
72 * Return: 0-255 Success, the byte was parsed correctly
73 * -1 Error, an invalid character was supplied
74 */
75static int ldm_parse_hexbyte (const u8 *src)
76{
77 unsigned int x; /* For correct wrapping */
78 int h;
79
80 /* high part */
81 x = h = hex_to_bin(src[0]);
82 if (h < 0)
83 return -1;
84
85 /* low part */
86 h = hex_to_bin(src[1]);
87 if (h < 0)
88 return -1;
89
90 return (x << 4) + h;
91}
92
93/**
94 * ldm_parse_guid - Convert GUID from ASCII to binary
95 * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
96 * @dest: Memory block to hold binary GUID (16 bytes)
97 *
98 * N.B. The GUID need not be NULL terminated.
99 *
100 * Return: 'true' @dest contains binary GUID
101 * 'false' @dest contents are undefined
102 */
103static bool ldm_parse_guid (const u8 *src, u8 *dest)
104{
105 static const int size[] = { 4, 2, 2, 2, 6 };
106 int i, j, v;
107
108 if (src[8] != '-' || src[13] != '-' ||
109 src[18] != '-' || src[23] != '-')
110 return false;
111
112 for (j = 0; j < 5; j++, src++)
113 for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
114 if ((v = ldm_parse_hexbyte (src)) < 0)
115 return false;
116
117 return true;
118}
119
120/**
121 * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure
122 * @data: Raw database PRIVHEAD structure loaded from the device
123 * @ph: In-memory privhead structure in which to return parsed information
124 *
125 * This parses the LDM database PRIVHEAD structure supplied in @data and
126 * sets up the in-memory privhead structure @ph with the obtained information.
127 *
128 * Return: 'true' @ph contains the PRIVHEAD data
129 * 'false' @ph contents are undefined
130 */
131static bool ldm_parse_privhead(const u8 *data, struct privhead *ph)
132{
133 bool is_vista = false;
134
135 BUG_ON(!data || !ph);
136 if (MAGIC_PRIVHEAD != get_unaligned_be64(data)) {
137 ldm_error("Cannot find PRIVHEAD structure. LDM database is"
138 " corrupt. Aborting.");
139 return false;
140 }
141 ph->ver_major = get_unaligned_be16(data + 0x000C);
142 ph->ver_minor = get_unaligned_be16(data + 0x000E);
143 ph->logical_disk_start = get_unaligned_be64(data + 0x011B);
144 ph->logical_disk_size = get_unaligned_be64(data + 0x0123);
145 ph->config_start = get_unaligned_be64(data + 0x012B);
146 ph->config_size = get_unaligned_be64(data + 0x0133);
147 /* Version 2.11 is Win2k/XP and version 2.12 is Vista. */
148 if (ph->ver_major == 2 && ph->ver_minor == 12)
149 is_vista = true;
150 if (!is_vista && (ph->ver_major != 2 || ph->ver_minor != 11)) {
151 ldm_error("Expected PRIVHEAD version 2.11 or 2.12, got %d.%d."
152 " Aborting.", ph->ver_major, ph->ver_minor);
153 return false;
154 }
155 ldm_debug("PRIVHEAD version %d.%d (Windows %s).", ph->ver_major,
156 ph->ver_minor, is_vista ? "Vista" : "2000/XP");
157 if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
158 /* Warn the user and continue, carefully. */
159 ldm_info("Database is normally %u bytes, it claims to "
160 "be %llu bytes.", LDM_DB_SIZE,
161 (unsigned long long)ph->config_size);
162 }
163 if ((ph->logical_disk_size == 0) || (ph->logical_disk_start +
164 ph->logical_disk_size > ph->config_start)) {
165 ldm_error("PRIVHEAD disk size doesn't match real disk size");
166 return false;
167 }
168 if (!ldm_parse_guid(data + 0x0030, ph->disk_id)) {
169 ldm_error("PRIVHEAD contains an invalid GUID.");
170 return false;
171 }
172 ldm_debug("Parsed PRIVHEAD successfully.");
173 return true;
174}
175
176/**
177 * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure
178 * @data: Raw database TOCBLOCK structure loaded from the device
179 * @toc: In-memory toc structure in which to return parsed information
180 *
181 * This parses the LDM Database TOCBLOCK (table of contents) structure supplied
182 * in @data and sets up the in-memory tocblock structure @toc with the obtained
183 * information.
184 *
185 * N.B. The *_start and *_size values returned in @toc are not range-checked.
186 *
187 * Return: 'true' @toc contains the TOCBLOCK data
188 * 'false' @toc contents are undefined
189 */
190static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
191{
192 BUG_ON (!data || !toc);
193
194 if (MAGIC_TOCBLOCK != get_unaligned_be64(data)) {
195 ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
196 return false;
197 }
198 strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
199 toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
200 toc->bitmap1_start = get_unaligned_be64(data + 0x2E);
201 toc->bitmap1_size = get_unaligned_be64(data + 0x36);
202
203 if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
204 sizeof (toc->bitmap1_name)) != 0) {
205 ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
206 TOC_BITMAP1, toc->bitmap1_name);
207 return false;
208 }
209 strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
210 toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
211 toc->bitmap2_start = get_unaligned_be64(data + 0x50);
212 toc->bitmap2_size = get_unaligned_be64(data + 0x58);
213 if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
214 sizeof (toc->bitmap2_name)) != 0) {
215 ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
216 TOC_BITMAP2, toc->bitmap2_name);
217 return false;
218 }
219 ldm_debug ("Parsed TOCBLOCK successfully.");
220 return true;
221}
222
223/**
224 * ldm_parse_vmdb - Read the LDM Database VMDB structure
225 * @data: Raw database VMDB structure loaded from the device
226 * @vm: In-memory vmdb structure in which to return parsed information
227 *
228 * This parses the LDM Database VMDB structure supplied in @data and sets up
229 * the in-memory vmdb structure @vm with the obtained information.
230 *
231 * N.B. The *_start, *_size and *_seq values will be range-checked later.
232 *
233 * Return: 'true' @vm contains VMDB info
234 * 'false' @vm contents are undefined
235 */
236static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
237{
238 BUG_ON (!data || !vm);
239
240 if (MAGIC_VMDB != get_unaligned_be32(data)) {
241 ldm_crit ("Cannot find the VMDB, database may be corrupt.");
242 return false;
243 }
244
245 vm->ver_major = get_unaligned_be16(data + 0x12);
246 vm->ver_minor = get_unaligned_be16(data + 0x14);
247 if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
248 ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
249 "Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
250 return false;
251 }
252
253 vm->vblk_size = get_unaligned_be32(data + 0x08);
254 if (vm->vblk_size == 0) {
255 ldm_error ("Illegal VBLK size");
256 return false;
257 }
258
259 vm->vblk_offset = get_unaligned_be32(data + 0x0C);
260 vm->last_vblk_seq = get_unaligned_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 * @state: Partition check state including 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 parsed_partitions *state,
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 (!state || !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_part_sector(state, ph[0]->config_start + off[i],
355 &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 = state->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 * @state: Partition check state including device holding the LDM Database
406 * @base: Offset, into @state->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 * @state->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 parsed_partitions *state,
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 int i, nr_tbs;
426 bool result = false;
427
428 BUG_ON(!state || !ldb);
429 ph = &ldb->ph;
430 tb[0] = &ldb->toc;
431 tb[1] = kmalloc(sizeof(*tb[1]) * 3, GFP_KERNEL);
432 if (!tb[1]) {
433 ldm_crit("Out of memory.");
434 goto err;
435 }
436 tb[2] = (struct tocblock*)((u8*)tb[1] + sizeof(*tb[1]));
437 tb[3] = (struct tocblock*)((u8*)tb[2] + sizeof(*tb[2]));
438 /*
439 * Try to read and parse all four TOCBLOCKs.
440 *
441 * Windows Vista LDM v2.12 does not always have all four TOCBLOCKs so
442 * skip any that fail as long as we get at least one valid TOCBLOCK.
443 */
444 for (nr_tbs = i = 0; i < 4; i++) {
445 data = read_part_sector(state, base + off[i], &sect);
446 if (!data) {
447 ldm_error("Disk read failed for TOCBLOCK %d.", i);
448 continue;
449 }
450 if (ldm_parse_tocblock(data, tb[nr_tbs]))
451 nr_tbs++;
452 put_dev_sector(sect);
453 }
454 if (!nr_tbs) {
455 ldm_crit("Failed to find a valid TOCBLOCK.");
456 goto err;
457 }
458 /* Range check the TOCBLOCK against a privhead. */
459 if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
460 ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) >
461 ph->config_size)) {
462 ldm_crit("The bitmaps are out of range. Giving up.");
463 goto err;
464 }
465 /* Compare all loaded TOCBLOCKs. */
466 for (i = 1; i < nr_tbs; i++) {
467 if (!ldm_compare_tocblocks(tb[0], tb[i])) {
468 ldm_crit("TOCBLOCKs 0 and %d do not match.", i);
469 goto err;
470 }
471 }
472 ldm_debug("Validated %d TOCBLOCKs successfully.", nr_tbs);
473 result = true;
474err:
475 kfree(tb[1]);
476 return result;
477}
478
479/**
480 * ldm_validate_vmdb - Read the VMDB and validate it
481 * @state: Partition check state including device holding the LDM Database
482 * @base: Offset, into @bdev, of the database
483 * @ldb: Cache of the database structures
484 *
485 * Find the vmdb of the LDM Database stored on @bdev and return the parsed
486 * information in @ldb.
487 *
488 * Return: 'true' @ldb contains validated VBDB info
489 * 'false' @ldb contents are undefined
490 */
491static bool ldm_validate_vmdb(struct parsed_partitions *state,
492 unsigned long base, struct ldmdb *ldb)
493{
494 Sector sect;
495 u8 *data;
496 bool result = false;
497 struct vmdb *vm;
498 struct tocblock *toc;
499
500 BUG_ON (!state || !ldb);
501
502 vm = &ldb->vm;
503 toc = &ldb->toc;
504
505 data = read_part_sector(state, base + OFF_VMDB, &sect);
506 if (!data) {
507 ldm_crit ("Disk read failed.");
508 return false;
509 }
510
511 if (!ldm_parse_vmdb (data, vm))
512 goto out; /* Already logged */
513
514 /* Are there uncommitted transactions? */
515 if (get_unaligned_be16(data + 0x10) != 0x01) {
516 ldm_crit ("Database is not in a consistent state. Aborting.");
517 goto out;
518 }
519
520 if (vm->vblk_offset != 512)
521 ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
522
523 /*
524 * The last_vblkd_seq can be before the end of the vmdb, just make sure
525 * it is not out of bounds.
526 */
527 if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) {
528 ldm_crit ("VMDB exceeds allowed size specified by TOCBLOCK. "
529 "Database is corrupt. Aborting.");
530 goto out;
531 }
532
533 result = true;
534out:
535 put_dev_sector (sect);
536 return result;
537}
538
539
540/**
541 * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk
542 * @state: Partition check state including device holding the LDM Database
543 *
544 * This function provides a weak test to decide whether the device is a dynamic
545 * disk or not. It looks for an MS-DOS-style partition table containing at
546 * least one partition of type 0x42 (formerly SFS, now used by Windows for
547 * dynamic disks).
548 *
549 * N.B. The only possible error can come from the read_part_sector and that is
550 * only likely to happen if the underlying device is strange. If that IS
551 * the case we should return zero to let someone else try.
552 *
553 * Return: 'true' @state->bdev is a dynamic disk
554 * 'false' @state->bdev is not a dynamic disk, or an error occurred
555 */
556static bool ldm_validate_partition_table(struct parsed_partitions *state)
557{
558 Sector sect;
559 u8 *data;
560 struct partition *p;
561 int i;
562 bool result = false;
563
564 BUG_ON(!state);
565
566 data = read_part_sector(state, 0, &sect);
567 if (!data) {
568 ldm_info ("Disk read failed.");
569 return false;
570 }
571
572 if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
573 goto out;
574
575 p = (struct partition*)(data + 0x01BE);
576 for (i = 0; i < 4; i++, p++)
577 if (SYS_IND (p) == LDM_PARTITION) {
578 result = true;
579 break;
580 }
581
582 if (result)
583 ldm_debug ("Found W2K dynamic disk partition type.");
584
585out:
586 put_dev_sector (sect);
587 return result;
588}
589
590/**
591 * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id
592 * @ldb: Cache of the database structures
593 *
594 * The LDM Database contains a list of all partitions on all dynamic disks.
595 * The primary PRIVHEAD, at the beginning of the physical disk, tells us
596 * the GUID of this disk. This function searches for the GUID in a linked
597 * list of vblk's.
598 *
599 * Return: Pointer, A matching vblk was found
600 * NULL, No match, or an error
601 */
602static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
603{
604 struct list_head *item;
605
606 BUG_ON (!ldb);
607
608 list_for_each (item, &ldb->v_disk) {
609 struct vblk *v = list_entry (item, struct vblk, list);
610 if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
611 return v;
612 }
613
614 return NULL;
615}
616
617/**
618 * ldm_create_data_partitions - Create data partitions for this device
619 * @pp: List of the partitions parsed so far
620 * @ldb: Cache of the database structures
621 *
622 * The database contains ALL the partitions for ALL disk groups, so we need to
623 * filter out this specific disk. Using the disk's object id, we can find all
624 * the partitions in the database that belong to this disk.
625 *
626 * Add each partition in our database, to the parsed_partitions structure.
627 *
628 * N.B. This function creates the partitions in the order it finds partition
629 * objects in the linked list.
630 *
631 * Return: 'true' Partition created
632 * 'false' Error, probably a range checking problem
633 */
634static bool ldm_create_data_partitions (struct parsed_partitions *pp,
635 const struct ldmdb *ldb)
636{
637 struct list_head *item;
638 struct vblk *vb;
639 struct vblk *disk;
640 struct vblk_part *part;
641 int part_num = 1;
642
643 BUG_ON (!pp || !ldb);
644
645 disk = ldm_get_disk_objid (ldb);
646 if (!disk) {
647 ldm_crit ("Can't find the ID of this disk in the database.");
648 return false;
649 }
650
651 strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE);
652
653 /* Create the data partitions */
654 list_for_each (item, &ldb->v_part) {
655 vb = list_entry (item, struct vblk, list);
656 part = &vb->vblk.part;
657
658 if (part->disk_id != disk->obj_id)
659 continue;
660
661 put_partition (pp, part_num, ldb->ph.logical_disk_start +
662 part->start, part->size);
663 part_num++;
664 }
665
666 strlcat(pp->pp_buf, "\n", PAGE_SIZE);
667 return true;
668}
669
670
671/**
672 * ldm_relative - Calculate the next relative offset
673 * @buffer: Block of data being worked on
674 * @buflen: Size of the block of data
675 * @base: Size of the previous fixed width fields
676 * @offset: Cumulative size of the previous variable-width fields
677 *
678 * Because many of the VBLK fields are variable-width, it's necessary
679 * to calculate each offset based on the previous one and the length
680 * of the field it pointed to.
681 *
682 * Return: -1 Error, the calculated offset exceeded the size of the buffer
683 * n OK, a range-checked offset into buffer
684 */
685static int ldm_relative(const u8 *buffer, int buflen, int base, int offset)
686{
687
688 base += offset;
689 if (!buffer || offset < 0 || base > buflen) {
690 if (!buffer)
691 ldm_error("!buffer");
692 if (offset < 0)
693 ldm_error("offset (%d) < 0", offset);
694 if (base > buflen)
695 ldm_error("base (%d) > buflen (%d)", base, buflen);
696 return -1;
697 }
698 if (base + buffer[base] >= buflen) {
699 ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base,
700 buffer[base], buflen);
701 return -1;
702 }
703 return buffer[base] + offset + 1;
704}
705
706/**
707 * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order
708 * @block: Pointer to the variable-width number to convert
709 *
710 * Large numbers in the LDM Database are often stored in a packed format. Each
711 * number is prefixed by a one byte width marker. All numbers in the database
712 * are stored in big-endian byte order. This function reads one of these
713 * numbers and returns the result
714 *
715 * N.B. This function DOES NOT perform any range checking, though the most
716 * it will read is eight bytes.
717 *
718 * Return: n A number
719 * 0 Zero, or an error occurred
720 */
721static u64 ldm_get_vnum (const u8 *block)
722{
723 u64 tmp = 0;
724 u8 length;
725
726 BUG_ON (!block);
727
728 length = *block++;
729
730 if (length && length <= 8)
731 while (length--)
732 tmp = (tmp << 8) | *block++;
733 else
734 ldm_error ("Illegal length %d.", length);
735
736 return tmp;
737}
738
739/**
740 * ldm_get_vstr - Read a length-prefixed string into a buffer
741 * @block: Pointer to the length marker
742 * @buffer: Location to copy string to
743 * @buflen: Size of the output buffer
744 *
745 * Many of the strings in the LDM Database are not NULL terminated. Instead
746 * they are prefixed by a one byte length marker. This function copies one of
747 * these strings into a buffer.
748 *
749 * N.B. This function DOES NOT perform any range checking on the input.
750 * If the buffer is too small, the output will be truncated.
751 *
752 * Return: 0, Error and @buffer contents are undefined
753 * n, String length in characters (excluding NULL)
754 * buflen-1, String was truncated.
755 */
756static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
757{
758 int length;
759
760 BUG_ON (!block || !buffer);
761
762 length = block[0];
763 if (length >= buflen) {
764 ldm_error ("Truncating string %d -> %d.", length, buflen);
765 length = buflen - 1;
766 }
767 memcpy (buffer, block + 1, length);
768 buffer[length] = 0;
769 return length;
770}
771
772
773/**
774 * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure
775 * @buffer: Block of data being worked on
776 * @buflen: Size of the block of data
777 * @vb: In-memory vblk in which to return information
778 *
779 * Read a raw VBLK Component object (version 3) into a vblk structure.
780 *
781 * Return: 'true' @vb contains a Component VBLK
782 * 'false' @vb contents are not defined
783 */
784static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
785{
786 int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
787 struct vblk_comp *comp;
788
789 BUG_ON (!buffer || !vb);
790
791 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
792 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
793 r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
794 r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate);
795 r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
796
797 if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
798 r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
799 r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe);
800 len = r_cols;
801 } else {
802 r_stripe = 0;
803 r_cols = 0;
804 len = r_parent;
805 }
806 if (len < 0)
807 return false;
808
809 len += VBLK_SIZE_CMP3;
810 if (len != get_unaligned_be32(buffer + 0x14))
811 return false;
812
813 comp = &vb->vblk.comp;
814 ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
815 sizeof (comp->state));
816 comp->type = buffer[0x18 + r_vstate];
817 comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate);
818 comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
819 comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
820
821 return true;
822}
823
824/**
825 * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure
826 * @buffer: Block of data being worked on
827 * @buflen: Size of the block of data
828 * @vb: In-memory vblk in which to return information
829 *
830 * Read a raw VBLK Disk Group object (version 3) into a vblk structure.
831 *
832 * Return: 'true' @vb contains a Disk Group VBLK
833 * 'false' @vb contents are not defined
834 */
835static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
836{
837 int r_objid, r_name, r_diskid, r_id1, r_id2, len;
838 struct vblk_dgrp *dgrp;
839
840 BUG_ON (!buffer || !vb);
841
842 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
843 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
844 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
845
846 if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
847 r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
848 r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
849 len = r_id2;
850 } else {
851 r_id1 = 0;
852 r_id2 = 0;
853 len = r_diskid;
854 }
855 if (len < 0)
856 return false;
857
858 len += VBLK_SIZE_DGR3;
859 if (len != get_unaligned_be32(buffer + 0x14))
860 return false;
861
862 dgrp = &vb->vblk.dgrp;
863 ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
864 sizeof (dgrp->disk_id));
865 return true;
866}
867
868/**
869 * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure
870 * @buffer: Block of data being worked on
871 * @buflen: Size of the block of data
872 * @vb: In-memory vblk in which to return information
873 *
874 * Read a raw VBLK Disk Group object (version 4) into a vblk structure.
875 *
876 * Return: 'true' @vb contains a Disk Group VBLK
877 * 'false' @vb contents are not defined
878 */
879static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
880{
881 char buf[64];
882 int r_objid, r_name, r_id1, r_id2, len;
883 struct vblk_dgrp *dgrp;
884
885 BUG_ON (!buffer || !vb);
886
887 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
888 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
889
890 if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
891 r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
892 r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
893 len = r_id2;
894 } else {
895 r_id1 = 0;
896 r_id2 = 0;
897 len = r_name;
898 }
899 if (len < 0)
900 return false;
901
902 len += VBLK_SIZE_DGR4;
903 if (len != get_unaligned_be32(buffer + 0x14))
904 return false;
905
906 dgrp = &vb->vblk.dgrp;
907
908 ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
909 return true;
910}
911
912/**
913 * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure
914 * @buffer: Block of data being worked on
915 * @buflen: Size of the block of data
916 * @vb: In-memory vblk in which to return information
917 *
918 * Read a raw VBLK Disk object (version 3) into a vblk structure.
919 *
920 * Return: 'true' @vb contains a Disk VBLK
921 * 'false' @vb contents are not defined
922 */
923static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
924{
925 int r_objid, r_name, r_diskid, r_altname, len;
926 struct vblk_disk *disk;
927
928 BUG_ON (!buffer || !vb);
929
930 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
931 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
932 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
933 r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
934 len = r_altname;
935 if (len < 0)
936 return false;
937
938 len += VBLK_SIZE_DSK3;
939 if (len != get_unaligned_be32(buffer + 0x14))
940 return false;
941
942 disk = &vb->vblk.disk;
943 ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
944 sizeof (disk->alt_name));
945 if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
946 return false;
947
948 return true;
949}
950
951/**
952 * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure
953 * @buffer: Block of data being worked on
954 * @buflen: Size of the block of data
955 * @vb: In-memory vblk in which to return information
956 *
957 * Read a raw VBLK Disk object (version 4) into a vblk structure.
958 *
959 * Return: 'true' @vb contains a Disk VBLK
960 * 'false' @vb contents are not defined
961 */
962static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
963{
964 int r_objid, r_name, len;
965 struct vblk_disk *disk;
966
967 BUG_ON (!buffer || !vb);
968
969 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
970 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
971 len = r_name;
972 if (len < 0)
973 return false;
974
975 len += VBLK_SIZE_DSK4;
976 if (len != get_unaligned_be32(buffer + 0x14))
977 return false;
978
979 disk = &vb->vblk.disk;
980 memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
981 return true;
982}
983
984/**
985 * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure
986 * @buffer: Block of data being worked on
987 * @buflen: Size of the block of data
988 * @vb: In-memory vblk in which to return information
989 *
990 * Read a raw VBLK Partition object (version 3) into a vblk structure.
991 *
992 * Return: 'true' @vb contains a Partition VBLK
993 * 'false' @vb contents are not defined
994 */
995static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb)
996{
997 int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
998 struct vblk_part *part;
999
1000 BUG_ON(!buffer || !vb);
1001 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1002 if (r_objid < 0) {
1003 ldm_error("r_objid %d < 0", r_objid);
1004 return false;
1005 }
1006 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1007 if (r_name < 0) {
1008 ldm_error("r_name %d < 0", r_name);
1009 return false;
1010 }
1011 r_size = ldm_relative(buffer, buflen, 0x34, r_name);
1012 if (r_size < 0) {
1013 ldm_error("r_size %d < 0", r_size);
1014 return false;
1015 }
1016 r_parent = ldm_relative(buffer, buflen, 0x34, r_size);
1017 if (r_parent < 0) {
1018 ldm_error("r_parent %d < 0", r_parent);
1019 return false;
1020 }
1021 r_diskid = ldm_relative(buffer, buflen, 0x34, r_parent);
1022 if (r_diskid < 0) {
1023 ldm_error("r_diskid %d < 0", r_diskid);
1024 return false;
1025 }
1026 if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
1027 r_index = ldm_relative(buffer, buflen, 0x34, r_diskid);
1028 if (r_index < 0) {
1029 ldm_error("r_index %d < 0", r_index);
1030 return false;
1031 }
1032 len = r_index;
1033 } else {
1034 r_index = 0;
1035 len = r_diskid;
1036 }
1037 if (len < 0) {
1038 ldm_error("len %d < 0", len);
1039 return false;
1040 }
1041 len += VBLK_SIZE_PRT3;
1042 if (len > get_unaligned_be32(buffer + 0x14)) {
1043 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1044 get_unaligned_be32(buffer + 0x14));
1045 return false;
1046 }
1047 part = &vb->vblk.part;
1048 part->start = get_unaligned_be64(buffer + 0x24 + r_name);
1049 part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name);
1050 part->size = ldm_get_vnum(buffer + 0x34 + r_name);
1051 part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size);
1052 part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent);
1053 if (vb->flags & VBLK_FLAG_PART_INDEX)
1054 part->partnum = buffer[0x35 + r_diskid];
1055 else
1056 part->partnum = 0;
1057 return true;
1058}
1059
1060/**
1061 * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure
1062 * @buffer: Block of data being worked on
1063 * @buflen: Size of the block of data
1064 * @vb: In-memory vblk in which to return information
1065 *
1066 * Read a raw VBLK Volume object (version 5) into a vblk structure.
1067 *
1068 * Return: 'true' @vb contains a Volume VBLK
1069 * 'false' @vb contents are not defined
1070 */
1071static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb)
1072{
1073 int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;
1074 int r_id1, r_id2, r_size2, r_drive, len;
1075 struct vblk_volu *volu;
1076
1077 BUG_ON(!buffer || !vb);
1078 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1079 if (r_objid < 0) {
1080 ldm_error("r_objid %d < 0", r_objid);
1081 return false;
1082 }
1083 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1084 if (r_name < 0) {
1085 ldm_error("r_name %d < 0", r_name);
1086 return false;
1087 }
1088 r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);
1089 if (r_vtype < 0) {
1090 ldm_error("r_vtype %d < 0", r_vtype);
1091 return false;
1092 }
1093 r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);
1094 if (r_disable_drive_letter < 0) {
1095 ldm_error("r_disable_drive_letter %d < 0",
1096 r_disable_drive_letter);
1097 return false;
1098 }
1099 r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);
1100 if (r_child < 0) {
1101 ldm_error("r_child %d < 0", r_child);
1102 return false;
1103 }
1104 r_size = ldm_relative(buffer, buflen, 0x3D, r_child);
1105 if (r_size < 0) {
1106 ldm_error("r_size %d < 0", r_size);
1107 return false;
1108 }
1109 if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {
1110 r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);
1111 if (r_id1 < 0) {
1112 ldm_error("r_id1 %d < 0", r_id1);
1113 return false;
1114 }
1115 } else
1116 r_id1 = r_size;
1117 if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {
1118 r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);
1119 if (r_id2 < 0) {
1120 ldm_error("r_id2 %d < 0", r_id2);
1121 return false;
1122 }
1123 } else
1124 r_id2 = r_id1;
1125 if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {
1126 r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);
1127 if (r_size2 < 0) {
1128 ldm_error("r_size2 %d < 0", r_size2);
1129 return false;
1130 }
1131 } else
1132 r_size2 = r_id2;
1133 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1134 r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);
1135 if (r_drive < 0) {
1136 ldm_error("r_drive %d < 0", r_drive);
1137 return false;
1138 }
1139 } else
1140 r_drive = r_size2;
1141 len = r_drive;
1142 if (len < 0) {
1143 ldm_error("len %d < 0", len);
1144 return false;
1145 }
1146 len += VBLK_SIZE_VOL5;
1147 if (len > get_unaligned_be32(buffer + 0x14)) {
1148 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1149 get_unaligned_be32(buffer + 0x14));
1150 return false;
1151 }
1152 volu = &vb->vblk.volu;
1153 ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,
1154 sizeof(volu->volume_type));
1155 memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,
1156 sizeof(volu->volume_state));
1157 volu->size = ldm_get_vnum(buffer + 0x3D + r_child);
1158 volu->partition_type = buffer[0x41 + r_size];
1159 memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));
1160 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1161 ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,
1162 sizeof(volu->drive_hint));
1163 }
1164 return true;
1165}
1166
1167/**
1168 * ldm_parse_vblk - Read a raw VBLK object into a vblk structure
1169 * @buf: Block of data being worked on
1170 * @len: Size of the block of data
1171 * @vb: In-memory vblk in which to return information
1172 *
1173 * Read a raw VBLK object into a vblk structure. This function just reads the
1174 * information common to all VBLK types, then delegates the rest of the work to
1175 * helper functions: ldm_parse_*.
1176 *
1177 * Return: 'true' @vb contains a VBLK
1178 * 'false' @vb contents are not defined
1179 */
1180static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
1181{
1182 bool result = false;
1183 int r_objid;
1184
1185 BUG_ON (!buf || !vb);
1186
1187 r_objid = ldm_relative (buf, len, 0x18, 0);
1188 if (r_objid < 0) {
1189 ldm_error ("VBLK header is corrupt.");
1190 return false;
1191 }
1192
1193 vb->flags = buf[0x12];
1194 vb->type = buf[0x13];
1195 vb->obj_id = ldm_get_vnum (buf + 0x18);
1196 ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
1197
1198 switch (vb->type) {
1199 case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break;
1200 case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break;
1201 case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break;
1202 case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break;
1203 case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break;
1204 case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break;
1205 case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break;
1206 }
1207
1208 if (result)
1209 ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
1210 (unsigned long long) vb->obj_id, vb->type);
1211 else
1212 ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
1213 (unsigned long long) vb->obj_id, vb->type);
1214
1215 return result;
1216}
1217
1218
1219/**
1220 * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database
1221 * @data: Raw VBLK to add to the database
1222 * @len: Size of the raw VBLK
1223 * @ldb: Cache of the database structures
1224 *
1225 * The VBLKs are sorted into categories. Partitions are also sorted by offset.
1226 *
1227 * N.B. This function does not check the validity of the VBLKs.
1228 *
1229 * Return: 'true' The VBLK was added
1230 * 'false' An error occurred
1231 */
1232static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
1233{
1234 struct vblk *vb;
1235 struct list_head *item;
1236
1237 BUG_ON (!data || !ldb);
1238
1239 vb = kmalloc (sizeof (*vb), GFP_KERNEL);
1240 if (!vb) {
1241 ldm_crit ("Out of memory.");
1242 return false;
1243 }
1244
1245 if (!ldm_parse_vblk (data, len, vb)) {
1246 kfree(vb);
1247 return false; /* Already logged */
1248 }
1249
1250 /* Put vblk into the correct list. */
1251 switch (vb->type) {
1252 case VBLK_DGR3:
1253 case VBLK_DGR4:
1254 list_add (&vb->list, &ldb->v_dgrp);
1255 break;
1256 case VBLK_DSK3:
1257 case VBLK_DSK4:
1258 list_add (&vb->list, &ldb->v_disk);
1259 break;
1260 case VBLK_VOL5:
1261 list_add (&vb->list, &ldb->v_volu);
1262 break;
1263 case VBLK_CMP3:
1264 list_add (&vb->list, &ldb->v_comp);
1265 break;
1266 case VBLK_PRT3:
1267 /* Sort by the partition's start sector. */
1268 list_for_each (item, &ldb->v_part) {
1269 struct vblk *v = list_entry (item, struct vblk, list);
1270 if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
1271 (v->vblk.part.start > vb->vblk.part.start)) {
1272 list_add_tail (&vb->list, &v->list);
1273 return true;
1274 }
1275 }
1276 list_add_tail (&vb->list, &ldb->v_part);
1277 break;
1278 }
1279 return true;
1280}
1281
1282/**
1283 * ldm_frag_add - Add a VBLK fragment to a list
1284 * @data: Raw fragment to be added to the list
1285 * @size: Size of the raw fragment
1286 * @frags: Linked list of VBLK fragments
1287 *
1288 * Fragmented VBLKs may not be consecutive in the database, so they are placed
1289 * in a list so they can be pieced together later.
1290 *
1291 * Return: 'true' Success, the VBLK was added to the list
1292 * 'false' Error, a problem occurred
1293 */
1294static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
1295{
1296 struct frag *f;
1297 struct list_head *item;
1298 int rec, num, group;
1299
1300 BUG_ON (!data || !frags);
1301
1302 if (size < 2 * VBLK_SIZE_HEAD) {
1303 ldm_error("Value of size is to small.");
1304 return false;
1305 }
1306
1307 group = get_unaligned_be32(data + 0x08);
1308 rec = get_unaligned_be16(data + 0x0C);
1309 num = get_unaligned_be16(data + 0x0E);
1310 if ((num < 1) || (num > 4)) {
1311 ldm_error ("A VBLK claims to have %d parts.", num);
1312 return false;
1313 }
1314 if (rec >= num) {
1315 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num);
1316 return false;
1317 }
1318
1319 list_for_each (item, frags) {
1320 f = list_entry (item, struct frag, list);
1321 if (f->group == group)
1322 goto found;
1323 }
1324
1325 f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
1326 if (!f) {
1327 ldm_crit ("Out of memory.");
1328 return false;
1329 }
1330
1331 f->group = group;
1332 f->num = num;
1333 f->rec = rec;
1334 f->map = 0xFF << num;
1335
1336 list_add_tail (&f->list, frags);
1337found:
1338 if (rec >= f->num) {
1339 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num);
1340 return false;
1341 }
1342
1343 if (f->map & (1 << rec)) {
1344 ldm_error ("Duplicate VBLK, part %d.", rec);
1345 f->map &= 0x7F; /* Mark the group as broken */
1346 return false;
1347 }
1348
1349 f->map |= (1 << rec);
1350
1351 data += VBLK_SIZE_HEAD;
1352 size -= VBLK_SIZE_HEAD;
1353
1354 memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
1355
1356 return true;
1357}
1358
1359/**
1360 * ldm_frag_free - Free a linked list of VBLK fragments
1361 * @list: Linked list of fragments
1362 *
1363 * Free a linked list of VBLK fragments
1364 *
1365 * Return: none
1366 */
1367static void ldm_frag_free (struct list_head *list)
1368{
1369 struct list_head *item, *tmp;
1370
1371 BUG_ON (!list);
1372
1373 list_for_each_safe (item, tmp, list)
1374 kfree (list_entry (item, struct frag, list));
1375}
1376
1377/**
1378 * ldm_frag_commit - Validate fragmented VBLKs and add them to the database
1379 * @frags: Linked list of VBLK fragments
1380 * @ldb: Cache of the database structures
1381 *
1382 * Now that all the fragmented VBLKs have been collected, they must be added to
1383 * the database for later use.
1384 *
1385 * Return: 'true' All the fragments we added successfully
1386 * 'false' One or more of the fragments we invalid
1387 */
1388static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
1389{
1390 struct frag *f;
1391 struct list_head *item;
1392
1393 BUG_ON (!frags || !ldb);
1394
1395 list_for_each (item, frags) {
1396 f = list_entry (item, struct frag, list);
1397
1398 if (f->map != 0xFF) {
1399 ldm_error ("VBLK group %d is incomplete (0x%02x).",
1400 f->group, f->map);
1401 return false;
1402 }
1403
1404 if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
1405 return false; /* Already logged */
1406 }
1407 return true;
1408}
1409
1410/**
1411 * ldm_get_vblks - Read the on-disk database of VBLKs into memory
1412 * @state: Partition check state including device holding the LDM Database
1413 * @base: Offset, into @state->bdev, of the database
1414 * @ldb: Cache of the database structures
1415 *
1416 * To use the information from the VBLKs, they need to be read from the disk,
1417 * unpacked and validated. We cache them in @ldb according to their type.
1418 *
1419 * Return: 'true' All the VBLKs were read successfully
1420 * 'false' An error occurred
1421 */
1422static bool ldm_get_vblks(struct parsed_partitions *state, unsigned long base,
1423 struct ldmdb *ldb)
1424{
1425 int size, perbuf, skip, finish, s, v, recs;
1426 u8 *data = NULL;
1427 Sector sect;
1428 bool result = false;
1429 LIST_HEAD (frags);
1430
1431 BUG_ON(!state || !ldb);
1432
1433 size = ldb->vm.vblk_size;
1434 perbuf = 512 / size;
1435 skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */
1436 finish = (size * ldb->vm.last_vblk_seq) >> 9;
1437
1438 for (s = skip; s < finish; s++) { /* For each sector */
1439 data = read_part_sector(state, base + OFF_VMDB + s, &sect);
1440 if (!data) {
1441 ldm_crit ("Disk read failed.");
1442 goto out;
1443 }
1444
1445 for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */
1446 if (MAGIC_VBLK != get_unaligned_be32(data)) {
1447 ldm_error ("Expected to find a VBLK.");
1448 goto out;
1449 }
1450
1451 recs = get_unaligned_be16(data + 0x0E); /* Number of records */
1452 if (recs == 1) {
1453 if (!ldm_ldmdb_add (data, size, ldb))
1454 goto out; /* Already logged */
1455 } else if (recs > 1) {
1456 if (!ldm_frag_add (data, size, &frags))
1457 goto out; /* Already logged */
1458 }
1459 /* else Record is not in use, ignore it. */
1460 }
1461 put_dev_sector (sect);
1462 data = NULL;
1463 }
1464
1465 result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */
1466out:
1467 if (data)
1468 put_dev_sector (sect);
1469 ldm_frag_free (&frags);
1470
1471 return result;
1472}
1473
1474/**
1475 * ldm_free_vblks - Free a linked list of vblk's
1476 * @lh: Head of a linked list of struct vblk
1477 *
1478 * Free a list of vblk's and free the memory used to maintain the list.
1479 *
1480 * Return: none
1481 */
1482static void ldm_free_vblks (struct list_head *lh)
1483{
1484 struct list_head *item, *tmp;
1485
1486 BUG_ON (!lh);
1487
1488 list_for_each_safe (item, tmp, lh)
1489 kfree (list_entry (item, struct vblk, list));
1490}
1491
1492
1493/**
1494 * ldm_partition - Find out whether a device is a dynamic disk and handle it
1495 * @state: Partition check state including device holding the LDM Database
1496 *
1497 * This determines whether the device @bdev is a dynamic disk and if so creates
1498 * the partitions necessary in the gendisk structure pointed to by @hd.
1499 *
1500 * We create a dummy device 1, which contains the LDM database, and then create
1501 * each partition described by the LDM database in sequence as devices 2+. For
1502 * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3,
1503 * and so on: the actual data containing partitions.
1504 *
1505 * Return: 1 Success, @state->bdev is a dynamic disk and we handled it
1506 * 0 Success, @state->bdev is not a dynamic disk
1507 * -1 An error occurred before enough information had been read
1508 * Or @state->bdev is a dynamic disk, but it may be corrupted
1509 */
1510int ldm_partition(struct parsed_partitions *state)
1511{
1512 struct ldmdb *ldb;
1513 unsigned long base;
1514 int result = -1;
1515
1516 BUG_ON(!state);
1517
1518 /* Look for signs of a Dynamic Disk */
1519 if (!ldm_validate_partition_table(state))
1520 return 0;
1521
1522 ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
1523 if (!ldb) {
1524 ldm_crit ("Out of memory.");
1525 goto out;
1526 }
1527
1528 /* Parse and check privheads. */
1529 if (!ldm_validate_privheads(state, &ldb->ph))
1530 goto out; /* Already logged */
1531
1532 /* All further references are relative to base (database start). */
1533 base = ldb->ph.config_start;
1534
1535 /* Parse and check tocs and vmdb. */
1536 if (!ldm_validate_tocblocks(state, base, ldb) ||
1537 !ldm_validate_vmdb(state, base, ldb))
1538 goto out; /* Already logged */
1539
1540 /* Initialize vblk lists in ldmdb struct */
1541 INIT_LIST_HEAD (&ldb->v_dgrp);
1542 INIT_LIST_HEAD (&ldb->v_disk);
1543 INIT_LIST_HEAD (&ldb->v_volu);
1544 INIT_LIST_HEAD (&ldb->v_comp);
1545 INIT_LIST_HEAD (&ldb->v_part);
1546
1547 if (!ldm_get_vblks(state, base, ldb)) {
1548 ldm_crit ("Failed to read the VBLKs from the database.");
1549 goto cleanup;
1550 }
1551
1552 /* Finally, create the data partition devices. */
1553 if (ldm_create_data_partitions(state, ldb)) {
1554 ldm_debug ("Parsed LDM database successfully.");
1555 result = 1;
1556 }
1557 /* else Already logged */
1558
1559cleanup:
1560 ldm_free_vblks (&ldb->v_dgrp);
1561 ldm_free_vblks (&ldb->v_disk);
1562 ldm_free_vblks (&ldb->v_volu);
1563 ldm_free_vblks (&ldb->v_comp);
1564 ldm_free_vblks (&ldb->v_part);
1565out:
1566 kfree (ldb);
1567 return result;
1568}
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h
new file mode 100644
index 00000000000..374242c0971
--- /dev/null
+++ b/fs/partitions/ldm.h
@@ -0,0 +1,215 @@
1/**
2 * ldm - Part of the Linux-NTFS project.
3 *
4 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
5 * Copyright (c) 2001-2007 Anton Altaparmakov
6 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
7 *
8 * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
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 58
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 LDM_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/* Borrowed from msdos.c */
102#define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
103
104struct frag { /* VBLK Fragment handling */
105 struct list_head list;
106 u32 group;
107 u8 num; /* Total number of records */
108 u8 rec; /* This is record number n */
109 u8 map; /* Which portions are in use */
110 u8 data[0];
111};
112
113/* In memory LDM database structures. */
114
115#define GUID_SIZE 16
116
117struct privhead { /* Offsets and sizes are in sectors. */
118 u16 ver_major;
119 u16 ver_minor;
120 u64 logical_disk_start;
121 u64 logical_disk_size;
122 u64 config_start;
123 u64 config_size;
124 u8 disk_id[GUID_SIZE];
125};
126
127struct tocblock { /* We have exactly two bitmaps. */
128 u8 bitmap1_name[16];
129 u64 bitmap1_start;
130 u64 bitmap1_size;
131 u8 bitmap2_name[16];
132 u64 bitmap2_start;
133 u64 bitmap2_size;
134};
135
136struct vmdb { /* VMDB: The database header */
137 u16 ver_major;
138 u16 ver_minor;
139 u32 vblk_size;
140 u32 vblk_offset;
141 u32 last_vblk_seq;
142};
143
144struct vblk_comp { /* VBLK Component */
145 u8 state[16];
146 u64 parent_id;
147 u8 type;
148 u8 children;
149 u16 chunksize;
150};
151
152struct vblk_dgrp { /* VBLK Disk Group */
153 u8 disk_id[64];
154};
155
156struct vblk_disk { /* VBLK Disk */
157 u8 disk_id[GUID_SIZE];
158 u8 alt_name[128];
159};
160
161struct vblk_part { /* VBLK Partition */
162 u64 start;
163 u64 size; /* start, size and vol_off in sectors */
164 u64 volume_offset;
165 u64 parent_id;
166 u64 disk_id;
167 u8 partnum;
168};
169
170struct vblk_volu { /* VBLK Volume */
171 u8 volume_type[16];
172 u8 volume_state[16];
173 u8 guid[16];
174 u8 drive_hint[4];
175 u64 size;
176 u8 partition_type;
177};
178
179struct vblk_head { /* VBLK standard header */
180 u32 group;
181 u16 rec;
182 u16 nrec;
183};
184
185struct vblk { /* Generalised VBLK */
186 u8 name[64];
187 u64 obj_id;
188 u32 sequence;
189 u8 flags;
190 u8 type;
191 union {
192 struct vblk_comp comp;
193 struct vblk_dgrp dgrp;
194 struct vblk_disk disk;
195 struct vblk_part part;
196 struct vblk_volu volu;
197 } vblk;
198 struct list_head list;
199};
200
201struct ldmdb { /* Cache of the database */
202 struct privhead ph;
203 struct tocblock toc;
204 struct vmdb vm;
205 struct list_head v_dgrp;
206 struct list_head v_disk;
207 struct list_head v_volu;
208 struct list_head v_comp;
209 struct list_head v_part;
210};
211
212int ldm_partition(struct parsed_partitions *state);
213
214#endif /* _FS_PT_LDM_H_ */
215
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
new file mode 100644
index 00000000000..11f688bd76c
--- /dev/null
+++ b/fs/partitions/mac.c
@@ -0,0 +1,134 @@
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/ctype.h>
10#include "check.h"
11#include "mac.h"
12
13#ifdef CONFIG_PPC_PMAC
14#include <asm/machdep.h>
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)
31{
32 Sector sect;
33 unsigned char *data;
34 int slot, blocks_in_map;
35 unsigned secsize;
36#ifdef CONFIG_PPC_PMAC
37 int found_root = 0;
38 int found_root_goodness = 0;
39#endif
40 struct mac_partition *part;
41 struct mac_driver_desc *md;
42
43 /* Get 0th block and look at the first partition map entry. */
44 md = read_part_sector(state, 0, &sect);
45 if (!md)
46 return -1;
47 if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
48 put_dev_sector(sect);
49 return 0;
50 }
51 secsize = be16_to_cpu(md->block_size);
52 put_dev_sector(sect);
53 data = read_part_sector(state, secsize/512, &sect);
54 if (!data)
55 return -1;
56 part = (struct mac_partition *) (data + secsize%512);
57 if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
58 put_dev_sector(sect);
59 return 0; /* not a MacOS disk */
60 }
61 blocks_in_map = be32_to_cpu(part->map_count);
62 if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {
63 put_dev_sector(sect);
64 return 0;
65 }
66 strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
67 for (slot = 1; slot <= blocks_in_map; ++slot) {
68 int pos = slot * secsize;
69 put_dev_sector(sect);
70 data = read_part_sector(state, pos/512, &sect);
71 if (!data)
72 return -1;
73 part = (struct mac_partition *) (data + pos%512);
74 if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
75 break;
76 put_partition(state, slot,
77 be32_to_cpu(part->start_block) * (secsize/512),
78 be32_to_cpu(part->block_count) * (secsize/512));
79
80 if (!strnicmp(part->type, "Linux_RAID", 10))
81 state->parts[slot].flags = ADDPART_FLAG_RAID;
82#ifdef CONFIG_PPC_PMAC
83 /*
84 * If this is the first bootable partition, tell the
85 * setup code, in case it wants to make this the root.
86 */
87 if (machine_is(powermac)) {
88 int goodness = 0;
89
90 mac_fix_string(part->processor, 16);
91 mac_fix_string(part->name, 32);
92 mac_fix_string(part->type, 32);
93
94 if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
95 && strcasecmp(part->processor, "powerpc") == 0)
96 goodness++;
97
98 if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
99 || (strnicmp(part->type, "Linux", 5) == 0
100 && strcasecmp(part->type, "Linux_swap") != 0)) {
101 int i, l;
102
103 goodness++;
104 l = strlen(part->name);
105 if (strcmp(part->name, "/") == 0)
106 goodness++;
107 for (i = 0; i <= l - 4; ++i) {
108 if (strnicmp(part->name + i, "root",
109 4) == 0) {
110 goodness += 2;
111 break;
112 }
113 }
114 if (strnicmp(part->name, "swap", 4) == 0)
115 goodness--;
116 }
117
118 if (goodness > found_root_goodness) {
119 found_root = slot;
120 found_root_goodness = goodness;
121 }
122 }
123#endif /* CONFIG_PPC_PMAC */
124 }
125#ifdef CONFIG_PPC_PMAC
126 if (found_root_goodness)
127 note_bootable_part(state->bdev->bd_dev, found_root,
128 found_root_goodness);
129#endif
130
131 put_dev_sector(sect);
132 strlcat(state->pp_buf, "\n", PAGE_SIZE);
133 return 1;
134}
diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h
new file mode 100644
index 00000000000..3c7d9843638
--- /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);
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
new file mode 100644
index 00000000000..5f79a6677c6
--- /dev/null
+++ b/fs/partitions/msdos.c
@@ -0,0 +1,552 @@
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#include <linux/msdos_fs.h>
22
23#include "check.h"
24#include "msdos.h"
25#include "efi.h"
26
27/*
28 * Many architectures don't like unaligned accesses, while
29 * the nr_sects and start_sect partition table entries are
30 * at a 2 (mod 4) address.
31 */
32#include <asm/unaligned.h>
33
34#define SYS_IND(p) get_unaligned(&p->sys_ind)
35
36static inline sector_t nr_sects(struct partition *p)
37{
38 return (sector_t)get_unaligned_le32(&p->nr_sects);
39}
40
41static inline sector_t start_sect(struct partition *p)
42{
43 return (sector_t)get_unaligned_le32(&p->start_sect);
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/* Value is EBCDIC 'IBMA' */
63#define AIX_LABEL_MAGIC1 0xC9
64#define AIX_LABEL_MAGIC2 0xC2
65#define AIX_LABEL_MAGIC3 0xD4
66#define AIX_LABEL_MAGIC4 0xC1
67static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
68{
69 struct partition *pt = (struct partition *) (p + 0x1be);
70 Sector sect;
71 unsigned char *d;
72 int slot, ret = 0;
73
74 if (!(p[0] == AIX_LABEL_MAGIC1 &&
75 p[1] == AIX_LABEL_MAGIC2 &&
76 p[2] == AIX_LABEL_MAGIC3 &&
77 p[3] == AIX_LABEL_MAGIC4))
78 return 0;
79 /* Assume the partition table is valid if Linux partitions exists */
80 for (slot = 1; slot <= 4; slot++, pt++) {
81 if (pt->sys_ind == LINUX_SWAP_PARTITION ||
82 pt->sys_ind == LINUX_RAID_PARTITION ||
83 pt->sys_ind == LINUX_DATA_PARTITION ||
84 pt->sys_ind == LINUX_LVM_PARTITION ||
85 is_extended_partition(pt))
86 return 0;
87 }
88 d = read_part_sector(state, 7, &sect);
89 if (d) {
90 if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
91 ret = 1;
92 put_dev_sector(sect);
93 };
94 return ret;
95}
96
97/*
98 * Create devices for each logical partition in an extended partition.
99 * The logical partitions form a linked list, with each entry being
100 * a partition table with two entries. The first entry
101 * is the real data partition (with a start relative to the partition
102 * table start). The second is a pointer to the next logical partition
103 * (with a start relative to the entire extended partition).
104 * We do not create a Linux partition for the partition tables, but
105 * only for the actual data partitions.
106 */
107
108static void parse_extended(struct parsed_partitions *state,
109 sector_t first_sector, sector_t first_size)
110{
111 struct partition *p;
112 Sector sect;
113 unsigned char *data;
114 sector_t this_sector, this_size;
115 sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
116 int loopct = 0; /* number of links followed
117 without finding a data partition */
118 int i;
119
120 this_sector = first_sector;
121 this_size = first_size;
122
123 while (1) {
124 if (++loopct > 100)
125 return;
126 if (state->next == state->limit)
127 return;
128 data = read_part_sector(state, this_sector, &sect);
129 if (!data)
130 return;
131
132 if (!msdos_magic_present(data + 510))
133 goto done;
134
135 p = (struct partition *) (data + 0x1be);
136
137 /*
138 * Usually, the first entry is the real data partition,
139 * the 2nd entry is the next extended partition, or empty,
140 * and the 3rd and 4th entries are unused.
141 * However, DRDOS sometimes has the extended partition as
142 * the first entry (when the data partition is empty),
143 * and OS/2 seems to use all four entries.
144 */
145
146 /*
147 * First process the data partition(s)
148 */
149 for (i=0; i<4; i++, p++) {
150 sector_t offs, size, next;
151 if (!nr_sects(p) || is_extended_partition(p))
152 continue;
153
154 /* Check the 3rd and 4th entries -
155 these sometimes contain random garbage */
156 offs = start_sect(p)*sector_size;
157 size = nr_sects(p)*sector_size;
158 next = this_sector + offs;
159 if (i >= 2) {
160 if (offs + size > this_size)
161 continue;
162 if (next < first_sector)
163 continue;
164 if (next + size > first_sector + first_size)
165 continue;
166 }
167
168 put_partition(state, state->next, next, size);
169 if (SYS_IND(p) == LINUX_RAID_PARTITION)
170 state->parts[state->next].flags = ADDPART_FLAG_RAID;
171 loopct = 0;
172 if (++state->next == state->limit)
173 goto done;
174 }
175 /*
176 * Next, process the (first) extended partition, if present.
177 * (So far, there seems to be no reason to make
178 * parse_extended() recursive and allow a tree
179 * of extended partitions.)
180 * It should be a link to the next logical partition.
181 */
182 p -= 4;
183 for (i=0; i<4; i++, p++)
184 if (nr_sects(p) && is_extended_partition(p))
185 break;
186 if (i == 4)
187 goto done; /* nothing left to do */
188
189 this_sector = first_sector + start_sect(p) * sector_size;
190 this_size = nr_sects(p) * sector_size;
191 put_dev_sector(sect);
192 }
193done:
194 put_dev_sector(sect);
195}
196
197/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
198 indicates linux swap. Be careful before believing this is Solaris. */
199
200static void parse_solaris_x86(struct parsed_partitions *state,
201 sector_t offset, sector_t size, int origin)
202{
203#ifdef CONFIG_SOLARIS_X86_PARTITION
204 Sector sect;
205 struct solaris_x86_vtoc *v;
206 int i;
207 short max_nparts;
208
209 v = read_part_sector(state, offset + 1, &sect);
210 if (!v)
211 return;
212 if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
213 put_dev_sector(sect);
214 return;
215 }
216 {
217 char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1];
218
219 snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin);
220 strlcat(state->pp_buf, tmp, PAGE_SIZE);
221 }
222 if (le32_to_cpu(v->v_version) != 1) {
223 char tmp[64];
224
225 snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n",
226 le32_to_cpu(v->v_version));
227 strlcat(state->pp_buf, tmp, PAGE_SIZE);
228 put_dev_sector(sect);
229 return;
230 }
231 /* Ensure we can handle previous case of VTOC with 8 entries gracefully */
232 max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8;
233 for (i=0; i<max_nparts && state->next<state->limit; i++) {
234 struct solaris_x86_slice *s = &v->v_slice[i];
235 char tmp[3 + 10 + 1 + 1];
236
237 if (s->s_size == 0)
238 continue;
239 snprintf(tmp, sizeof(tmp), " [s%d]", i);
240 strlcat(state->pp_buf, tmp, PAGE_SIZE);
241 /* solaris partitions are relative to current MS-DOS
242 * one; must add the offset of the current partition */
243 put_partition(state, state->next++,
244 le32_to_cpu(s->s_start)+offset,
245 le32_to_cpu(s->s_size));
246 }
247 put_dev_sector(sect);
248 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
249#endif
250}
251
252#if defined(CONFIG_BSD_DISKLABEL)
253/*
254 * Create devices for BSD partitions listed in a disklabel, under a
255 * dos-like partition. See parse_extended() for more information.
256 */
257static void parse_bsd(struct parsed_partitions *state,
258 sector_t offset, sector_t size, int origin, char *flavour,
259 int max_partitions)
260{
261 Sector sect;
262 struct bsd_disklabel *l;
263 struct bsd_partition *p;
264 char tmp[64];
265
266 l = read_part_sector(state, offset + 1, &sect);
267 if (!l)
268 return;
269 if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
270 put_dev_sector(sect);
271 return;
272 }
273
274 snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
275 strlcat(state->pp_buf, tmp, PAGE_SIZE);
276
277 if (le16_to_cpu(l->d_npartitions) < max_partitions)
278 max_partitions = le16_to_cpu(l->d_npartitions);
279 for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
280 sector_t bsd_start, bsd_size;
281
282 if (state->next == state->limit)
283 break;
284 if (p->p_fstype == BSD_FS_UNUSED)
285 continue;
286 bsd_start = le32_to_cpu(p->p_offset);
287 bsd_size = le32_to_cpu(p->p_size);
288 if (offset == bsd_start && size == bsd_size)
289 /* full parent partition, we have it already */
290 continue;
291 if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
292 strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE);
293 continue;
294 }
295 put_partition(state, state->next++, bsd_start, bsd_size);
296 }
297 put_dev_sector(sect);
298 if (le16_to_cpu(l->d_npartitions) > max_partitions) {
299 snprintf(tmp, sizeof(tmp), " (ignored %d more)",
300 le16_to_cpu(l->d_npartitions) - max_partitions);
301 strlcat(state->pp_buf, tmp, PAGE_SIZE);
302 }
303 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
304}
305#endif
306
307static void parse_freebsd(struct parsed_partitions *state,
308 sector_t offset, sector_t size, int origin)
309{
310#ifdef CONFIG_BSD_DISKLABEL
311 parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
312#endif
313}
314
315static void parse_netbsd(struct parsed_partitions *state,
316 sector_t offset, sector_t size, int origin)
317{
318#ifdef CONFIG_BSD_DISKLABEL
319 parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
320#endif
321}
322
323static void parse_openbsd(struct parsed_partitions *state,
324 sector_t offset, sector_t size, int origin)
325{
326#ifdef CONFIG_BSD_DISKLABEL
327 parse_bsd(state, offset, size, origin, "openbsd",
328 OPENBSD_MAXPARTITIONS);
329#endif
330}
331
332/*
333 * Create devices for Unixware partitions listed in a disklabel, under a
334 * dos-like partition. See parse_extended() for more information.
335 */
336static void parse_unixware(struct parsed_partitions *state,
337 sector_t offset, sector_t size, int origin)
338{
339#ifdef CONFIG_UNIXWARE_DISKLABEL
340 Sector sect;
341 struct unixware_disklabel *l;
342 struct unixware_slice *p;
343
344 l = read_part_sector(state, offset + 29, &sect);
345 if (!l)
346 return;
347 if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
348 le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
349 put_dev_sector(sect);
350 return;
351 }
352 {
353 char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1];
354
355 snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin);
356 strlcat(state->pp_buf, tmp, PAGE_SIZE);
357 }
358 p = &l->vtoc.v_slice[1];
359 /* I omit the 0th slice as it is the same as whole disk. */
360 while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
361 if (state->next == state->limit)
362 break;
363
364 if (p->s_label != UNIXWARE_FS_UNUSED)
365 put_partition(state, state->next++,
366 le32_to_cpu(p->start_sect),
367 le32_to_cpu(p->nr_sects));
368 p++;
369 }
370 put_dev_sector(sect);
371 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
372#endif
373}
374
375/*
376 * Minix 2.0.0/2.0.2 subpartition support.
377 * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
378 * Rajeev V. Pillai <rajeevvp@yahoo.com>
379 */
380static void parse_minix(struct parsed_partitions *state,
381 sector_t offset, sector_t size, int origin)
382{
383#ifdef CONFIG_MINIX_SUBPARTITION
384 Sector sect;
385 unsigned char *data;
386 struct partition *p;
387 int i;
388
389 data = read_part_sector(state, offset, &sect);
390 if (!data)
391 return;
392
393 p = (struct partition *)(data + 0x1be);
394
395 /* The first sector of a Minix partition can have either
396 * a secondary MBR describing its subpartitions, or
397 * the normal boot sector. */
398 if (msdos_magic_present (data + 510) &&
399 SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
400 char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1];
401
402 snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin);
403 strlcat(state->pp_buf, tmp, PAGE_SIZE);
404 for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
405 if (state->next == state->limit)
406 break;
407 /* add each partition in use */
408 if (SYS_IND(p) == MINIX_PARTITION)
409 put_partition(state, state->next++,
410 start_sect(p), nr_sects(p));
411 }
412 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
413 }
414 put_dev_sector(sect);
415#endif /* CONFIG_MINIX_SUBPARTITION */
416}
417
418static struct {
419 unsigned char id;
420 void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
421} subtypes[] = {
422 {FREEBSD_PARTITION, parse_freebsd},
423 {NETBSD_PARTITION, parse_netbsd},
424 {OPENBSD_PARTITION, parse_openbsd},
425 {MINIX_PARTITION, parse_minix},
426 {UNIXWARE_PARTITION, parse_unixware},
427 {SOLARIS_X86_PARTITION, parse_solaris_x86},
428 {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
429 {0, NULL},
430};
431
432int msdos_partition(struct parsed_partitions *state)
433{
434 sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
435 Sector sect;
436 unsigned char *data;
437 struct partition *p;
438 struct fat_boot_sector *fb;
439 int slot;
440
441 data = read_part_sector(state, 0, &sect);
442 if (!data)
443 return -1;
444 if (!msdos_magic_present(data + 510)) {
445 put_dev_sector(sect);
446 return 0;
447 }
448
449 if (aix_magic_present(state, data)) {
450 put_dev_sector(sect);
451 strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
452 return 0;
453 }
454
455 /*
456 * Now that the 55aa signature is present, this is probably
457 * either the boot sector of a FAT filesystem or a DOS-type
458 * partition table. Reject this in case the boot indicator
459 * is not 0 or 0x80.
460 */
461 p = (struct partition *) (data + 0x1be);
462 for (slot = 1; slot <= 4; slot++, p++) {
463 if (p->boot_ind != 0 && p->boot_ind != 0x80) {
464 /*
465 * Even without a valid boot inidicator value
466 * its still possible this is valid FAT filesystem
467 * without a partition table.
468 */
469 fb = (struct fat_boot_sector *) data;
470 if (slot == 1 && fb->reserved && fb->fats
471 && fat_valid_media(fb->media)) {
472 strlcat(state->pp_buf, "\n", PAGE_SIZE);
473 put_dev_sector(sect);
474 return 1;
475 } else {
476 put_dev_sector(sect);
477 return 0;
478 }
479 }
480 }
481
482#ifdef CONFIG_EFI_PARTITION
483 p = (struct partition *) (data + 0x1be);
484 for (slot = 1 ; slot <= 4 ; slot++, p++) {
485 /* If this is an EFI GPT disk, msdos should ignore it. */
486 if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
487 put_dev_sector(sect);
488 return 0;
489 }
490 }
491#endif
492 p = (struct partition *) (data + 0x1be);
493
494 /*
495 * Look for partitions in two passes:
496 * First find the primary and DOS-type extended partitions.
497 * On the second pass look inside *BSD, Unixware and Solaris partitions.
498 */
499
500 state->next = 5;
501 for (slot = 1 ; slot <= 4 ; slot++, p++) {
502 sector_t start = start_sect(p)*sector_size;
503 sector_t size = nr_sects(p)*sector_size;
504 if (!size)
505 continue;
506 if (is_extended_partition(p)) {
507 /*
508 * prevent someone doing mkfs or mkswap on an
509 * extended partition, but leave room for LILO
510 * FIXME: this uses one logical sector for > 512b
511 * sector, although it may not be enough/proper.
512 */
513 sector_t n = 2;
514 n = min(size, max(sector_size, n));
515 put_partition(state, slot, start, n);
516
517 strlcat(state->pp_buf, " <", PAGE_SIZE);
518 parse_extended(state, start, size);
519 strlcat(state->pp_buf, " >", PAGE_SIZE);
520 continue;
521 }
522 put_partition(state, slot, start, size);
523 if (SYS_IND(p) == LINUX_RAID_PARTITION)
524 state->parts[slot].flags = ADDPART_FLAG_RAID;
525 if (SYS_IND(p) == DM6_PARTITION)
526 strlcat(state->pp_buf, "[DM]", PAGE_SIZE);
527 if (SYS_IND(p) == EZD_PARTITION)
528 strlcat(state->pp_buf, "[EZD]", PAGE_SIZE);
529 }
530
531 strlcat(state->pp_buf, "\n", PAGE_SIZE);
532
533 /* second pass - output for each on a separate line */
534 p = (struct partition *) (0x1be + data);
535 for (slot = 1 ; slot <= 4 ; slot++, p++) {
536 unsigned char id = SYS_IND(p);
537 int n;
538
539 if (!nr_sects(p))
540 continue;
541
542 for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
543 ;
544
545 if (!subtypes[n].parse)
546 continue;
547 subtypes[n].parse(state, start_sect(p) * sector_size,
548 nr_sects(p) * sector_size, slot);
549 }
550 put_dev_sector(sect);
551 return 1;
552}
diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h
new file mode 100644
index 00000000000..38c781c490b
--- /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);
8
diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c
new file mode 100644
index 00000000000..764b86a0196
--- /dev/null
+++ b/fs/partitions/osf.c
@@ -0,0 +1,86 @@
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
13#define MAX_OSF_PARTITIONS 18
14
15int osf_partition(struct parsed_partitions *state)
16{
17 int i;
18 int slot = 1;
19 unsigned int npartitions;
20 Sector sect;
21 unsigned char *data;
22 struct disklabel {
23 __le32 d_magic;
24 __le16 d_type,d_subtype;
25 u8 d_typename[16];
26 u8 d_packname[16];
27 __le32 d_secsize;
28 __le32 d_nsectors;
29 __le32 d_ntracks;
30 __le32 d_ncylinders;
31 __le32 d_secpercyl;
32 __le32 d_secprtunit;
33 __le16 d_sparespertrack;
34 __le16 d_sparespercyl;
35 __le32 d_acylinders;
36 __le16 d_rpm, d_interleave, d_trackskew, d_cylskew;
37 __le32 d_headswitch, d_trkseek, d_flags;
38 __le32 d_drivedata[5];
39 __le32 d_spare[5];
40 __le32 d_magic2;
41 __le16 d_checksum;
42 __le16 d_npartitions;
43 __le32 d_bbsize, d_sbsize;
44 struct d_partition {
45 __le32 p_size;
46 __le32 p_offset;
47 __le32 p_fsize;
48 u8 p_fstype;
49 u8 p_frag;
50 __le16 p_cpg;
51 } d_partitions[MAX_OSF_PARTITIONS];
52 } * label;
53 struct d_partition * partition;
54
55 data = read_part_sector(state, 0, &sect);
56 if (!data)
57 return -1;
58
59 label = (struct disklabel *) (data+64);
60 partition = label->d_partitions;
61 if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
62 put_dev_sector(sect);
63 return 0;
64 }
65 if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
66 put_dev_sector(sect);
67 return 0;
68 }
69 npartitions = le16_to_cpu(label->d_npartitions);
70 if (npartitions > MAX_OSF_PARTITIONS) {
71 put_dev_sector(sect);
72 return 0;
73 }
74 for (i = 0 ; i < npartitions; i++, partition++) {
75 if (slot == state->limit)
76 break;
77 if (le32_to_cpu(partition->p_size))
78 put_partition(state, slot,
79 le32_to_cpu(partition->p_offset),
80 le32_to_cpu(partition->p_size));
81 slot++;
82 }
83 strlcat(state->pp_buf, "\n", PAGE_SIZE);
84 put_dev_sector(sect);
85 return 1;
86}
diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h
new file mode 100644
index 00000000000..20ed2315ec1
--- /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);
diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c
new file mode 100644
index 00000000000..ea8a86dceaf
--- /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)
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 = read_part_sector(state, 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(state->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 = ADDPART_FLAG_RAID;
76 }
77 slot++;
78 }
79 strlcat(state->pp_buf, "\n", PAGE_SIZE);
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..b9553ebdd5a
--- /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);
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..b5b6fcfb3d3
--- /dev/null
+++ b/fs/partitions/sun.c
@@ -0,0 +1,122 @@
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)
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 struct sun_vtoc {
23 __be32 version; /* Layout version */
24 char volume[8]; /* Volume name */
25 __be16 nparts; /* Number of partitions */
26 struct sun_info { /* Partition hdrs, sec 2 */
27 __be16 id;
28 __be16 flags;
29 } infos[8];
30 __be16 padding; /* Alignment padding */
31 __be32 bootinfo[3]; /* Info needed by mboot */
32 __be32 sanity; /* To verify vtoc sanity */
33 __be32 reserved[10]; /* Free space */
34 __be32 timestamp[8]; /* Partition timestamp */
35 } vtoc;
36 __be32 write_reinstruct; /* sectors to skip, writes */
37 __be32 read_reinstruct; /* sectors to skip, reads */
38 unsigned char spare[148]; /* Padding */
39 __be16 rspeed; /* Disk rotational speed */
40 __be16 pcylcount; /* Physical cylinder count */
41 __be16 sparecyl; /* extra sects per cylinder */
42 __be16 obs1; /* gap1 */
43 __be16 obs2; /* gap2 */
44 __be16 ilfact; /* Interleave factor */
45 __be16 ncyl; /* Data cylinder count */
46 __be16 nacyl; /* Alt. cylinder count */
47 __be16 ntrks; /* Tracks per cylinder */
48 __be16 nsect; /* Sectors per track */
49 __be16 obs3; /* bhead - Label head offset */
50 __be16 obs4; /* ppart - Physical Partition */
51 struct sun_partition {
52 __be32 start_cylinder;
53 __be32 num_sectors;
54 } partitions[8];
55 __be16 magic; /* Magic number */
56 __be16 csum; /* Label xor'd checksum */
57 } * label;
58 struct sun_partition *p;
59 unsigned long spc;
60 char b[BDEVNAME_SIZE];
61 int use_vtoc;
62 int nparts;
63
64 label = read_part_sector(state, 0, &sect);
65 if (!label)
66 return -1;
67
68 p = label->partitions;
69 if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
70/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
71 bdevname(bdev, b), be16_to_cpu(label->magic)); */
72 put_dev_sector(sect);
73 return 0;
74 }
75 /* Look at the checksum */
76 ush = ((__be16 *) (label+1)) - 1;
77 for (csum = 0; ush >= ((__be16 *) label);)
78 csum ^= *ush--;
79 if (csum) {
80 printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
81 bdevname(state->bdev, b));
82 put_dev_sector(sect);
83 return 0;
84 }
85
86 /* Check to see if we can use the VTOC table */
87 use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) &&
88 (be32_to_cpu(label->vtoc.version) == 1) &&
89 (be16_to_cpu(label->vtoc.nparts) <= 8));
90
91 /* Use 8 partition entries if not specified in validated VTOC */
92 nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8;
93
94 /*
95 * So that old Linux-Sun partitions continue to work,
96 * alow the VTOC to be used under the additional condition ...
97 */
98 use_vtoc = use_vtoc || !(label->vtoc.sanity ||
99 label->vtoc.version || label->vtoc.nparts);
100 spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
101 for (i = 0; i < nparts; i++, p++) {
102 unsigned long st_sector;
103 unsigned int num_sectors;
104
105 st_sector = be32_to_cpu(p->start_cylinder) * spc;
106 num_sectors = be32_to_cpu(p->num_sectors);
107 if (num_sectors) {
108 put_partition(state, slot, st_sector, num_sectors);
109 state->parts[slot].flags = 0;
110 if (use_vtoc) {
111 if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION)
112 state->parts[slot].flags |= ADDPART_FLAG_RAID;
113 else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK)
114 state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK;
115 }
116 }
117 slot++;
118 }
119 strlcat(state->pp_buf, "\n", PAGE_SIZE);
120 put_dev_sector(sect);
121 return 1;
122}
diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h
new file mode 100644
index 00000000000..2424baa8319
--- /dev/null
+++ b/fs/partitions/sun.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/sun.h
3 */
4
5#define SUN_LABEL_MAGIC 0xDABE
6#define SUN_VTOC_SANITY 0x600DDEEE
7
8int sun_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/sysv68.c b/fs/partitions/sysv68.c
new file mode 100644
index 00000000000..9627ccffc1c
--- /dev/null
+++ b/fs/partitions/sysv68.c
@@ -0,0 +1,95 @@
1/*
2 * fs/partitions/sysv68.c
3 *
4 * Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be>
5 */
6
7#include "check.h"
8#include "sysv68.h"
9
10/*
11 * Volume ID structure: on first 256-bytes sector of disk
12 */
13
14struct volumeid {
15 u8 vid_unused[248];
16 u8 vid_mac[8]; /* ASCII string "MOTOROLA" */
17};
18
19/*
20 * config block: second 256-bytes sector on disk
21 */
22
23struct dkconfig {
24 u8 ios_unused0[128];
25 __be32 ios_slcblk; /* Slice table block number */
26 __be16 ios_slccnt; /* Number of entries in slice table */
27 u8 ios_unused1[122];
28};
29
30/*
31 * combined volumeid and dkconfig block
32 */
33
34struct dkblk0 {
35 struct volumeid dk_vid;
36 struct dkconfig dk_ios;
37};
38
39/*
40 * Slice Table Structure
41 */
42
43struct slice {
44 __be32 nblocks; /* slice size (in blocks) */
45 __be32 blkoff; /* block offset of slice */
46};
47
48
49int sysv68_partition(struct parsed_partitions *state)
50{
51 int i, slices;
52 int slot = 1;
53 Sector sect;
54 unsigned char *data;
55 struct dkblk0 *b;
56 struct slice *slice;
57 char tmp[64];
58
59 data = read_part_sector(state, 0, &sect);
60 if (!data)
61 return -1;
62
63 b = (struct dkblk0 *)data;
64 if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) {
65 put_dev_sector(sect);
66 return 0;
67 }
68 slices = be16_to_cpu(b->dk_ios.ios_slccnt);
69 i = be32_to_cpu(b->dk_ios.ios_slcblk);
70 put_dev_sector(sect);
71
72 data = read_part_sector(state, i, &sect);
73 if (!data)
74 return -1;
75
76 slices -= 1; /* last slice is the whole disk */
77 snprintf(tmp, sizeof(tmp), "sysV68: %s(s%u)", state->name, slices);
78 strlcat(state->pp_buf, tmp, PAGE_SIZE);
79 slice = (struct slice *)data;
80 for (i = 0; i < slices; i++, slice++) {
81 if (slot == state->limit)
82 break;
83 if (be32_to_cpu(slice->nblocks)) {
84 put_partition(state, slot,
85 be32_to_cpu(slice->blkoff),
86 be32_to_cpu(slice->nblocks));
87 snprintf(tmp, sizeof(tmp), "(s%u)", i);
88 strlcat(state->pp_buf, tmp, PAGE_SIZE);
89 }
90 slot++;
91 }
92 strlcat(state->pp_buf, "\n", PAGE_SIZE);
93 put_dev_sector(sect);
94 return 1;
95}
diff --git a/fs/partitions/sysv68.h b/fs/partitions/sysv68.h
new file mode 100644
index 00000000000..bf2f5ffa97a
--- /dev/null
+++ b/fs/partitions/sysv68.h
@@ -0,0 +1 @@
extern int sysv68_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c
new file mode 100644
index 00000000000..8dbaf9f77a9
--- /dev/null
+++ b/fs/partitions/ultrix.c
@@ -0,0 +1,48 @@
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#include "ultrix.h"
11
12int ultrix_partition(struct parsed_partitions *state)
13{
14 int i;
15 Sector sect;
16 unsigned char *data;
17 struct ultrix_disklabel {
18 s32 pt_magic; /* magic no. indicating part. info exits */
19 s32 pt_valid; /* set by driver if pt is current */
20 struct pt_info {
21 s32 pi_nblocks; /* no. of sectors */
22 u32 pi_blkoff; /* block offset for start */
23 } pt_part[8];
24 } *label;
25
26#define PT_MAGIC 0x032957 /* Partition magic number */
27#define PT_VALID 1 /* Indicates if struct is valid */
28
29 data = read_part_sector(state, (16384 - sizeof(*label))/512, &sect);
30 if (!data)
31 return -1;
32
33 label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
34
35 if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
36 for (i=0; i<8; i++)
37 if (label->pt_part[i].pi_nblocks)
38 put_partition(state, i+1,
39 label->pt_part[i].pi_blkoff,
40 label->pt_part[i].pi_nblocks);
41 put_dev_sector(sect);
42 strlcat(state->pp_buf, "\n", PAGE_SIZE);
43 return 1;
44 } else {
45 put_dev_sector(sect);
46 return 0;
47 }
48}
diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h
new file mode 100644
index 00000000000..a3cc00b2bde
--- /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);