Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ldm.c
Go to the documentation of this file.
1 
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 
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 static __printf(3, 4)
53 void _ldm_printk(const char *level, const char *function, const char *fmt, ...)
54 {
55  struct va_format vaf;
56  va_list args;
57 
58  va_start (args, fmt);
59 
60  vaf.fmt = fmt;
61  vaf.va = &args;
62 
63  printk("%s%s(): %pV\n", level, function, &vaf);
64 
65  va_end(args);
66 }
67 
77 static int ldm_parse_hexbyte (const u8 *src)
78 {
79  unsigned int x; /* For correct wrapping */
80  int h;
81 
82  /* high part */
83  x = h = hex_to_bin(src[0]);
84  if (h < 0)
85  return -1;
86 
87  /* low part */
88  h = hex_to_bin(src[1]);
89  if (h < 0)
90  return -1;
91 
92  return (x << 4) + h;
93 }
94 
105 static bool ldm_parse_guid (const u8 *src, u8 *dest)
106 {
107  static const int size[] = { 4, 2, 2, 2, 6 };
108  int i, j, v;
109 
110  if (src[8] != '-' || src[13] != '-' ||
111  src[18] != '-' || src[23] != '-')
112  return false;
113 
114  for (j = 0; j < 5; j++, src++)
115  for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
116  if ((v = ldm_parse_hexbyte (src)) < 0)
117  return false;
118 
119  return true;
120 }
121 
133 static bool ldm_parse_privhead(const u8 *data, struct privhead *ph)
134 {
135  bool is_vista = false;
136 
137  BUG_ON(!data || !ph);
138  if (MAGIC_PRIVHEAD != get_unaligned_be64(data)) {
139  ldm_error("Cannot find PRIVHEAD structure. LDM database is"
140  " corrupt. Aborting.");
141  return false;
142  }
143  ph->ver_major = get_unaligned_be16(data + 0x000C);
144  ph->ver_minor = get_unaligned_be16(data + 0x000E);
145  ph->logical_disk_start = get_unaligned_be64(data + 0x011B);
146  ph->logical_disk_size = get_unaligned_be64(data + 0x0123);
147  ph->config_start = get_unaligned_be64(data + 0x012B);
148  ph->config_size = get_unaligned_be64(data + 0x0133);
149  /* Version 2.11 is Win2k/XP and version 2.12 is Vista. */
150  if (ph->ver_major == 2 && ph->ver_minor == 12)
151  is_vista = true;
152  if (!is_vista && (ph->ver_major != 2 || ph->ver_minor != 11)) {
153  ldm_error("Expected PRIVHEAD version 2.11 or 2.12, got %d.%d."
154  " Aborting.", ph->ver_major, ph->ver_minor);
155  return false;
156  }
157  ldm_debug("PRIVHEAD version %d.%d (Windows %s).", ph->ver_major,
158  ph->ver_minor, is_vista ? "Vista" : "2000/XP");
159  if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
160  /* Warn the user and continue, carefully. */
161  ldm_info("Database is normally %u bytes, it claims to "
162  "be %llu bytes.", LDM_DB_SIZE,
163  (unsigned long long)ph->config_size);
164  }
165  if ((ph->logical_disk_size == 0) || (ph->logical_disk_start +
166  ph->logical_disk_size > ph->config_start)) {
167  ldm_error("PRIVHEAD disk size doesn't match real disk size");
168  return false;
169  }
170  if (!ldm_parse_guid(data + 0x0030, ph->disk_id)) {
171  ldm_error("PRIVHEAD contains an invalid GUID.");
172  return false;
173  }
174  ldm_debug("Parsed PRIVHEAD successfully.");
175  return true;
176 }
177 
192 static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
193 {
194  BUG_ON (!data || !toc);
195 
196  if (MAGIC_TOCBLOCK != get_unaligned_be64(data)) {
197  ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
198  return false;
199  }
200  strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
201  toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
202  toc->bitmap1_start = get_unaligned_be64(data + 0x2E);
203  toc->bitmap1_size = get_unaligned_be64(data + 0x36);
204 
205  if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
206  sizeof (toc->bitmap1_name)) != 0) {
207  ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
208  TOC_BITMAP1, toc->bitmap1_name);
209  return false;
210  }
211  strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
212  toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
213  toc->bitmap2_start = get_unaligned_be64(data + 0x50);
214  toc->bitmap2_size = get_unaligned_be64(data + 0x58);
215  if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
216  sizeof (toc->bitmap2_name)) != 0) {
217  ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
218  TOC_BITMAP2, toc->bitmap2_name);
219  return false;
220  }
221  ldm_debug ("Parsed TOCBLOCK successfully.");
222  return true;
223 }
224 
238 static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
239 {
240  BUG_ON (!data || !vm);
241 
242  if (MAGIC_VMDB != get_unaligned_be32(data)) {
243  ldm_crit ("Cannot find the VMDB, database may be corrupt.");
244  return false;
245  }
246 
247  vm->ver_major = get_unaligned_be16(data + 0x12);
248  vm->ver_minor = get_unaligned_be16(data + 0x14);
249  if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
250  ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
251  "Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
252  return false;
253  }
254 
255  vm->vblk_size = get_unaligned_be32(data + 0x08);
256  if (vm->vblk_size == 0) {
257  ldm_error ("Illegal VBLK size");
258  return false;
259  }
260 
261  vm->vblk_offset = get_unaligned_be32(data + 0x0C);
262  vm->last_vblk_seq = get_unaligned_be32(data + 0x04);
263 
264  ldm_debug ("Parsed VMDB successfully.");
265  return true;
266 }
267 
278 static bool ldm_compare_privheads (const struct privhead *ph1,
279  const struct privhead *ph2)
280 {
281  BUG_ON (!ph1 || !ph2);
282 
283  return ((ph1->ver_major == ph2->ver_major) &&
284  (ph1->ver_minor == ph2->ver_minor) &&
285  (ph1->logical_disk_start == ph2->logical_disk_start) &&
286  (ph1->logical_disk_size == ph2->logical_disk_size) &&
287  (ph1->config_start == ph2->config_start) &&
288  (ph1->config_size == ph2->config_size) &&
289  !memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE));
290 }
291 
302 static bool ldm_compare_tocblocks (const struct tocblock *toc1,
303  const struct tocblock *toc2)
304 {
305  BUG_ON (!toc1 || !toc2);
306 
307  return ((toc1->bitmap1_start == toc2->bitmap1_start) &&
308  (toc1->bitmap1_size == toc2->bitmap1_size) &&
309  (toc1->bitmap2_start == toc2->bitmap2_start) &&
310  (toc1->bitmap2_size == toc2->bitmap2_size) &&
311  !strncmp (toc1->bitmap1_name, toc2->bitmap1_name,
312  sizeof (toc1->bitmap1_name)) &&
313  !strncmp (toc1->bitmap2_name, toc2->bitmap2_name,
314  sizeof (toc1->bitmap2_name)));
315 }
316 
331 static bool ldm_validate_privheads(struct parsed_partitions *state,
332  struct privhead *ph1)
333 {
334  static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
335  struct privhead *ph[3] = { ph1 };
336  Sector sect;
337  u8 *data;
338  bool result = false;
339  long num_sects;
340  int i;
341 
342  BUG_ON (!state || !ph1);
343 
344  ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL);
345  ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL);
346  if (!ph[1] || !ph[2]) {
347  ldm_crit ("Out of memory.");
348  goto out;
349  }
350 
351  /* off[1 & 2] are relative to ph[0]->config_start */
352  ph[0]->config_start = 0;
353 
354  /* Read and parse privheads */
355  for (i = 0; i < 3; i++) {
356  data = read_part_sector(state, ph[0]->config_start + off[i],
357  &sect);
358  if (!data) {
359  ldm_crit ("Disk read failed.");
360  goto out;
361  }
362  result = ldm_parse_privhead (data, ph[i]);
363  put_dev_sector (sect);
364  if (!result) {
365  ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */
366  if (i < 2)
367  goto out; /* Already logged */
368  else
369  break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */
370  }
371  }
372 
373  num_sects = state->bdev->bd_inode->i_size >> 9;
374 
375  if ((ph[0]->config_start > num_sects) ||
376  ((ph[0]->config_start + ph[0]->config_size) > num_sects)) {
377  ldm_crit ("Database extends beyond the end of the disk.");
378  goto out;
379  }
380 
381  if ((ph[0]->logical_disk_start > ph[0]->config_start) ||
382  ((ph[0]->logical_disk_start + ph[0]->logical_disk_size)
383  > ph[0]->config_start)) {
384  ldm_crit ("Disk and database overlap.");
385  goto out;
386  }
387 
388  if (!ldm_compare_privheads (ph[0], ph[1])) {
389  ldm_crit ("Primary and backup PRIVHEADs don't match.");
390  goto out;
391  }
392  /* FIXME ignore this for now
393  if (!ldm_compare_privheads (ph[0], ph[2])) {
394  ldm_crit ("Primary and backup PRIVHEADs don't match.");
395  goto out;
396  }*/
397  ldm_debug ("Validated PRIVHEADs successfully.");
398  result = true;
399 out:
400  kfree (ph[1]);
401  kfree (ph[2]);
402  return result;
403 }
404 
419 static bool ldm_validate_tocblocks(struct parsed_partitions *state,
420  unsigned long base, struct ldmdb *ldb)
421 {
422  static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
423  struct tocblock *tb[4];
424  struct privhead *ph;
425  Sector sect;
426  u8 *data;
427  int i, nr_tbs;
428  bool result = false;
429 
430  BUG_ON(!state || !ldb);
431  ph = &ldb->ph;
432  tb[0] = &ldb->toc;
433  tb[1] = kmalloc(sizeof(*tb[1]) * 3, GFP_KERNEL);
434  if (!tb[1]) {
435  ldm_crit("Out of memory.");
436  goto err;
437  }
438  tb[2] = (struct tocblock*)((u8*)tb[1] + sizeof(*tb[1]));
439  tb[3] = (struct tocblock*)((u8*)tb[2] + sizeof(*tb[2]));
440  /*
441  * Try to read and parse all four TOCBLOCKs.
442  *
443  * Windows Vista LDM v2.12 does not always have all four TOCBLOCKs so
444  * skip any that fail as long as we get at least one valid TOCBLOCK.
445  */
446  for (nr_tbs = i = 0; i < 4; i++) {
447  data = read_part_sector(state, base + off[i], &sect);
448  if (!data) {
449  ldm_error("Disk read failed for TOCBLOCK %d.", i);
450  continue;
451  }
452  if (ldm_parse_tocblock(data, tb[nr_tbs]))
453  nr_tbs++;
454  put_dev_sector(sect);
455  }
456  if (!nr_tbs) {
457  ldm_crit("Failed to find a valid TOCBLOCK.");
458  goto err;
459  }
460  /* Range check the TOCBLOCK against a privhead. */
461  if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
462  ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) >
463  ph->config_size)) {
464  ldm_crit("The bitmaps are out of range. Giving up.");
465  goto err;
466  }
467  /* Compare all loaded TOCBLOCKs. */
468  for (i = 1; i < nr_tbs; i++) {
469  if (!ldm_compare_tocblocks(tb[0], tb[i])) {
470  ldm_crit("TOCBLOCKs 0 and %d do not match.", i);
471  goto err;
472  }
473  }
474  ldm_debug("Validated %d TOCBLOCKs successfully.", nr_tbs);
475  result = true;
476 err:
477  kfree(tb[1]);
478  return result;
479 }
480 
493 static bool ldm_validate_vmdb(struct parsed_partitions *state,
494  unsigned long base, struct ldmdb *ldb)
495 {
496  Sector sect;
497  u8 *data;
498  bool result = false;
499  struct vmdb *vm;
500  struct tocblock *toc;
501 
502  BUG_ON (!state || !ldb);
503 
504  vm = &ldb->vm;
505  toc = &ldb->toc;
506 
507  data = read_part_sector(state, base + OFF_VMDB, &sect);
508  if (!data) {
509  ldm_crit ("Disk read failed.");
510  return false;
511  }
512 
513  if (!ldm_parse_vmdb (data, vm))
514  goto out; /* Already logged */
515 
516  /* Are there uncommitted transactions? */
517  if (get_unaligned_be16(data + 0x10) != 0x01) {
518  ldm_crit ("Database is not in a consistent state. Aborting.");
519  goto out;
520  }
521 
522  if (vm->vblk_offset != 512)
523  ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
524 
525  /*
526  * The last_vblkd_seq can be before the end of the vmdb, just make sure
527  * it is not out of bounds.
528  */
529  if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) {
530  ldm_crit ("VMDB exceeds allowed size specified by TOCBLOCK. "
531  "Database is corrupt. Aborting.");
532  goto out;
533  }
534 
535  result = true;
536 out:
537  put_dev_sector (sect);
538  return result;
539 }
540 
541 
558 static bool ldm_validate_partition_table(struct parsed_partitions *state)
559 {
560  Sector sect;
561  u8 *data;
562  struct partition *p;
563  int i;
564  bool result = false;
565 
566  BUG_ON(!state);
567 
568  data = read_part_sector(state, 0, &sect);
569  if (!data) {
570  ldm_info ("Disk read failed.");
571  return false;
572  }
573 
574  if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
575  goto out;
576 
577  p = (struct partition*)(data + 0x01BE);
578  for (i = 0; i < 4; i++, p++)
579  if (SYS_IND (p) == LDM_PARTITION) {
580  result = true;
581  break;
582  }
583 
584  if (result)
585  ldm_debug ("Found W2K dynamic disk partition type.");
586 
587 out:
588  put_dev_sector (sect);
589  return result;
590 }
591 
604 static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
605 {
606  struct list_head *item;
607 
608  BUG_ON (!ldb);
609 
610  list_for_each (item, &ldb->v_disk) {
611  struct vblk *v = list_entry (item, struct vblk, list);
612  if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
613  return v;
614  }
615 
616  return NULL;
617 }
618 
636 static bool ldm_create_data_partitions (struct parsed_partitions *pp,
637  const struct ldmdb *ldb)
638 {
639  struct list_head *item;
640  struct vblk *vb;
641  struct vblk *disk;
642  struct vblk_part *part;
643  int part_num = 1;
644 
645  BUG_ON (!pp || !ldb);
646 
647  disk = ldm_get_disk_objid (ldb);
648  if (!disk) {
649  ldm_crit ("Can't find the ID of this disk in the database.");
650  return false;
651  }
652 
653  strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE);
654 
655  /* Create the data partitions */
656  list_for_each (item, &ldb->v_part) {
657  vb = list_entry (item, struct vblk, list);
658  part = &vb->vblk.part;
659 
660  if (part->disk_id != disk->obj_id)
661  continue;
662 
663  put_partition (pp, part_num, ldb->ph.logical_disk_start +
664  part->start, part->size);
665  part_num++;
666  }
667 
668  strlcat(pp->pp_buf, "\n", PAGE_SIZE);
669  return true;
670 }
671 
672 
687 static int ldm_relative(const u8 *buffer, int buflen, int base, int offset)
688 {
689 
690  base += offset;
691  if (!buffer || offset < 0 || base > buflen) {
692  if (!buffer)
693  ldm_error("!buffer");
694  if (offset < 0)
695  ldm_error("offset (%d) < 0", offset);
696  if (base > buflen)
697  ldm_error("base (%d) > buflen (%d)", base, buflen);
698  return -1;
699  }
700  if (base + buffer[base] >= buflen) {
701  ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base,
702  buffer[base], buflen);
703  return -1;
704  }
705  return buffer[base] + offset + 1;
706 }
707 
723 static u64 ldm_get_vnum (const u8 *block)
724 {
725  u64 tmp = 0;
726  u8 length;
727 
728  BUG_ON (!block);
729 
730  length = *block++;
731 
732  if (length && length <= 8)
733  while (length--)
734  tmp = (tmp << 8) | *block++;
735  else
736  ldm_error ("Illegal length %d.", length);
737 
738  return tmp;
739 }
740 
758 static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
759 {
760  int length;
761 
762  BUG_ON (!block || !buffer);
763 
764  length = block[0];
765  if (length >= buflen) {
766  ldm_error ("Truncating string %d -> %d.", length, buflen);
767  length = buflen - 1;
768  }
769  memcpy (buffer, block + 1, length);
770  buffer[length] = 0;
771  return length;
772 }
773 
774 
786 static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
787 {
788  int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
789  struct vblk_comp *comp;
790 
791  BUG_ON (!buffer || !vb);
792 
793  r_objid = ldm_relative (buffer, buflen, 0x18, 0);
794  r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
795  r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
796  r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate);
797  r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
798 
799  if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
800  r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
801  r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe);
802  len = r_cols;
803  } else {
804  r_stripe = 0;
805  r_cols = 0;
806  len = r_parent;
807  }
808  if (len < 0)
809  return false;
810 
811  len += VBLK_SIZE_CMP3;
812  if (len != get_unaligned_be32(buffer + 0x14))
813  return false;
814 
815  comp = &vb->vblk.comp;
816  ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
817  sizeof (comp->state));
818  comp->type = buffer[0x18 + r_vstate];
819  comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate);
820  comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
821  comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
822 
823  return true;
824 }
825 
837 static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
838 {
839  int r_objid, r_name, r_diskid, r_id1, r_id2, len;
840  struct vblk_dgrp *dgrp;
841 
842  BUG_ON (!buffer || !vb);
843 
844  r_objid = ldm_relative (buffer, buflen, 0x18, 0);
845  r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
846  r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
847 
848  if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
849  r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
850  r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
851  len = r_id2;
852  } else {
853  r_id1 = 0;
854  r_id2 = 0;
855  len = r_diskid;
856  }
857  if (len < 0)
858  return false;
859 
860  len += VBLK_SIZE_DGR3;
861  if (len != get_unaligned_be32(buffer + 0x14))
862  return false;
863 
864  dgrp = &vb->vblk.dgrp;
865  ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
866  sizeof (dgrp->disk_id));
867  return true;
868 }
869 
881 static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
882 {
883  char buf[64];
884  int r_objid, r_name, r_id1, r_id2, len;
885  struct vblk_dgrp *dgrp;
886 
887  BUG_ON (!buffer || !vb);
888 
889  r_objid = ldm_relative (buffer, buflen, 0x18, 0);
890  r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
891 
892  if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
893  r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
894  r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
895  len = r_id2;
896  } else {
897  r_id1 = 0;
898  r_id2 = 0;
899  len = r_name;
900  }
901  if (len < 0)
902  return false;
903 
904  len += VBLK_SIZE_DGR4;
905  if (len != get_unaligned_be32(buffer + 0x14))
906  return false;
907 
908  dgrp = &vb->vblk.dgrp;
909 
910  ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
911  return true;
912 }
913 
925 static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
926 {
927  int r_objid, r_name, r_diskid, r_altname, len;
928  struct vblk_disk *disk;
929 
930  BUG_ON (!buffer || !vb);
931 
932  r_objid = ldm_relative (buffer, buflen, 0x18, 0);
933  r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
934  r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
935  r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
936  len = r_altname;
937  if (len < 0)
938  return false;
939 
940  len += VBLK_SIZE_DSK3;
941  if (len != get_unaligned_be32(buffer + 0x14))
942  return false;
943 
944  disk = &vb->vblk.disk;
945  ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
946  sizeof (disk->alt_name));
947  if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
948  return false;
949 
950  return true;
951 }
952 
964 static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
965 {
966  int r_objid, r_name, len;
967  struct vblk_disk *disk;
968 
969  BUG_ON (!buffer || !vb);
970 
971  r_objid = ldm_relative (buffer, buflen, 0x18, 0);
972  r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
973  len = r_name;
974  if (len < 0)
975  return false;
976 
977  len += VBLK_SIZE_DSK4;
978  if (len != get_unaligned_be32(buffer + 0x14))
979  return false;
980 
981  disk = &vb->vblk.disk;
982  memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
983  return true;
984 }
985 
997 static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb)
998 {
999  int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
1000  struct vblk_part *part;
1001 
1002  BUG_ON(!buffer || !vb);
1003  r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1004  if (r_objid < 0) {
1005  ldm_error("r_objid %d < 0", r_objid);
1006  return false;
1007  }
1008  r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1009  if (r_name < 0) {
1010  ldm_error("r_name %d < 0", r_name);
1011  return false;
1012  }
1013  r_size = ldm_relative(buffer, buflen, 0x34, r_name);
1014  if (r_size < 0) {
1015  ldm_error("r_size %d < 0", r_size);
1016  return false;
1017  }
1018  r_parent = ldm_relative(buffer, buflen, 0x34, r_size);
1019  if (r_parent < 0) {
1020  ldm_error("r_parent %d < 0", r_parent);
1021  return false;
1022  }
1023  r_diskid = ldm_relative(buffer, buflen, 0x34, r_parent);
1024  if (r_diskid < 0) {
1025  ldm_error("r_diskid %d < 0", r_diskid);
1026  return false;
1027  }
1028  if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
1029  r_index = ldm_relative(buffer, buflen, 0x34, r_diskid);
1030  if (r_index < 0) {
1031  ldm_error("r_index %d < 0", r_index);
1032  return false;
1033  }
1034  len = r_index;
1035  } else {
1036  r_index = 0;
1037  len = r_diskid;
1038  }
1039  if (len < 0) {
1040  ldm_error("len %d < 0", len);
1041  return false;
1042  }
1043  len += VBLK_SIZE_PRT3;
1044  if (len > get_unaligned_be32(buffer + 0x14)) {
1045  ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1046  get_unaligned_be32(buffer + 0x14));
1047  return false;
1048  }
1049  part = &vb->vblk.part;
1050  part->start = get_unaligned_be64(buffer + 0x24 + r_name);
1051  part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name);
1052  part->size = ldm_get_vnum(buffer + 0x34 + r_name);
1053  part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size);
1054  part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent);
1055  if (vb->flags & VBLK_FLAG_PART_INDEX)
1056  part->partnum = buffer[0x35 + r_diskid];
1057  else
1058  part->partnum = 0;
1059  return true;
1060 }
1061 
1073 static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb)
1074 {
1075  int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;
1076  int r_id1, r_id2, r_size2, r_drive, len;
1077  struct vblk_volu *volu;
1078 
1079  BUG_ON(!buffer || !vb);
1080  r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1081  if (r_objid < 0) {
1082  ldm_error("r_objid %d < 0", r_objid);
1083  return false;
1084  }
1085  r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1086  if (r_name < 0) {
1087  ldm_error("r_name %d < 0", r_name);
1088  return false;
1089  }
1090  r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);
1091  if (r_vtype < 0) {
1092  ldm_error("r_vtype %d < 0", r_vtype);
1093  return false;
1094  }
1095  r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);
1096  if (r_disable_drive_letter < 0) {
1097  ldm_error("r_disable_drive_letter %d < 0",
1098  r_disable_drive_letter);
1099  return false;
1100  }
1101  r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);
1102  if (r_child < 0) {
1103  ldm_error("r_child %d < 0", r_child);
1104  return false;
1105  }
1106  r_size = ldm_relative(buffer, buflen, 0x3D, r_child);
1107  if (r_size < 0) {
1108  ldm_error("r_size %d < 0", r_size);
1109  return false;
1110  }
1111  if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {
1112  r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);
1113  if (r_id1 < 0) {
1114  ldm_error("r_id1 %d < 0", r_id1);
1115  return false;
1116  }
1117  } else
1118  r_id1 = r_size;
1119  if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {
1120  r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);
1121  if (r_id2 < 0) {
1122  ldm_error("r_id2 %d < 0", r_id2);
1123  return false;
1124  }
1125  } else
1126  r_id2 = r_id1;
1127  if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {
1128  r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);
1129  if (r_size2 < 0) {
1130  ldm_error("r_size2 %d < 0", r_size2);
1131  return false;
1132  }
1133  } else
1134  r_size2 = r_id2;
1135  if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1136  r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);
1137  if (r_drive < 0) {
1138  ldm_error("r_drive %d < 0", r_drive);
1139  return false;
1140  }
1141  } else
1142  r_drive = r_size2;
1143  len = r_drive;
1144  if (len < 0) {
1145  ldm_error("len %d < 0", len);
1146  return false;
1147  }
1148  len += VBLK_SIZE_VOL5;
1149  if (len > get_unaligned_be32(buffer + 0x14)) {
1150  ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1151  get_unaligned_be32(buffer + 0x14));
1152  return false;
1153  }
1154  volu = &vb->vblk.volu;
1155  ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,
1156  sizeof(volu->volume_type));
1157  memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,
1158  sizeof(volu->volume_state));
1159  volu->size = ldm_get_vnum(buffer + 0x3D + r_child);
1160  volu->partition_type = buffer[0x41 + r_size];
1161  memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));
1162  if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1163  ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,
1164  sizeof(volu->drive_hint));
1165  }
1166  return true;
1167 }
1168 
1182 static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
1183 {
1184  bool result = false;
1185  int r_objid;
1186 
1187  BUG_ON (!buf || !vb);
1188 
1189  r_objid = ldm_relative (buf, len, 0x18, 0);
1190  if (r_objid < 0) {
1191  ldm_error ("VBLK header is corrupt.");
1192  return false;
1193  }
1194 
1195  vb->flags = buf[0x12];
1196  vb->type = buf[0x13];
1197  vb->obj_id = ldm_get_vnum (buf + 0x18);
1198  ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
1199 
1200  switch (vb->type) {
1201  case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break;
1202  case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break;
1203  case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break;
1204  case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break;
1205  case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break;
1206  case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break;
1207  case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break;
1208  }
1209 
1210  if (result)
1211  ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
1212  (unsigned long long) vb->obj_id, vb->type);
1213  else
1214  ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
1215  (unsigned long long) vb->obj_id, vb->type);
1216 
1217  return result;
1218 }
1219 
1220 
1234 static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
1235 {
1236  struct vblk *vb;
1237  struct list_head *item;
1238 
1239  BUG_ON (!data || !ldb);
1240 
1241  vb = kmalloc (sizeof (*vb), GFP_KERNEL);
1242  if (!vb) {
1243  ldm_crit ("Out of memory.");
1244  return false;
1245  }
1246 
1247  if (!ldm_parse_vblk (data, len, vb)) {
1248  kfree(vb);
1249  return false; /* Already logged */
1250  }
1251 
1252  /* Put vblk into the correct list. */
1253  switch (vb->type) {
1254  case VBLK_DGR3:
1255  case VBLK_DGR4:
1256  list_add (&vb->list, &ldb->v_dgrp);
1257  break;
1258  case VBLK_DSK3:
1259  case VBLK_DSK4:
1260  list_add (&vb->list, &ldb->v_disk);
1261  break;
1262  case VBLK_VOL5:
1263  list_add (&vb->list, &ldb->v_volu);
1264  break;
1265  case VBLK_CMP3:
1266  list_add (&vb->list, &ldb->v_comp);
1267  break;
1268  case VBLK_PRT3:
1269  /* Sort by the partition's start sector. */
1270  list_for_each (item, &ldb->v_part) {
1271  struct vblk *v = list_entry (item, struct vblk, list);
1272  if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
1273  (v->vblk.part.start > vb->vblk.part.start)) {
1274  list_add_tail (&vb->list, &v->list);
1275  return true;
1276  }
1277  }
1278  list_add_tail (&vb->list, &ldb->v_part);
1279  break;
1280  }
1281  return true;
1282 }
1283 
1296 static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
1297 {
1298  struct frag *f;
1299  struct list_head *item;
1300  int rec, num, group;
1301 
1302  BUG_ON (!data || !frags);
1303 
1304  if (size < 2 * VBLK_SIZE_HEAD) {
1305  ldm_error("Value of size is to small.");
1306  return false;
1307  }
1308 
1309  group = get_unaligned_be32(data + 0x08);
1310  rec = get_unaligned_be16(data + 0x0C);
1311  num = get_unaligned_be16(data + 0x0E);
1312  if ((num < 1) || (num > 4)) {
1313  ldm_error ("A VBLK claims to have %d parts.", num);
1314  return false;
1315  }
1316  if (rec >= num) {
1317  ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num);
1318  return false;
1319  }
1320 
1321  list_for_each (item, frags) {
1322  f = list_entry (item, struct frag, list);
1323  if (f->group == group)
1324  goto found;
1325  }
1326 
1327  f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
1328  if (!f) {
1329  ldm_crit ("Out of memory.");
1330  return false;
1331  }
1332 
1333  f->group = group;
1334  f->num = num;
1335  f->rec = rec;
1336  f->map = 0xFF << num;
1337 
1338  list_add_tail (&f->list, frags);
1339 found:
1340  if (rec >= f->num) {
1341  ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num);
1342  return false;
1343  }
1344  if (f->map & (1 << rec)) {
1345  ldm_error ("Duplicate VBLK, part %d.", rec);
1346  f->map &= 0x7F; /* Mark the group as broken */
1347  return false;
1348  }
1349  f->map |= (1 << rec);
1350  if (!rec)
1351  memcpy(f->data, data, VBLK_SIZE_HEAD);
1352  data += VBLK_SIZE_HEAD;
1353  size -= VBLK_SIZE_HEAD;
1354  memcpy(f->data + VBLK_SIZE_HEAD + rec * size, data, size);
1355  return true;
1356 }
1357 
1366 static void ldm_frag_free (struct list_head *list)
1367 {
1368  struct list_head *item, *tmp;
1369 
1370  BUG_ON (!list);
1371 
1372  list_for_each_safe (item, tmp, list)
1373  kfree (list_entry (item, struct frag, list));
1374 }
1375 
1387 static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
1388 {
1389  struct frag *f;
1390  struct list_head *item;
1391 
1392  BUG_ON (!frags || !ldb);
1393 
1394  list_for_each (item, frags) {
1395  f = list_entry (item, struct frag, list);
1396 
1397  if (f->map != 0xFF) {
1398  ldm_error ("VBLK group %d is incomplete (0x%02x).",
1399  f->group, f->map);
1400  return false;
1401  }
1402 
1403  if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
1404  return false; /* Already logged */
1405  }
1406  return true;
1407 }
1408 
1421 static bool ldm_get_vblks(struct parsed_partitions *state, unsigned long base,
1422  struct ldmdb *ldb)
1423 {
1424  int size, perbuf, skip, finish, s, v, recs;
1425  u8 *data = NULL;
1426  Sector sect;
1427  bool result = false;
1428  LIST_HEAD (frags);
1429 
1430  BUG_ON(!state || !ldb);
1431 
1432  size = ldb->vm.vblk_size;
1433  perbuf = 512 / size;
1434  skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */
1435  finish = (size * ldb->vm.last_vblk_seq) >> 9;
1436 
1437  for (s = skip; s < finish; s++) { /* For each sector */
1438  data = read_part_sector(state, base + OFF_VMDB + s, &sect);
1439  if (!data) {
1440  ldm_crit ("Disk read failed.");
1441  goto out;
1442  }
1443 
1444  for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */
1445  if (MAGIC_VBLK != get_unaligned_be32(data)) {
1446  ldm_error ("Expected to find a VBLK.");
1447  goto out;
1448  }
1449 
1450  recs = get_unaligned_be16(data + 0x0E); /* Number of records */
1451  if (recs == 1) {
1452  if (!ldm_ldmdb_add (data, size, ldb))
1453  goto out; /* Already logged */
1454  } else if (recs > 1) {
1455  if (!ldm_frag_add (data, size, &frags))
1456  goto out; /* Already logged */
1457  }
1458  /* else Record is not in use, ignore it. */
1459  }
1460  put_dev_sector (sect);
1461  data = NULL;
1462  }
1463 
1464  result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */
1465 out:
1466  if (data)
1467  put_dev_sector (sect);
1468  ldm_frag_free (&frags);
1469 
1470  return result;
1471 }
1472 
1481 static void ldm_free_vblks (struct list_head *lh)
1482 {
1483  struct list_head *item, *tmp;
1484 
1485  BUG_ON (!lh);
1486 
1487  list_for_each_safe (item, tmp, lh)
1488  kfree (list_entry (item, struct vblk, list));
1489 }
1490 
1491 
1510 {
1511  struct ldmdb *ldb;
1512  unsigned long base;
1513  int result = -1;
1514 
1515  BUG_ON(!state);
1516 
1517  /* Look for signs of a Dynamic Disk */
1518  if (!ldm_validate_partition_table(state))
1519  return 0;
1520 
1521  ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
1522  if (!ldb) {
1523  ldm_crit ("Out of memory.");
1524  goto out;
1525  }
1526 
1527  /* Parse and check privheads. */
1528  if (!ldm_validate_privheads(state, &ldb->ph))
1529  goto out; /* Already logged */
1530 
1531  /* All further references are relative to base (database start). */
1532  base = ldb->ph.config_start;
1533 
1534  /* Parse and check tocs and vmdb. */
1535  if (!ldm_validate_tocblocks(state, base, ldb) ||
1536  !ldm_validate_vmdb(state, base, ldb))
1537  goto out; /* Already logged */
1538 
1539  /* Initialize vblk lists in ldmdb struct */
1540  INIT_LIST_HEAD (&ldb->v_dgrp);
1541  INIT_LIST_HEAD (&ldb->v_disk);
1542  INIT_LIST_HEAD (&ldb->v_volu);
1543  INIT_LIST_HEAD (&ldb->v_comp);
1544  INIT_LIST_HEAD (&ldb->v_part);
1545 
1546  if (!ldm_get_vblks(state, base, ldb)) {
1547  ldm_crit ("Failed to read the VBLKs from the database.");
1548  goto cleanup;
1549  }
1550 
1551  /* Finally, create the data partition devices. */
1552  if (ldm_create_data_partitions(state, ldb)) {
1553  ldm_debug ("Parsed LDM database successfully.");
1554  result = 1;
1555  }
1556  /* else Already logged */
1557 
1558 cleanup:
1559  ldm_free_vblks (&ldb->v_dgrp);
1560  ldm_free_vblks (&ldb->v_disk);
1561  ldm_free_vblks (&ldb->v_volu);
1562  ldm_free_vblks (&ldb->v_comp);
1563  ldm_free_vblks (&ldb->v_part);
1564 out:
1565  kfree (ldb);
1566  return result;
1567 }