0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/slab.h>
0013 #include <linux/pagemap.h>
0014 #include <linux/stringify.h>
0015 #include <linux/kernel.h>
0016 #include <linux/uuid.h>
0017 #include <linux/msdos_partition.h>
0018
0019 #include "ldm.h"
0020 #include "check.h"
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #ifndef CONFIG_LDM_DEBUG
0031 #define ldm_debug(...) do {} while (0)
0032 #else
0033 #define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __func__, f, ##a)
0034 #endif
0035
0036 #define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __func__, f, ##a)
0037 #define ldm_error(f, a...) _ldm_printk (KERN_ERR, __func__, f, ##a)
0038 #define ldm_info(f, a...) _ldm_printk (KERN_INFO, __func__, f, ##a)
0039
0040 static __printf(3, 4)
0041 void _ldm_printk(const char *level, const char *function, const char *fmt, ...)
0042 {
0043 struct va_format vaf;
0044 va_list args;
0045
0046 va_start (args, fmt);
0047
0048 vaf.fmt = fmt;
0049 vaf.va = &args;
0050
0051 printk("%s%s(): %pV\n", level, function, &vaf);
0052
0053 va_end(args);
0054 }
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 static bool ldm_parse_privhead(const u8 *data, struct privhead *ph)
0068 {
0069 bool is_vista = false;
0070
0071 BUG_ON(!data || !ph);
0072 if (MAGIC_PRIVHEAD != get_unaligned_be64(data)) {
0073 ldm_error("Cannot find PRIVHEAD structure. LDM database is"
0074 " corrupt. Aborting.");
0075 return false;
0076 }
0077 ph->ver_major = get_unaligned_be16(data + 0x000C);
0078 ph->ver_minor = get_unaligned_be16(data + 0x000E);
0079 ph->logical_disk_start = get_unaligned_be64(data + 0x011B);
0080 ph->logical_disk_size = get_unaligned_be64(data + 0x0123);
0081 ph->config_start = get_unaligned_be64(data + 0x012B);
0082 ph->config_size = get_unaligned_be64(data + 0x0133);
0083
0084 if (ph->ver_major == 2 && ph->ver_minor == 12)
0085 is_vista = true;
0086 if (!is_vista && (ph->ver_major != 2 || ph->ver_minor != 11)) {
0087 ldm_error("Expected PRIVHEAD version 2.11 or 2.12, got %d.%d."
0088 " Aborting.", ph->ver_major, ph->ver_minor);
0089 return false;
0090 }
0091 ldm_debug("PRIVHEAD version %d.%d (Windows %s).", ph->ver_major,
0092 ph->ver_minor, is_vista ? "Vista" : "2000/XP");
0093 if (ph->config_size != LDM_DB_SIZE) {
0094
0095 ldm_info("Database is normally %u bytes, it claims to "
0096 "be %llu bytes.", LDM_DB_SIZE,
0097 (unsigned long long)ph->config_size);
0098 }
0099 if ((ph->logical_disk_size == 0) || (ph->logical_disk_start +
0100 ph->logical_disk_size > ph->config_start)) {
0101 ldm_error("PRIVHEAD disk size doesn't match real disk size");
0102 return false;
0103 }
0104 if (uuid_parse(data + 0x0030, &ph->disk_id)) {
0105 ldm_error("PRIVHEAD contains an invalid GUID.");
0106 return false;
0107 }
0108 ldm_debug("Parsed PRIVHEAD successfully.");
0109 return true;
0110 }
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
0127 {
0128 BUG_ON (!data || !toc);
0129
0130 if (MAGIC_TOCBLOCK != get_unaligned_be64(data)) {
0131 ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
0132 return false;
0133 }
0134 strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
0135 toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
0136 toc->bitmap1_start = get_unaligned_be64(data + 0x2E);
0137 toc->bitmap1_size = get_unaligned_be64(data + 0x36);
0138
0139 if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
0140 sizeof (toc->bitmap1_name)) != 0) {
0141 ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
0142 TOC_BITMAP1, toc->bitmap1_name);
0143 return false;
0144 }
0145 strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
0146 toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
0147 toc->bitmap2_start = get_unaligned_be64(data + 0x50);
0148 toc->bitmap2_size = get_unaligned_be64(data + 0x58);
0149 if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
0150 sizeof (toc->bitmap2_name)) != 0) {
0151 ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
0152 TOC_BITMAP2, toc->bitmap2_name);
0153 return false;
0154 }
0155 ldm_debug ("Parsed TOCBLOCK successfully.");
0156 return true;
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172 static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
0173 {
0174 BUG_ON (!data || !vm);
0175
0176 if (MAGIC_VMDB != get_unaligned_be32(data)) {
0177 ldm_crit ("Cannot find the VMDB, database may be corrupt.");
0178 return false;
0179 }
0180
0181 vm->ver_major = get_unaligned_be16(data + 0x12);
0182 vm->ver_minor = get_unaligned_be16(data + 0x14);
0183 if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
0184 ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
0185 "Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
0186 return false;
0187 }
0188
0189 vm->vblk_size = get_unaligned_be32(data + 0x08);
0190 if (vm->vblk_size == 0) {
0191 ldm_error ("Illegal VBLK size");
0192 return false;
0193 }
0194
0195 vm->vblk_offset = get_unaligned_be32(data + 0x0C);
0196 vm->last_vblk_seq = get_unaligned_be32(data + 0x04);
0197
0198 ldm_debug ("Parsed VMDB successfully.");
0199 return true;
0200 }
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 static bool ldm_compare_privheads (const struct privhead *ph1,
0213 const struct privhead *ph2)
0214 {
0215 BUG_ON (!ph1 || !ph2);
0216
0217 return ((ph1->ver_major == ph2->ver_major) &&
0218 (ph1->ver_minor == ph2->ver_minor) &&
0219 (ph1->logical_disk_start == ph2->logical_disk_start) &&
0220 (ph1->logical_disk_size == ph2->logical_disk_size) &&
0221 (ph1->config_start == ph2->config_start) &&
0222 (ph1->config_size == ph2->config_size) &&
0223 uuid_equal(&ph1->disk_id, &ph2->disk_id));
0224 }
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static bool ldm_compare_tocblocks (const struct tocblock *toc1,
0237 const struct tocblock *toc2)
0238 {
0239 BUG_ON (!toc1 || !toc2);
0240
0241 return ((toc1->bitmap1_start == toc2->bitmap1_start) &&
0242 (toc1->bitmap1_size == toc2->bitmap1_size) &&
0243 (toc1->bitmap2_start == toc2->bitmap2_start) &&
0244 (toc1->bitmap2_size == toc2->bitmap2_size) &&
0245 !strncmp (toc1->bitmap1_name, toc2->bitmap1_name,
0246 sizeof (toc1->bitmap1_name)) &&
0247 !strncmp (toc1->bitmap2_name, toc2->bitmap2_name,
0248 sizeof (toc1->bitmap2_name)));
0249 }
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 static bool ldm_validate_privheads(struct parsed_partitions *state,
0266 struct privhead *ph1)
0267 {
0268 static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
0269 struct privhead *ph[3] = { ph1 };
0270 Sector sect;
0271 u8 *data;
0272 bool result = false;
0273 long num_sects;
0274 int i;
0275
0276 BUG_ON (!state || !ph1);
0277
0278 ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL);
0279 ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL);
0280 if (!ph[1] || !ph[2]) {
0281 ldm_crit ("Out of memory.");
0282 goto out;
0283 }
0284
0285
0286 ph[0]->config_start = 0;
0287
0288
0289 for (i = 0; i < 3; i++) {
0290 data = read_part_sector(state, ph[0]->config_start + off[i],
0291 §);
0292 if (!data) {
0293 ldm_crit ("Disk read failed.");
0294 goto out;
0295 }
0296 result = ldm_parse_privhead (data, ph[i]);
0297 put_dev_sector (sect);
0298 if (!result) {
0299 ldm_error ("Cannot find PRIVHEAD %d.", i+1);
0300 if (i < 2)
0301 goto out;
0302 else
0303 break;
0304 }
0305 }
0306
0307 num_sects = get_capacity(state->disk);
0308
0309 if ((ph[0]->config_start > num_sects) ||
0310 ((ph[0]->config_start + ph[0]->config_size) > num_sects)) {
0311 ldm_crit ("Database extends beyond the end of the disk.");
0312 goto out;
0313 }
0314
0315 if ((ph[0]->logical_disk_start > ph[0]->config_start) ||
0316 ((ph[0]->logical_disk_start + ph[0]->logical_disk_size)
0317 > ph[0]->config_start)) {
0318 ldm_crit ("Disk and database overlap.");
0319 goto out;
0320 }
0321
0322 if (!ldm_compare_privheads (ph[0], ph[1])) {
0323 ldm_crit ("Primary and backup PRIVHEADs don't match.");
0324 goto out;
0325 }
0326
0327
0328
0329
0330
0331 ldm_debug ("Validated PRIVHEADs successfully.");
0332 result = true;
0333 out:
0334 kfree (ph[1]);
0335 kfree (ph[2]);
0336 return result;
0337 }
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353 static bool ldm_validate_tocblocks(struct parsed_partitions *state,
0354 unsigned long base, struct ldmdb *ldb)
0355 {
0356 static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
0357 struct tocblock *tb[4];
0358 struct privhead *ph;
0359 Sector sect;
0360 u8 *data;
0361 int i, nr_tbs;
0362 bool result = false;
0363
0364 BUG_ON(!state || !ldb);
0365 ph = &ldb->ph;
0366 tb[0] = &ldb->toc;
0367 tb[1] = kmalloc_array(3, sizeof(*tb[1]), GFP_KERNEL);
0368 if (!tb[1]) {
0369 ldm_crit("Out of memory.");
0370 goto err;
0371 }
0372 tb[2] = (struct tocblock*)((u8*)tb[1] + sizeof(*tb[1]));
0373 tb[3] = (struct tocblock*)((u8*)tb[2] + sizeof(*tb[2]));
0374
0375
0376
0377
0378
0379
0380 for (nr_tbs = i = 0; i < 4; i++) {
0381 data = read_part_sector(state, base + off[i], §);
0382 if (!data) {
0383 ldm_error("Disk read failed for TOCBLOCK %d.", i);
0384 continue;
0385 }
0386 if (ldm_parse_tocblock(data, tb[nr_tbs]))
0387 nr_tbs++;
0388 put_dev_sector(sect);
0389 }
0390 if (!nr_tbs) {
0391 ldm_crit("Failed to find a valid TOCBLOCK.");
0392 goto err;
0393 }
0394
0395 if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
0396 ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) >
0397 ph->config_size)) {
0398 ldm_crit("The bitmaps are out of range. Giving up.");
0399 goto err;
0400 }
0401
0402 for (i = 1; i < nr_tbs; i++) {
0403 if (!ldm_compare_tocblocks(tb[0], tb[i])) {
0404 ldm_crit("TOCBLOCKs 0 and %d do not match.", i);
0405 goto err;
0406 }
0407 }
0408 ldm_debug("Validated %d TOCBLOCKs successfully.", nr_tbs);
0409 result = true;
0410 err:
0411 kfree(tb[1]);
0412 return result;
0413 }
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427 static bool ldm_validate_vmdb(struct parsed_partitions *state,
0428 unsigned long base, struct ldmdb *ldb)
0429 {
0430 Sector sect;
0431 u8 *data;
0432 bool result = false;
0433 struct vmdb *vm;
0434 struct tocblock *toc;
0435
0436 BUG_ON (!state || !ldb);
0437
0438 vm = &ldb->vm;
0439 toc = &ldb->toc;
0440
0441 data = read_part_sector(state, base + OFF_VMDB, §);
0442 if (!data) {
0443 ldm_crit ("Disk read failed.");
0444 return false;
0445 }
0446
0447 if (!ldm_parse_vmdb (data, vm))
0448 goto out;
0449
0450
0451 if (get_unaligned_be16(data + 0x10) != 0x01) {
0452 ldm_crit ("Database is not in a consistent state. Aborting.");
0453 goto out;
0454 }
0455
0456 if (vm->vblk_offset != 512)
0457 ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
0458
0459
0460
0461
0462
0463 if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) {
0464 ldm_crit ("VMDB exceeds allowed size specified by TOCBLOCK. "
0465 "Database is corrupt. Aborting.");
0466 goto out;
0467 }
0468
0469 result = true;
0470 out:
0471 put_dev_sector (sect);
0472 return result;
0473 }
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492 static bool ldm_validate_partition_table(struct parsed_partitions *state)
0493 {
0494 Sector sect;
0495 u8 *data;
0496 struct msdos_partition *p;
0497 int i;
0498 bool result = false;
0499
0500 BUG_ON(!state);
0501
0502 data = read_part_sector(state, 0, §);
0503 if (!data) {
0504 ldm_info ("Disk read failed.");
0505 return false;
0506 }
0507
0508 if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
0509 goto out;
0510
0511 p = (struct msdos_partition *)(data + 0x01BE);
0512 for (i = 0; i < 4; i++, p++)
0513 if (p->sys_ind == LDM_PARTITION) {
0514 result = true;
0515 break;
0516 }
0517
0518 if (result)
0519 ldm_debug ("Found W2K dynamic disk partition type.");
0520
0521 out:
0522 put_dev_sector (sect);
0523 return result;
0524 }
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538 static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
0539 {
0540 struct list_head *item;
0541
0542 BUG_ON (!ldb);
0543
0544 list_for_each (item, &ldb->v_disk) {
0545 struct vblk *v = list_entry (item, struct vblk, list);
0546 if (uuid_equal(&v->vblk.disk.disk_id, &ldb->ph.disk_id))
0547 return v;
0548 }
0549
0550 return NULL;
0551 }
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570 static bool ldm_create_data_partitions (struct parsed_partitions *pp,
0571 const struct ldmdb *ldb)
0572 {
0573 struct list_head *item;
0574 struct vblk *vb;
0575 struct vblk *disk;
0576 struct vblk_part *part;
0577 int part_num = 1;
0578
0579 BUG_ON (!pp || !ldb);
0580
0581 disk = ldm_get_disk_objid (ldb);
0582 if (!disk) {
0583 ldm_crit ("Can't find the ID of this disk in the database.");
0584 return false;
0585 }
0586
0587 strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE);
0588
0589
0590 list_for_each (item, &ldb->v_part) {
0591 vb = list_entry (item, struct vblk, list);
0592 part = &vb->vblk.part;
0593
0594 if (part->disk_id != disk->obj_id)
0595 continue;
0596
0597 put_partition (pp, part_num, ldb->ph.logical_disk_start +
0598 part->start, part->size);
0599 part_num++;
0600 }
0601
0602 strlcat(pp->pp_buf, "\n", PAGE_SIZE);
0603 return true;
0604 }
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621 static int ldm_relative(const u8 *buffer, int buflen, int base, int offset)
0622 {
0623
0624 base += offset;
0625 if (!buffer || offset < 0 || base > buflen) {
0626 if (!buffer)
0627 ldm_error("!buffer");
0628 if (offset < 0)
0629 ldm_error("offset (%d) < 0", offset);
0630 if (base > buflen)
0631 ldm_error("base (%d) > buflen (%d)", base, buflen);
0632 return -1;
0633 }
0634 if (base + buffer[base] >= buflen) {
0635 ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base,
0636 buffer[base], buflen);
0637 return -1;
0638 }
0639 return buffer[base] + offset + 1;
0640 }
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657 static u64 ldm_get_vnum (const u8 *block)
0658 {
0659 u64 tmp = 0;
0660 u8 length;
0661
0662 BUG_ON (!block);
0663
0664 length = *block++;
0665
0666 if (length && length <= 8)
0667 while (length--)
0668 tmp = (tmp << 8) | *block++;
0669 else
0670 ldm_error ("Illegal length %d.", length);
0671
0672 return tmp;
0673 }
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692 static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
0693 {
0694 int length;
0695
0696 BUG_ON (!block || !buffer);
0697
0698 length = block[0];
0699 if (length >= buflen) {
0700 ldm_error ("Truncating string %d -> %d.", length, buflen);
0701 length = buflen - 1;
0702 }
0703 memcpy (buffer, block + 1, length);
0704 buffer[length] = 0;
0705 return length;
0706 }
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720 static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
0721 {
0722 int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
0723 struct vblk_comp *comp;
0724
0725 BUG_ON (!buffer || !vb);
0726
0727 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
0728 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
0729 r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
0730 r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate);
0731 r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
0732
0733 if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
0734 r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
0735 r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe);
0736 len = r_cols;
0737 } else {
0738 r_stripe = 0;
0739 len = r_parent;
0740 }
0741 if (len < 0)
0742 return false;
0743
0744 len += VBLK_SIZE_CMP3;
0745 if (len != get_unaligned_be32(buffer + 0x14))
0746 return false;
0747
0748 comp = &vb->vblk.comp;
0749 ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
0750 sizeof (comp->state));
0751 comp->type = buffer[0x18 + r_vstate];
0752 comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate);
0753 comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
0754 comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
0755
0756 return true;
0757 }
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770 static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
0771 {
0772 int r_objid, r_name, r_diskid, r_id1, r_id2, len;
0773 struct vblk_dgrp *dgrp;
0774
0775 BUG_ON (!buffer || !vb);
0776
0777 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
0778 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
0779 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
0780
0781 if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
0782 r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
0783 r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
0784 len = r_id2;
0785 } else
0786 len = r_diskid;
0787 if (len < 0)
0788 return false;
0789
0790 len += VBLK_SIZE_DGR3;
0791 if (len != get_unaligned_be32(buffer + 0x14))
0792 return false;
0793
0794 dgrp = &vb->vblk.dgrp;
0795 ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
0796 sizeof (dgrp->disk_id));
0797 return true;
0798 }
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811 static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
0812 {
0813 char buf[64];
0814 int r_objid, r_name, r_id1, r_id2, len;
0815
0816 BUG_ON (!buffer || !vb);
0817
0818 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
0819 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
0820
0821 if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
0822 r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
0823 r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
0824 len = r_id2;
0825 } else
0826 len = r_name;
0827 if (len < 0)
0828 return false;
0829
0830 len += VBLK_SIZE_DGR4;
0831 if (len != get_unaligned_be32(buffer + 0x14))
0832 return false;
0833
0834 ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
0835 return true;
0836 }
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849 static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
0850 {
0851 int r_objid, r_name, r_diskid, r_altname, len;
0852 struct vblk_disk *disk;
0853
0854 BUG_ON (!buffer || !vb);
0855
0856 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
0857 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
0858 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
0859 r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
0860 len = r_altname;
0861 if (len < 0)
0862 return false;
0863
0864 len += VBLK_SIZE_DSK3;
0865 if (len != get_unaligned_be32(buffer + 0x14))
0866 return false;
0867
0868 disk = &vb->vblk.disk;
0869 ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
0870 sizeof (disk->alt_name));
0871 if (uuid_parse(buffer + 0x19 + r_name, &disk->disk_id))
0872 return false;
0873
0874 return true;
0875 }
0876
0877
0878
0879
0880
0881
0882
0883
0884
0885
0886
0887
0888 static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
0889 {
0890 int r_objid, r_name, len;
0891 struct vblk_disk *disk;
0892
0893 BUG_ON (!buffer || !vb);
0894
0895 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
0896 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
0897 len = r_name;
0898 if (len < 0)
0899 return false;
0900
0901 len += VBLK_SIZE_DSK4;
0902 if (len != get_unaligned_be32(buffer + 0x14))
0903 return false;
0904
0905 disk = &vb->vblk.disk;
0906 import_uuid(&disk->disk_id, buffer + 0x18 + r_name);
0907 return true;
0908 }
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921 static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb)
0922 {
0923 int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
0924 struct vblk_part *part;
0925
0926 BUG_ON(!buffer || !vb);
0927 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
0928 if (r_objid < 0) {
0929 ldm_error("r_objid %d < 0", r_objid);
0930 return false;
0931 }
0932 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
0933 if (r_name < 0) {
0934 ldm_error("r_name %d < 0", r_name);
0935 return false;
0936 }
0937 r_size = ldm_relative(buffer, buflen, 0x34, r_name);
0938 if (r_size < 0) {
0939 ldm_error("r_size %d < 0", r_size);
0940 return false;
0941 }
0942 r_parent = ldm_relative(buffer, buflen, 0x34, r_size);
0943 if (r_parent < 0) {
0944 ldm_error("r_parent %d < 0", r_parent);
0945 return false;
0946 }
0947 r_diskid = ldm_relative(buffer, buflen, 0x34, r_parent);
0948 if (r_diskid < 0) {
0949 ldm_error("r_diskid %d < 0", r_diskid);
0950 return false;
0951 }
0952 if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
0953 r_index = ldm_relative(buffer, buflen, 0x34, r_diskid);
0954 if (r_index < 0) {
0955 ldm_error("r_index %d < 0", r_index);
0956 return false;
0957 }
0958 len = r_index;
0959 } else
0960 len = r_diskid;
0961 if (len < 0) {
0962 ldm_error("len %d < 0", len);
0963 return false;
0964 }
0965 len += VBLK_SIZE_PRT3;
0966 if (len > get_unaligned_be32(buffer + 0x14)) {
0967 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
0968 get_unaligned_be32(buffer + 0x14));
0969 return false;
0970 }
0971 part = &vb->vblk.part;
0972 part->start = get_unaligned_be64(buffer + 0x24 + r_name);
0973 part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name);
0974 part->size = ldm_get_vnum(buffer + 0x34 + r_name);
0975 part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size);
0976 part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent);
0977 if (vb->flags & VBLK_FLAG_PART_INDEX)
0978 part->partnum = buffer[0x35 + r_diskid];
0979 else
0980 part->partnum = 0;
0981 return true;
0982 }
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995 static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb)
0996 {
0997 int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;
0998 int r_id1, r_id2, r_size2, r_drive, len;
0999 struct vblk_volu *volu;
1000
1001 BUG_ON(!buffer || !vb);
1002 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1003 if (r_objid < 0) {
1004 ldm_error("r_objid %d < 0", r_objid);
1005 return false;
1006 }
1007 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1008 if (r_name < 0) {
1009 ldm_error("r_name %d < 0", r_name);
1010 return false;
1011 }
1012 r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);
1013 if (r_vtype < 0) {
1014 ldm_error("r_vtype %d < 0", r_vtype);
1015 return false;
1016 }
1017 r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);
1018 if (r_disable_drive_letter < 0) {
1019 ldm_error("r_disable_drive_letter %d < 0",
1020 r_disable_drive_letter);
1021 return false;
1022 }
1023 r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);
1024 if (r_child < 0) {
1025 ldm_error("r_child %d < 0", r_child);
1026 return false;
1027 }
1028 r_size = ldm_relative(buffer, buflen, 0x3D, r_child);
1029 if (r_size < 0) {
1030 ldm_error("r_size %d < 0", r_size);
1031 return false;
1032 }
1033 if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {
1034 r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);
1035 if (r_id1 < 0) {
1036 ldm_error("r_id1 %d < 0", r_id1);
1037 return false;
1038 }
1039 } else
1040 r_id1 = r_size;
1041 if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {
1042 r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);
1043 if (r_id2 < 0) {
1044 ldm_error("r_id2 %d < 0", r_id2);
1045 return false;
1046 }
1047 } else
1048 r_id2 = r_id1;
1049 if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {
1050 r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);
1051 if (r_size2 < 0) {
1052 ldm_error("r_size2 %d < 0", r_size2);
1053 return false;
1054 }
1055 } else
1056 r_size2 = r_id2;
1057 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1058 r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);
1059 if (r_drive < 0) {
1060 ldm_error("r_drive %d < 0", r_drive);
1061 return false;
1062 }
1063 } else
1064 r_drive = r_size2;
1065 len = r_drive;
1066 if (len < 0) {
1067 ldm_error("len %d < 0", len);
1068 return false;
1069 }
1070 len += VBLK_SIZE_VOL5;
1071 if (len > get_unaligned_be32(buffer + 0x14)) {
1072 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1073 get_unaligned_be32(buffer + 0x14));
1074 return false;
1075 }
1076 volu = &vb->vblk.volu;
1077 ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,
1078 sizeof(volu->volume_type));
1079 memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,
1080 sizeof(volu->volume_state));
1081 volu->size = ldm_get_vnum(buffer + 0x3D + r_child);
1082 volu->partition_type = buffer[0x41 + r_size];
1083 memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));
1084 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1085 ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,
1086 sizeof(volu->drive_hint));
1087 }
1088 return true;
1089 }
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104 static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
1105 {
1106 bool result = false;
1107 int r_objid;
1108
1109 BUG_ON (!buf || !vb);
1110
1111 r_objid = ldm_relative (buf, len, 0x18, 0);
1112 if (r_objid < 0) {
1113 ldm_error ("VBLK header is corrupt.");
1114 return false;
1115 }
1116
1117 vb->flags = buf[0x12];
1118 vb->type = buf[0x13];
1119 vb->obj_id = ldm_get_vnum (buf + 0x18);
1120 ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
1121
1122 switch (vb->type) {
1123 case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break;
1124 case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break;
1125 case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break;
1126 case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break;
1127 case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break;
1128 case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break;
1129 case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break;
1130 }
1131
1132 if (result)
1133 ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
1134 (unsigned long long) vb->obj_id, vb->type);
1135 else
1136 ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
1137 (unsigned long long) vb->obj_id, vb->type);
1138
1139 return result;
1140 }
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156 static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
1157 {
1158 struct vblk *vb;
1159 struct list_head *item;
1160
1161 BUG_ON (!data || !ldb);
1162
1163 vb = kmalloc (sizeof (*vb), GFP_KERNEL);
1164 if (!vb) {
1165 ldm_crit ("Out of memory.");
1166 return false;
1167 }
1168
1169 if (!ldm_parse_vblk (data, len, vb)) {
1170 kfree(vb);
1171 return false;
1172 }
1173
1174
1175 switch (vb->type) {
1176 case VBLK_DGR3:
1177 case VBLK_DGR4:
1178 list_add (&vb->list, &ldb->v_dgrp);
1179 break;
1180 case VBLK_DSK3:
1181 case VBLK_DSK4:
1182 list_add (&vb->list, &ldb->v_disk);
1183 break;
1184 case VBLK_VOL5:
1185 list_add (&vb->list, &ldb->v_volu);
1186 break;
1187 case VBLK_CMP3:
1188 list_add (&vb->list, &ldb->v_comp);
1189 break;
1190 case VBLK_PRT3:
1191
1192 list_for_each (item, &ldb->v_part) {
1193 struct vblk *v = list_entry (item, struct vblk, list);
1194 if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
1195 (v->vblk.part.start > vb->vblk.part.start)) {
1196 list_add_tail (&vb->list, &v->list);
1197 return true;
1198 }
1199 }
1200 list_add_tail (&vb->list, &ldb->v_part);
1201 break;
1202 }
1203 return true;
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218 static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
1219 {
1220 struct frag *f;
1221 struct list_head *item;
1222 int rec, num, group;
1223
1224 BUG_ON (!data || !frags);
1225
1226 if (size < 2 * VBLK_SIZE_HEAD) {
1227 ldm_error("Value of size is too small.");
1228 return false;
1229 }
1230
1231 group = get_unaligned_be32(data + 0x08);
1232 rec = get_unaligned_be16(data + 0x0C);
1233 num = get_unaligned_be16(data + 0x0E);
1234 if ((num < 1) || (num > 4)) {
1235 ldm_error ("A VBLK claims to have %d parts.", num);
1236 return false;
1237 }
1238 if (rec >= num) {
1239 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num);
1240 return false;
1241 }
1242
1243 list_for_each (item, frags) {
1244 f = list_entry (item, struct frag, list);
1245 if (f->group == group)
1246 goto found;
1247 }
1248
1249 f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
1250 if (!f) {
1251 ldm_crit ("Out of memory.");
1252 return false;
1253 }
1254
1255 f->group = group;
1256 f->num = num;
1257 f->rec = rec;
1258 f->map = 0xFF << num;
1259
1260 list_add_tail (&f->list, frags);
1261 found:
1262 if (rec >= f->num) {
1263 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num);
1264 return false;
1265 }
1266 if (f->map & (1 << rec)) {
1267 ldm_error ("Duplicate VBLK, part %d.", rec);
1268 f->map &= 0x7F;
1269 return false;
1270 }
1271 f->map |= (1 << rec);
1272 if (!rec)
1273 memcpy(f->data, data, VBLK_SIZE_HEAD);
1274 data += VBLK_SIZE_HEAD;
1275 size -= VBLK_SIZE_HEAD;
1276 memcpy(f->data + VBLK_SIZE_HEAD + rec * size, data, size);
1277 return true;
1278 }
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288 static void ldm_frag_free (struct list_head *list)
1289 {
1290 struct list_head *item, *tmp;
1291
1292 BUG_ON (!list);
1293
1294 list_for_each_safe (item, tmp, list)
1295 kfree (list_entry (item, struct frag, list));
1296 }
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309 static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
1310 {
1311 struct frag *f;
1312 struct list_head *item;
1313
1314 BUG_ON (!frags || !ldb);
1315
1316 list_for_each (item, frags) {
1317 f = list_entry (item, struct frag, list);
1318
1319 if (f->map != 0xFF) {
1320 ldm_error ("VBLK group %d is incomplete (0x%02x).",
1321 f->group, f->map);
1322 return false;
1323 }
1324
1325 if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
1326 return false;
1327 }
1328 return true;
1329 }
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343 static bool ldm_get_vblks(struct parsed_partitions *state, unsigned long base,
1344 struct ldmdb *ldb)
1345 {
1346 int size, perbuf, skip, finish, s, v, recs;
1347 u8 *data = NULL;
1348 Sector sect;
1349 bool result = false;
1350 LIST_HEAD (frags);
1351
1352 BUG_ON(!state || !ldb);
1353
1354 size = ldb->vm.vblk_size;
1355 perbuf = 512 / size;
1356 skip = ldb->vm.vblk_offset >> 9;
1357 finish = (size * ldb->vm.last_vblk_seq) >> 9;
1358
1359 for (s = skip; s < finish; s++) {
1360 data = read_part_sector(state, base + OFF_VMDB + s, §);
1361 if (!data) {
1362 ldm_crit ("Disk read failed.");
1363 goto out;
1364 }
1365
1366 for (v = 0; v < perbuf; v++, data+=size) {
1367 if (MAGIC_VBLK != get_unaligned_be32(data)) {
1368 ldm_error ("Expected to find a VBLK.");
1369 goto out;
1370 }
1371
1372 recs = get_unaligned_be16(data + 0x0E);
1373 if (recs == 1) {
1374 if (!ldm_ldmdb_add (data, size, ldb))
1375 goto out;
1376 } else if (recs > 1) {
1377 if (!ldm_frag_add (data, size, &frags))
1378 goto out;
1379 }
1380
1381 }
1382 put_dev_sector (sect);
1383 data = NULL;
1384 }
1385
1386 result = ldm_frag_commit (&frags, ldb);
1387 out:
1388 if (data)
1389 put_dev_sector (sect);
1390 ldm_frag_free (&frags);
1391
1392 return result;
1393 }
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403 static void ldm_free_vblks (struct list_head *lh)
1404 {
1405 struct list_head *item, *tmp;
1406
1407 BUG_ON (!lh);
1408
1409 list_for_each_safe (item, tmp, lh)
1410 kfree (list_entry (item, struct vblk, list));
1411 }
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431 int ldm_partition(struct parsed_partitions *state)
1432 {
1433 struct ldmdb *ldb;
1434 unsigned long base;
1435 int result = -1;
1436
1437 BUG_ON(!state);
1438
1439
1440 if (!ldm_validate_partition_table(state))
1441 return 0;
1442
1443 ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
1444 if (!ldb) {
1445 ldm_crit ("Out of memory.");
1446 goto out;
1447 }
1448
1449
1450 if (!ldm_validate_privheads(state, &ldb->ph))
1451 goto out;
1452
1453
1454 base = ldb->ph.config_start;
1455
1456
1457 if (!ldm_validate_tocblocks(state, base, ldb) ||
1458 !ldm_validate_vmdb(state, base, ldb))
1459 goto out;
1460
1461
1462 INIT_LIST_HEAD (&ldb->v_dgrp);
1463 INIT_LIST_HEAD (&ldb->v_disk);
1464 INIT_LIST_HEAD (&ldb->v_volu);
1465 INIT_LIST_HEAD (&ldb->v_comp);
1466 INIT_LIST_HEAD (&ldb->v_part);
1467
1468 if (!ldm_get_vblks(state, base, ldb)) {
1469 ldm_crit ("Failed to read the VBLKs from the database.");
1470 goto cleanup;
1471 }
1472
1473
1474 if (ldm_create_data_partitions(state, ldb)) {
1475 ldm_debug ("Parsed LDM database successfully.");
1476 result = 1;
1477 }
1478
1479
1480 cleanup:
1481 ldm_free_vblks (&ldb->v_dgrp);
1482 ldm_free_vblks (&ldb->v_disk);
1483 ldm_free_vblks (&ldb->v_volu);
1484 ldm_free_vblks (&ldb->v_comp);
1485 ldm_free_vblks (&ldb->v_part);
1486 out:
1487 kfree (ldb);
1488 return result;
1489 }