File: /usr/src/linux/fs/partitions/ldm.c
1 /*
2 * $Id: ldm.c,v 1.25 2001/07/25 23:32:02 flatcap Exp $
3 *
4 * ldm - Part of the Linux-NTFS project.
5 *
6 * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
7 * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
8 *
9 * Documentation is available at http://linux-ntfs.sf.net/ldm
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program (in the main directory of the Linux-NTFS source
23 * in the file COPYING); if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26 #include <linux/types.h>
27 #include <asm/unaligned.h>
28 #include <asm/byteorder.h>
29 #include <linux/genhd.h>
30 #include <linux/blkdev.h>
31 #include <linux/slab.h>
32 #include "check.h"
33 #include "ldm.h"
34 #include "msdos.h"
35
36 #if 0 /* Fool kernel-doc since it doesn't do macros yet. */
37 /**
38 * ldm_debug - output an error message if debugging was enabled at compile time
39 * @f: a printf format string containing the message
40 * @...: the variables to substitute into @f
41 *
42 * ldm_debug() writes a DEBUG level message to the syslog but only if the
43 * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
44 */
45 static void ldm_debug(const char *f, ...);
46 #endif
47 #ifdef CONFIG_LDM_DEBUG
48 #define ldm_debug(f, a...) \
49 { \
50 printk(LDM_DEBUG " DEBUG (%s, %d): %s: ", \
51 __FILE__, __LINE__, __FUNCTION__); \
52 printk(f, ##a); \
53 }
54 #else /* !CONFIG_LDM_DEBUG */
55 #define ldm_debug(f, a...) do {} while (0)
56 #endif /* !CONFIG_LDM_DEBUG */
57
58 /* Necessary forward declarations. */
59 static int create_partition(struct gendisk *, int, int, int);
60 static int parse_privhead(const u8 *, struct privhead *);
61 static u64 get_vnum(const u8 *, int *);
62 static int get_vstr(const u8 *, u8 *, const int);
63
64 /**
65 * parse_vblk_part - parse a LDM database vblk partition record
66 * @buffer: vblk partition record loaded from the LDM database
67 * @buf_size: size of @buffer in bytes
68 * @vb: in memory vblk structure to return parsed information in
69 *
70 * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition
71 * record, supplied in @buffer and sets up the in memory vblk structure @vb
72 * with the obtained information.
73 *
74 * Return 1 on success and -1 on error, in which case @vb is undefined.
75 */
76 static int parse_vblk_part(const u8 *buffer, const int buf_size,
77 struct vblk *vb)
78 {
79 int err, rel_objid, rel_name, rel_size, rel_parent;
80
81 if (0x34 >= buf_size)
82 return -1;
83 /* Calculate relative offsets. */
84 rel_objid = 1 + buffer[0x18];
85 if (0x18 + rel_objid >= buf_size)
86 return -1;
87 rel_name = 1 + buffer[0x18 + rel_objid] + rel_objid;
88 if (0x34 + rel_name >= buf_size)
89 return -1;
90 rel_size = 1 + buffer[0x34 + rel_name] + rel_name;
91 if (0x34 + rel_size >= buf_size)
92 return -1;
93 rel_parent = 1 + buffer[0x34 + rel_size] + rel_size;
94 if (0x34 + rel_parent >= buf_size)
95 return -1;
96 /* Setup @vb. */
97 vb->vblk_type = VBLK_PART;
98 vb->obj_id = get_vnum(buffer + 0x18, &err);
99 if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size)
100 return -1;
101 vb->disk_id = get_vnum(buffer + 0x34 + rel_parent, &err);
102 if (err || 0x24 + rel_name + 8 > buf_size)
103 return -1;
104 vb->start_sector = BE64(buffer + 0x24 + rel_name);
105 if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size)
106 return -1;
107 vb->num_sectors = get_vnum(buffer + 0x34 + rel_name, &err);
108 if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size)
109 return -1;
110 err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name));
111 if (err == -1)
112 return err;
113 ldm_debug("Parsed Partition VBLK successfully.\n");
114 return 1;
115 }
116
117 /**
118 * parse_vblk - parse a LDM database vblk record
119 * @buffer: vblk record loaded from the LDM database
120 * @buf_size: size of @buffer in bytes
121 * @vb: in memory vblk structure to return parsed information in
122 *
123 * This parses the LDM database vblk record supplied in @buffer and sets up
124 * the in memory vblk structure @vb with the obtained information.
125 *
126 * Return 1 on success, 0 if successful but record not in use, and -1 on error.
127 * If the return value is 0 or -1, @vb is undefined.
128 *
129 * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records
130 * describing a partition. For all others, we just set @vb->vblk_type to 0 and
131 * return success. This of course means that if @vb->vblk_type is zero, all
132 * other fields in @vb are undefined.
133 */
134 static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb)
135 {
136 int err = 1;
137
138 if (buf_size < 0x14)
139 return -1;
140 if (MAGIC_VBLK != BE32(buffer)) {
141 printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n");
142 return -1;
143 }
144 if ((BE16(buffer + 0x0E) == 0) || /* Record is not in use. */
145 (BE16(buffer + 0x0C) != 0)) /* Part 2 of an ext. record */
146 return 0;
147 /* FIXME: What about extended VBLKs? */
148 switch (buffer[0x13]) {
149 case VBLK_PART:
150 err = parse_vblk_part(buffer, buf_size, vb);
151 break;
152 default:
153 vb->vblk_type = 0;
154 }
155 if (err != -1)
156 ldm_debug("Parsed VBLK successfully.\n");
157 return err;
158 }
159
160 /**
161 * create_data_partitions - create the data partition devices
162 * @hd: gendisk structure in which to create the data partitions
163 * @first_sector: first sector within the disk device
164 * @first_part_minor: first minor number of data partition devices
165 * @dev: partition device holding the LDM database
166 * @vm: in memory vmdb structure of @dev
167 * @ph: in memory privhead structure of the disk device
168 * @dk: in memory ldmdisk structure of the disk device
169 *
170 * The database contains ALL the partitions for ALL the disks, so we need to
171 * filter out this specific disk. Using the disk's object id, we can find all
172 * the partitions in the database that belong to this disk.
173 *
174 * For each found partition, we create a corresponding partition device starting
175 * with minor number @first_part_minor.
176 *
177 * Return 1 on success and -1 on error.
178 */
179 static int create_data_partitions(struct gendisk *hd,
180 const unsigned long first_sector, int first_part_minor,
181 const kdev_t dev, const struct vmdb *vm,
182 const struct privhead *ph, const struct ldmdisk *dk)
183 {
184 struct buffer_head *bh;
185 struct vblk *vb;
186 int vblk;
187 int vsize; /* VBLK size. */
188 int perbuf; /* VBLKs per buffer. */
189 int buffer, lastbuf, lastofs, err;
190
191 vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
192 if (!vb)
193 goto no_mem;
194 vsize = vm->vblk_size;
195 if (vsize < 1 || vsize > LDM_BLOCKSIZE)
196 goto err_out;
197 perbuf = LDM_BLOCKSIZE / vsize;
198 if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
199 goto err_out;
200 /* 512 == VMDB size */
201 lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
202 lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
203 if (lastofs)
204 lastbuf++;
205 if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
206 ph->config_size * 512)
207 goto err_out;
208 printk(" <");
209 for (buffer = 0; buffer < lastbuf; buffer++) {
210 if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
211 goto read_err;
212 for (vblk = 0; vblk < perbuf; vblk++) {
213 u8 *block;
214
215 if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
216 break;
217 block = bh->b_data + vsize * vblk;
218 if (block + vsize > (u8*)bh->b_data + LDM_BLOCKSIZE)
219 goto brelse_out;
220 if (parse_vblk(block, LDM_BLOCKSIZE, vb) != 1)
221 continue;
222 if (vb->vblk_type != VBLK_PART)
223 continue;
224 if (dk->obj_id != vb->disk_id)
225 continue;
226 if (create_partition(hd, first_part_minor,
227 first_sector + vb->start_sector +
228 ph->logical_disk_start,
229 vb->num_sectors) == 1)
230 first_part_minor++;
231 }
232 brelse(bh);
233 }
234 printk(" >\n");
235 err = 1;
236 out:
237 kfree(vb);
238 return err;
239 brelse_out:
240 brelse(bh);
241 goto err_out;
242 no_mem:
243 printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
244 goto err_out;
245 read_err:
246 printk(LDM_CRIT "Disk read failed in create_partitions.\n");
247 err_out:
248 err = -1;
249 goto out;
250 }
251
252 /**
253 * get_vnum - convert a variable-width, big endian number, to cpu u64 one
254 * @block: pointer to the variable-width number to convert
255 * @err: address of an integer into which to return the error code.
256 *
257 * This converts a variable-width, big endian number into a 64-bit, CPU format
258 * number and returns the result with err set to 0. If an error occurs return 0
259 * with err set to -1.
260 *
261 * The first byte of a variable-width number is the size of the number in bytes.
262 */
263 static u64 get_vnum(const u8 *block, int *err)
264 {
265 u64 tmp = 0ULL;
266 u8 length = *block++;
267
268 if (length && length <= 8) {
269 while (length--)
270 tmp = (tmp << 8) | *block++;
271 *err = 0;
272 } else {
273 printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length);
274 *err = 1;
275 }
276 return tmp;
277 }
278
279 /**
280 * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one
281 * @block: string to convert
282 * @buffer: output buffer
283 * @buflen: size of output buffer
284 *
285 * This converts @block, a counted, non-null-terminated ASCII string, into a
286 * C-style, null-terminated, ASCII string and returns this in @buffer. The
287 * maximum number of characters converted is given by @buflen.
288 *
289 * The first bytes of a counted string stores the length of the string in bytes.
290 *
291 * Return the number of characters written to @buffer, not including the
292 * terminating null character, on success, and -1 on error, in which case
293 * @buffer is not defined.
294 */
295 static int get_vstr(const u8 *block, u8 *buffer, const int buflen)
296 {
297 int length = block[0];
298
299 if (length < 1)
300 return -1;
301 if (length >= buflen) {
302 printk(LDM_ERR "String too long for buffer in get_vstr(): "
303 "(%d/%d). Truncating.\n", length, buflen);
304 length = buflen - 1;
305 }
306 memcpy(buffer, block + 1, length);
307 buffer[length] = (u8)'\0';
308 return length;
309 }
310
311 /**
312 * get_disk_objid - obtain the object id for the device we are working on
313 * @dev: partition device holding the LDM database
314 * @vm: in memory vmdb structure of the LDM database
315 * @ph: in memory privhead structure of the device we are working on
316 * @dk: in memory ldmdisk structure to return information into
317 *
318 * This obtains the object id for the device we are working on as defined by
319 * the private header @ph. The obtained object id, together with the disk's
320 * GUID from @ph are returned in the ldmdisk structure pointed to by @dk.
321 *
322 * A Disk has two Ids. The main one is a GUID in string format. The second,
323 * used internally for cross-referencing, is a small, sequentially allocated,
324 * number. The PRIVHEAD, just after the partition table, tells us the disk's
325 * GUID. To find the disk's object id, we have to look through the database.
326 *
327 * Return 1 on success and -1 on error, in which case @dk is undefined.
328 */
329 static int get_disk_objid(const kdev_t dev, const struct vmdb *vm,
330 const struct privhead *ph, struct ldmdisk *dk)
331 {
332 struct buffer_head *bh;
333 u8 *disk_id;
334 int vblk;
335 int vsize; /* VBLK size. */
336 int perbuf; /* VBLKs per buffer. */
337 int buffer, lastbuf, lastofs, err;
338
339 disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL);
340 if (!disk_id)
341 goto no_mem;
342 vsize = vm->vblk_size;
343 if (vsize < 1 || vsize > LDM_BLOCKSIZE)
344 goto err_out;
345 perbuf = LDM_BLOCKSIZE / vsize;
346 if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
347 goto err_out;
348 /* 512 == VMDB size */
349 lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
350 lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
351 if (lastofs)
352 lastbuf++;
353 if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
354 ph->config_size * 512)
355 goto err_out;
356 for (buffer = 0; buffer < lastbuf; buffer++) {
357 if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
358 goto read_err;
359 for (vblk = 0; vblk < perbuf; vblk++) {
360 int rel_objid, rel_name, delta;
361 u8 *block;
362
363 if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
364 break;
365 block = bh->b_data + vblk * vsize;
366 delta = vblk * vsize + 0x18;
367 if (delta >= LDM_BLOCKSIZE)
368 goto brelse_out;
369 if (block[0x13] != VBLK_DISK)
370 continue;
371 /* Calculate relative offsets. */
372 rel_objid = 1 + block[0x18];
373 if (delta + rel_objid >= LDM_BLOCKSIZE)
374 goto brelse_out;
375 rel_name = 1 + block[0x18 + rel_objid] + rel_objid;
376 if (delta + rel_name >= LDM_BLOCKSIZE ||
377 delta + rel_name + block[0x18 + rel_name] >=
378 LDM_BLOCKSIZE)
379 goto brelse_out;
380 err = get_vstr(block + 0x18 + rel_name, disk_id,
381 DISK_ID_SIZE);
382 if (err == -1)
383 goto brelse_out;
384 if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
385 dk->obj_id = get_vnum(block + 0x18, &err);
386 brelse(bh);
387 if (err)
388 goto out;
389 strncpy(dk->disk_id, ph->disk_id,
390 sizeof(dk->disk_id));
391 dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0';
392 err = 1;
393 goto out;
394 }
395 }
396 brelse(bh);
397 }
398 err = -1;
399 out:
400 kfree(disk_id);
401 return err;
402 brelse_out:
403 brelse(bh);
404 goto err_out;
405 no_mem:
406 printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
407 goto err_out;
408 read_err:
409 printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");
410 err_out:
411 err = -1;
412 goto out;
413 }
414
415 /**
416 * parse_vmdb - parse the LDM database vmdb structure
417 * @buffer: LDM database vmdb structure loaded from the device
418 * @vm: in memory vmdb structure to return parsed information in
419 *
420 * This parses the LDM database vmdb structure supplied in @buffer and sets up
421 * the in memory vmdb structure @vm with the obtained information.
422 *
423 * Return 1 on success and -1 on error, in which case @vm is undefined.
424 *
425 * NOTE: The *_start, *_size and *_seq values returned in @vm have not been
426 * checked for validity, so make sure to check them when using them.
427 */
428 static int parse_vmdb(const u8 *buffer, struct vmdb *vm)
429 {
430 if (MAGIC_VMDB != BE32(buffer)) {
431 printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n");
432 return -1;
433 }
434 vm->ver_major = BE16(buffer + 0x12);
435 vm->ver_minor = BE16(buffer + 0x14);
436 if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
437 printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. "
438 "Aborting.\n", 4, 10, vm->ver_major,
439 vm->ver_minor);
440 return -1;
441 }
442 vm->vblk_size = BE32(buffer + 0x08);
443 vm->vblk_offset = BE32(buffer + 0x0C);
444 vm->last_vblk_seq = BE32(buffer + 0x04);
445
446 ldm_debug("Parsed VMDB successfully.\n");
447 return 1;
448 }
449
450 /**
451 * validate_vmdb - validate the vmdb
452 * @dev: partition device holding the LDM database
453 * @vm: in memory vmdb in which to return information
454 *
455 * Find the vmdb of the LDM database stored on @dev and return the parsed
456 * information into @vm.
457 *
458 * Return 1 on success and -1 on error, in which case @vm is undefined.
459 */
460 static int validate_vmdb(const kdev_t dev, struct vmdb *vm)
461 {
462 struct buffer_head *bh;
463 int ret;
464
465 if (!(bh = bread(dev, OFF_VMDB, LDM_BLOCKSIZE))) {
466 printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
467 return -1;
468 }
469 ret = parse_vmdb(bh->b_data + 0x200, vm);
470 brelse(bh);
471 return ret;
472 }
473
474 /**
475 * compare_tocblocks - compare two tables of contents
476 * @toc1: first toc
477 * @toc2: second toc
478 *
479 * This compares the two tables of contents @toc1 and @toc2.
480 *
481 * Return 1 if @toc1 and @toc2 are equal and -1 otherwise.
482 */
483 static int compare_tocblocks(const struct tocblock *toc1,
484 const struct tocblock *toc2)
485 {
486 if ((toc1->bitmap1_start == toc2->bitmap1_start) &&
487 (toc1->bitmap1_size == toc2->bitmap1_size) &&
488 (toc1->bitmap2_start == toc2->bitmap2_start) &&
489 (toc1->bitmap2_size == toc2->bitmap2_size) &&
490 !strncmp(toc1->bitmap1_name, toc2->bitmap1_name,
491 sizeof(toc1->bitmap1_name)) &&
492 !strncmp(toc1->bitmap2_name, toc2->bitmap2_name,
493 sizeof(toc1->bitmap2_name)))
494 return 1;
495 return -1;
496 }
497
498 /**
499 * parse_tocblock - parse the LDM database table of contents structure
500 * @buffer: LDM database toc structure loaded from the device
501 * @toc: in memory toc structure to return parsed information in
502 *
503 * This parses the LDM database table of contents structure supplied in @buffer
504 * and sets up the in memory table of contents structure @toc with the obtained
505 * information.
506 *
507 * Return 1 on success and -1 on error, in which case @toc is undefined.
508 *
509 * FIXME: The *_start and *_size values returned in @toc are not been checked
510 * for validity but as we don't use the actual values for anything other than
511 * comparing between the toc and its backups, the values are not important.
512 */
513 static int parse_tocblock(const u8 *buffer, struct tocblock *toc)
514 {
515 if (MAGIC_TOCBLOCK != BE64(buffer)) {
516 printk(LDM_CRIT "Cannot find TOCBLOCK, database may be "
517 "corrupt.\n");
518 return -1;
519 }
520 strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name));
521 toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0';
522 toc->bitmap1_start = BE64(buffer + 0x2E);
523 toc->bitmap1_size = BE64(buffer + 0x36);
524 /*toc->bitmap1_flags = BE64(buffer + 0x3E);*/
525 if (strncmp(toc->bitmap1_name, TOC_BITMAP1,
526 sizeof(toc->bitmap1_name)) != 0) {
527 printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is "
528 "%s.\n", TOC_BITMAP1, toc->bitmap1_name);
529 return -1;
530 }
531 strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name));
532 toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0';
533 toc->bitmap2_start = BE64(buffer + 0x50);
534 toc->bitmap2_size = BE64(buffer + 0x58);
535 /*toc->bitmap2_flags = BE64(buffer + 0x60);*/
536 if (strncmp(toc->bitmap2_name, TOC_BITMAP2,
537 sizeof(toc->bitmap2_name)) != 0) {
538 printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is "
539 "%s.\n", TOC_BITMAP2, toc->bitmap2_name);
540 return -1;
541 }
542 ldm_debug("Parsed TOCBLOCK successfully.\n");
543 return 1;
544 }
545
546 /**
547 * validate_tocblocks - validate the table of contents and its backups
548 * @dev: partition device holding the LDM database
549 * @toc1: in memory table of contents in which to return information
550 *
551 * Find and compare the four tables of contents of the LDM database stored on
552 * @dev and return the parsed information into @toc1.
553 *
554 * Return 1 on success and -1 on error, in which case @toc1 is undefined.
555 */
556 static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1)
557 {
558 struct buffer_head *bh;
559 struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
560 int err;
561
562 toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL);
563 if (!toc2)
564 goto no_mem;
565 toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL);
566 if (!toc3)
567 goto no_mem;
568 toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL);
569 if (!toc4)
570 goto no_mem;
571 /* Read and parse first toc. */
572 if (!(bh = bread(devdb, OFF_TOCBLOCK1, LDM_BLOCKSIZE))) {
573 printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
574 goto err_out;
575 }
576 err = parse_tocblock(bh->b_data + 0x0200, toc1);
577 brelse(bh);
578 if (err != 1)
579 goto out;
580 /* Read and parse second toc. */
581 if (!(bh = bread(devdb, OFF_TOCBLOCK2, LDM_BLOCKSIZE))) {
582 printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
583 goto err_out;
584 }
585 err = parse_tocblock(bh->b_data, toc2);
586 brelse(bh);
587 if (err != 1)
588 goto out;
589 /* Read and parse third toc. */
590 if (!(bh = bread(devdb, OFF_TOCBLOCK3, LDM_BLOCKSIZE))) {
591 printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
592 goto err_out;
593 }
594 err = parse_tocblock(bh->b_data + 0x0200, toc3);
595 brelse(bh);
596 if (err != 1)
597 goto out;
598 /* Read and parse fourth toc. */
599 if (!(bh = bread(devdb, OFF_TOCBLOCK4, LDM_BLOCKSIZE))) {
600 printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
601 goto err_out;
602 }
603 err = parse_tocblock(bh->b_data, toc4);
604 brelse(bh);
605 if (err != 1)
606 goto out;
607 /* Compare all tocs. */
608 err = compare_tocblocks(toc1, toc2);
609 if (err != 1) {
610 printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n");
611 goto out;
612 }
613 err = compare_tocblocks(toc3, toc4);
614 if (err != 1) {
615 printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n");
616 goto out;
617 }
618 err = compare_tocblocks(toc1, toc3);
619 if (err != 1)
620 printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n");
621 else
622 ldm_debug("Validated TOCBLOCKs successfully.\n");
623 out:
624 kfree(toc2);
625 kfree(toc3);
626 kfree(toc4);
627 return err;
628 no_mem:
629 printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
630 err_out:
631 err = -1;
632 goto out;
633 }
634
635 /**
636 * compare_privheads - compare two privheads
637 * @ph1: first privhead
638 * @ph2: second privhead
639 *
640 * This compares the two privheads @ph1 and @ph2.
641 *
642 * Return 1 if @ph1 and @ph2 are equal and -1 otherwise.
643 */
644 static int compare_privheads(const struct privhead *ph1,
645 const struct privhead *ph2)
646 {
647 if ((ph1->ver_major == ph2->ver_major) &&
648 (ph1->ver_minor == ph2->ver_minor) &&
649 (ph1->logical_disk_start == ph2->logical_disk_start) &&
650 (ph1->logical_disk_size == ph2->logical_disk_size) &&
651 (ph1->config_start == ph2->config_start) &&
652 (ph1->config_size == ph2->config_size) &&
653 !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id)))
654 return 1;
655 return -1;
656 }
657
658 /**
659 * validate_privheads - compare the privhead backups to the first one
660 * @dev: partition device holding the LDM database
661 * @ph1: first privhead which we have already validated before
662 *
663 * We already have one privhead from the beginning of the disk.
664 * Now we compare the two other copies for safety.
665 *
666 * Return 1 on succes and -1 on error.
667 */
668 static int validate_privheads(const kdev_t dev, const struct privhead *ph1)
669 {
670 struct buffer_head *bh;
671 struct privhead *ph2 = NULL, *ph3 = NULL;
672 int err;
673
674 ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL);
675 if (!ph2)
676 goto no_mem;
677 ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
678 if (!ph3)
679 goto no_mem;
680 if (!(bh = bread(dev, OFF_PRIVHEAD2, LDM_BLOCKSIZE))) {
681 printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
682 goto err_out;
683 }
684 err = parse_privhead(bh->b_data, ph2);
685 brelse(bh);
686 if (err != 1)
687 goto out;
688 if (!(bh = bread(dev, OFF_PRIVHEAD3, LDM_BLOCKSIZE))) {
689 printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
690 goto err_out;
691 }
692 err = parse_privhead(bh->b_data + 0x0200, ph3);
693 brelse(bh);
694 if (err != 1)
695 goto out;
696 err = compare_privheads(ph1, ph2);
697 if (err != 1) {
698 printk(LDM_CRIT "First and second PRIVHEADs don't match.\n");
699 goto out;
700 }
701 err = compare_privheads(ph1, ph3);
702 if (err != 1)
703 printk(LDM_CRIT "First and third PRIVHEADs don't match.\n");
704 else
705 /* We _could_ have checked more. */
706 ldm_debug("Validated PRIVHEADs successfully.\n");
707 out:
708 kfree(ph2);
709 kfree(ph3);
710 return err;
711 no_mem:
712 printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
713 err_out:
714 err = -1;
715 goto out;
716 }
717
718 /**
719 * create_partition - validate input and create a kernel partition device
720 * @hd: gendisk structure in which to create partition
721 * @minor: minor number for device to create
722 * @start: starting offset of the partition into the parent device
723 * @size: size of the partition
724 *
725 * This validates the range, then puts an entry into the kernel's partition
726 * table.
727 *
728 * @start and @size are numbers of sectors.
729 *
730 * Return 1 on succes and -1 on error.
731 */
732 static int create_partition(struct gendisk *hd, const int minor,
733 const int start, const int size)
734 {
735 int disk_minor;
736
737 if (!hd->part)
738 return -1;
739 /*
740 * Get the minor number of the parent device so we can check we don't
741 * go beyond the end of the device.
742 */
743 disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
744 if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
745 printk(LDM_CRIT "LDM Partition exceeds physical disk. "
746 "Aborting.\n");
747 return -1;
748 }
749 add_gd_partition(hd, minor, start, size);
750 ldm_debug("Created partition successfully.\n");
751 return 1;
752 }
753
754 /**
755 * parse_privhead - parse the LDM database PRIVHEAD structure
756 * @buffer: LDM database privhead structure loaded from the device
757 * @ph: in memory privhead structure to return parsed information in
758 *
759 * This parses the LDM database PRIVHEAD structure supplied in @buffer and
760 * sets up the in memory privhead structure @ph with the obtained information.
761 *
762 * Return 1 on succes and -1 on error, in which case @ph is undefined.
763 */
764 static int parse_privhead(const u8 *buffer, struct privhead *ph)
765 {
766 if (MAGIC_PRIVHEAD != BE64(buffer)) {
767 printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database "
768 "is corrupt. Aborting.\n");
769 return -1;
770 }
771 ph->ver_major = BE16(buffer + 0x000C);
772 ph->ver_minor = BE16(buffer + 0x000E);
773 if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
774 printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. "
775 "Aborting.\n", 2, 11, ph->ver_major,
776 ph->ver_minor);
777 return -1;
778 }
779 ph->config_start = BE64(buffer + 0x012B);
780 ph->config_size = BE64(buffer + 0x0133);
781 if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
782 printk(LDM_ERR "Database should be %u bytes, claims to be %Lu "
783 "bytes. Aborting.\n", LDM_DB_SIZE,
784 ph->config_size);
785 return -1;
786 }
787 ph->logical_disk_start = BE64(buffer + 0x011B);
788 ph->logical_disk_size = BE64(buffer + 0x0123);
789 if (!ph->logical_disk_size ||
790 ph->logical_disk_start + ph->logical_disk_size > ph->config_start)
791 return -1;
792
793 memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id));
794
795 ldm_debug("Parsed PRIVHEAD successfully.\n");
796 return 1;
797 }
798
799 /**
800 * create_db_partition - create a dedicated partition for our database
801 * @hd: gendisk structure in which to create partition
802 * @dev: device of which to create partition
803 * @ph: @dev's LDM database private header
804 *
805 * Find the primary private header, locate the LDM database, then create a
806 * partition to wrap it.
807 *
808 * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
809 */
810 static int create_db_partition(struct gendisk *hd, const kdev_t dev,
811 const unsigned long first_sector, const int first_part_minor,
812 struct privhead *ph)
813 {
814 struct buffer_head *bh;
815 int err;
816
817 if (!(bh = bread(dev, OFF_PRIVHEAD1, LDM_BLOCKSIZE))) {
818 printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
819 return -1;
820 }
821 if (BE64(bh->b_data) != MAGIC_PRIVHEAD) {
822 ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
823 "or corrupt LDM database.\n");
824 return 0;
825 }
826 err = parse_privhead(bh->b_data, ph);
827 if (err == 1)
828 err = create_partition(hd, first_part_minor, first_sector +
829 ph->config_start, ph->config_size);
830 brelse(bh);
831 return err;
832 }
833
834 /**
835 * validate_patition_table - check whether @dev is a dynamic disk
836 * @dev: device to test
837 *
838 * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition
839 * table with one or more entries of type 0x42 (the former Secure File System
840 * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it.
841 * If this succeeds we assume we have a dynamic disk, and not otherwise.
842 *
843 * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
844 */
845 static int validate_partition_table(const kdev_t dev)
846 {
847 struct buffer_head *bh;
848 struct partition *p;
849 int i, nr_sfs;
850
851 if (!(bh = bread(dev, 0, LDM_BLOCKSIZE))) {
852 if (warn_no_part)
853 printk(LDM_ERR "Unable to read partition table.\n");
854 return -1;
855 }
856 if (*(u16*)(bh->b_data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
857 ldm_debug("No MS-DOS partition found.\n");
858 goto no_msdos_partition;
859 }
860 nr_sfs = 0;
861 p = (struct partition*)(bh->b_data + 0x01BE);
862 for (i = 0; i < 4; i++) {
863 if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
864 continue;
865 if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) {
866 nr_sfs++;
867 continue;
868 }
869 goto not_dynamic_disk;
870 }
871 if (!nr_sfs)
872 goto not_dynamic_disk;
873 ldm_debug("Parsed partition table successfully.\n");
874 brelse(bh);
875 return 1;
876 not_dynamic_disk:
877 ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
878 no_msdos_partition:
879 brelse(bh);
880 return 0;
881 }
882
883 /**
884 * ldm_partition - find out whether a device is a dynamic disk and handle it
885 * @hd: gendisk structure in which to return the handled disk
886 * @dev: device we need to look at
887 * @first_sector: first sector within the device
888 * @first_part_minor: first minor number of partitions for the device
889 *
890 * Description:
891 *
892 * This determines whether the device @dev is a dynamic disk and if so creates
893 * the partitions necessary in the gendisk structure pointed to by @hd.
894 *
895 * We create a dummy device 1, which contains the LDM database, we skip
896 * devices 2-4 and then create each partition described by the LDM database
897 * in sequence as devices 5 and following. For example, if the device is hda,
898 * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the
899 * actual data containing partitions.
900 *
901 * Return values:
902 *
903 * 1 if @dev is a dynamic disk and we handled it,
904 * 0 if @dev is not a dynamic disk,
905 * -1 if an error occured.
906 */
907 int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
908 int first_part_minor)
909 {
910 kdev_t devdb;
911 struct privhead *ph = NULL;
912 struct tocblock *toc = NULL;
913 struct vmdb *vm = NULL;
914 struct ldmdisk *dk = NULL;
915 int err;
916
917 if (!hd)
918 return 0;
919 err = (int)get_ptable_blocksize(dev);
920 if (err != LDM_BLOCKSIZE) { /* 1024 bytes */
921 ldm_debug("Expected a blocksize of %d bytes, got %d instead.\n",
922 LDM_BLOCKSIZE, get_ptable_blocksize(dev));
923 return 0;
924 }
925 err = get_hardsect_size(dev);
926 if (err != 512) {
927 ldm_debug("Expected a sector size of %d bytes, got %d "
928 "instead.\n", 512, get_hardsect_size(dev));
929 return 0;
930 }
931 /* Check the partition table. */
932 err = validate_partition_table(dev);
933 if (err != 1)
934 return err;
935 if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
936 goto no_mem;
937 /* Create the LDM database device. */
938 err = create_db_partition(hd, dev, first_sector, first_part_minor, ph);
939 if (err != 1)
940 goto out;
941 /* For convenience, work with the LDM database device from now on. */
942 devdb = MKDEV(MAJOR(dev), first_part_minor);
943 /* Check the backup privheads. */
944 err = validate_privheads(devdb, ph);
945 if (err != 1)
946 goto out;
947 /* Check the table of contents and its backups. */
948 if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
949 goto no_mem;
950 err = validate_tocblocks(devdb, toc);
951 if (err != 1)
952 goto out;
953 /* Check the vmdb. */
954 if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
955 goto no_mem;
956 err = validate_vmdb(devdb, vm);
957 if (err != 1)
958 goto out;
959 /* Find the object id for @dev in the LDM database. */
960 if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
961 goto no_mem;
962 err = get_disk_objid(devdb, vm, ph, dk);
963 if (err != 1)
964 goto out;
965 /* Finally, create the data partition devices. */
966 err = create_data_partitions(hd, first_sector, first_part_minor +
967 LDM_FIRST_PART_OFFSET, devdb, vm, ph, dk);
968 if (err == 1)
969 ldm_debug("Parsed LDM database successfully.\n");
970 out:
971 kfree(ph);
972 kfree(toc);
973 kfree(vm);
974 kfree(dk);
975 return err;
976 no_mem:
977 printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
978 err = -1;
979 goto out;
980 }
981
982