]> git.proxmox.com Git - grub2.git/blob - grub-core/disk/lvm.c
* grub-core/disk/lvm.c: Use grub_size_t for sizes and grub_ssize_t
[grub2.git] / grub-core / disk / lvm.c
1 /* lvm.c - module to read Logical Volumes. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2006,2007,2008,2009,2011 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/dl.h>
21 #include <grub/disk.h>
22 #include <grub/mm.h>
23 #include <grub/err.h>
24 #include <grub/misc.h>
25 #include <grub/lvm.h>
26 #include <grub/partition.h>
27 #include <grub/i18n.h>
28
29 #ifdef GRUB_UTIL
30 #include <grub/emu/misc.h>
31 #include <grub/emu/hostdisk.h>
32 #endif
33
34 GRUB_MOD_LICENSE ("GPLv3+");
35
36 \f
37 /* Go the string STR and return the number after STR. *P will point
38 at the number. In case STR is not found, *P will be NULL and the
39 return value will be 0. */
40 static grub_uint64_t
41 grub_lvm_getvalue (char **p, const char *str)
42 {
43 *p = grub_strstr (*p, str);
44 if (! *p)
45 return 0;
46 *p += grub_strlen (str);
47 return grub_strtoull (*p, p, 10);
48 }
49
50 #if 0
51 static int
52 grub_lvm_checkvalue (char **p, char *str, char *tmpl)
53 {
54 int tmpllen = grub_strlen (tmpl);
55 *p = grub_strstr (*p, str);
56 if (! *p)
57 return 0;
58 *p += grub_strlen (str);
59 if (**p != '"')
60 return 0;
61 return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"');
62 }
63 #endif
64
65 static int
66 grub_lvm_check_flag (char *p, const char *str, const char *flag)
67 {
68 grub_size_t len_str = grub_strlen (str), len_flag = grub_strlen (flag);
69 while (1)
70 {
71 char *q;
72 p = grub_strstr (p, str);
73 if (! p)
74 return 0;
75 p += len_str;
76 if (grub_memcmp (p, " = [", sizeof (" = [") - 1) != 0)
77 continue;
78 q = p + sizeof (" = [") - 1;
79 while (1)
80 {
81 while (grub_isspace (*q))
82 q++;
83 if (*q != '"')
84 return 0;
85 q++;
86 if (grub_memcmp (q, flag, len_flag) == 0 && q[len_flag] == '"')
87 return 1;
88 while (*q != '"')
89 q++;
90 q++;
91 if (*q == ']')
92 return 0;
93 q++;
94 }
95 }
96 }
97
98 static struct grub_diskfilter_vg *
99 grub_lvm_detect (grub_disk_t disk,
100 struct grub_diskfilter_pv_id *id,
101 grub_disk_addr_t *start_sector)
102 {
103 grub_err_t err;
104 grub_uint64_t mda_offset, mda_size;
105 char buf[GRUB_LVM_LABEL_SIZE];
106 char vg_id[GRUB_LVM_ID_STRLEN+1];
107 char pv_id[GRUB_LVM_ID_STRLEN+1];
108 char *metadatabuf, *p, *q, *vgname;
109 struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
110 struct grub_lvm_pv_header *pvh;
111 struct grub_lvm_disk_locn *dlocn;
112 struct grub_lvm_mda_header *mdah;
113 struct grub_lvm_raw_locn *rlocn;
114 unsigned int i, j;
115 grub_size_t vgname_len;
116 struct grub_diskfilter_vg *vg;
117 struct grub_diskfilter_pv *pv;
118
119 /* Search for label. */
120 for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
121 {
122 err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
123 if (err)
124 goto fail;
125
126 if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
127 sizeof (lh->id)))
128 && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
129 sizeof (lh->type))))
130 break;
131 }
132
133 /* Return if we didn't find a label. */
134 if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
135 {
136 #ifdef GRUB_UTIL
137 grub_util_info ("no LVM signature found");
138 #endif
139 goto fail;
140 }
141
142 pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
143
144 for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
145 {
146 pv_id[j++] = pvh->pv_uuid[i];
147 if ((i != 1) && (i != 29) && (i % 4 == 1))
148 pv_id[j++] = '-';
149 }
150 pv_id[j] = '\0';
151
152 dlocn = pvh->disk_areas_xl;
153
154 dlocn++;
155 /* Is it possible to have multiple data/metadata areas? I haven't
156 seen devices that have it. */
157 if (dlocn->offset)
158 {
159 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
160 "we don't support multiple LVM data areas");
161
162 #ifdef GRUB_UTIL
163 grub_util_info ("we don't support multiple LVM data areas\n");
164 #endif
165 goto fail;
166 }
167
168 dlocn++;
169 mda_offset = grub_le_to_cpu64 (dlocn->offset);
170 mda_size = grub_le_to_cpu64 (dlocn->size);
171
172 /* It's possible to have multiple copies of metadata areas, we just use the
173 first one. */
174
175 /* Allocate buffer space for the circular worst-case scenario. */
176 metadatabuf = grub_malloc (2 * mda_size);
177 if (! metadatabuf)
178 goto fail;
179
180 err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
181 if (err)
182 goto fail2;
183
184 mdah = (struct grub_lvm_mda_header *) metadatabuf;
185 if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
186 sizeof (mdah->magic)))
187 || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
188 {
189 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
190 "unknown LVM metadata header");
191 #ifdef GRUB_UTIL
192 grub_util_info ("unknown LVM metadata header\n");
193 #endif
194 goto fail2;
195 }
196
197 rlocn = mdah->raw_locns;
198 if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
199 grub_le_to_cpu64 (mdah->size))
200 {
201 /* Metadata is circular. Copy the wrap in place. */
202 grub_memcpy (metadatabuf + mda_size,
203 metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
204 grub_le_to_cpu64 (rlocn->offset) +
205 grub_le_to_cpu64 (rlocn->size) -
206 grub_le_to_cpu64 (mdah->size));
207 }
208 p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
209
210 while (*q != ' ' && q < metadatabuf + mda_size)
211 q++;
212
213 if (q == metadatabuf + mda_size)
214 {
215 #ifdef GRUB_UTIL
216 grub_util_info ("error parsing metadata\n");
217 #endif
218 goto fail2;
219 }
220
221 vgname_len = q - p;
222 vgname = grub_malloc (vgname_len + 1);
223 if (!vgname)
224 goto fail2;
225
226 grub_memcpy (vgname, p, vgname_len);
227 vgname[vgname_len] = '\0';
228
229 p = grub_strstr (q, "id = \"");
230 if (p == NULL)
231 {
232 #ifdef GRUB_UTIL
233 grub_util_info ("couldn't find ID\n");
234 #endif
235 goto fail3;
236 }
237 p += sizeof ("id = \"") - 1;
238 grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
239 vg_id[GRUB_LVM_ID_STRLEN] = '\0';
240
241 vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
242
243 if (! vg)
244 {
245 /* First time we see this volume group. We've to create the
246 whole volume group structure. */
247 vg = grub_malloc (sizeof (*vg));
248 if (! vg)
249 goto fail3;
250 vg->name = vgname;
251 vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
252 if (! vg->uuid)
253 goto fail3;
254 grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN);
255 vg->uuid_len = GRUB_LVM_ID_STRLEN;
256
257 vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
258 if (p == NULL)
259 {
260 #ifdef GRUB_UTIL
261 grub_util_info ("unknown extent size\n");
262 #endif
263 goto fail4;
264 }
265
266 vg->lvs = NULL;
267 vg->pvs = NULL;
268
269 p = grub_strstr (p, "physical_volumes {");
270 if (p)
271 {
272 p += sizeof ("physical_volumes {") - 1;
273
274 /* Add all the pvs to the volume group. */
275 while (1)
276 {
277 grub_ssize_t s;
278 while (grub_isspace (*p))
279 p++;
280
281 if (*p == '}')
282 break;
283
284 pv = grub_zalloc (sizeof (*pv));
285 q = p;
286 while (*q != ' ')
287 q++;
288
289 s = q - p;
290 pv->name = grub_malloc (s + 1);
291 grub_memcpy (pv->name, p, s);
292 pv->name[s] = '\0';
293
294 p = grub_strstr (p, "id = \"");
295 if (p == NULL)
296 goto pvs_fail;
297 p += sizeof("id = \"") - 1;
298
299 pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
300 if (!pv->id.uuid)
301 goto pvs_fail;
302 grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN);
303 pv->id.uuidlen = GRUB_LVM_ID_STRLEN;
304
305 pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
306 if (p == NULL)
307 {
308 #ifdef GRUB_UTIL
309 grub_util_info ("unknown pe_start\n");
310 #endif
311 goto pvs_fail;
312 }
313
314 p = grub_strchr (p, '}');
315 if (p == NULL)
316 {
317 #ifdef GRUB_UTIL
318 grub_util_info ("error parsing pe_start\n");
319 #endif
320 goto pvs_fail;
321 }
322 p++;
323
324 pv->disk = NULL;
325 pv->next = vg->pvs;
326 vg->pvs = pv;
327
328 continue;
329 pvs_fail:
330 grub_free (pv->name);
331 grub_free (pv);
332 goto fail4;
333 }
334 }
335
336 p = grub_strstr (p, "logical_volumes");
337 if (p)
338 {
339 p += sizeof ("logical_volumes = ") - 1;
340
341 /* And add all the lvs to the volume group. */
342 while (1)
343 {
344 grub_ssize_t s;
345 int skip_lv = 0;
346 struct grub_diskfilter_lv *lv;
347 struct grub_diskfilter_segment *seg;
348 int is_pvmove;
349
350 while (grub_isspace (*p))
351 p++;
352
353 if (*p == '}')
354 break;
355
356 lv = grub_zalloc (sizeof (*lv));
357
358 q = p;
359 while (*q != ' ')
360 q++;
361
362 s = q - p;
363 lv->name = grub_strndup (p, s);
364 if (!lv->name)
365 goto lvs_fail;
366
367 {
368 const char *iptr;
369 char *optr;
370 lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len
371 + 1 + 2 * s + 1);
372 if (!lv->fullname)
373 goto lvs_fail;
374
375 grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1);
376 optr = lv->fullname + sizeof ("lvm/") - 1;
377 for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
378 {
379 *optr++ = *iptr;
380 if (*iptr == '-')
381 *optr++ = '-';
382 }
383 *optr++ = '-';
384 for (iptr = p; iptr < p + s; iptr++)
385 {
386 *optr++ = *iptr;
387 if (*iptr == '-')
388 *optr++ = '-';
389 }
390 *optr++ = 0;
391 lv->idname = grub_malloc (sizeof ("lvmid/")
392 + 2 * GRUB_LVM_ID_STRLEN + 1);
393 if (!lv->idname)
394 goto lvs_fail;
395 grub_memcpy (lv->idname, "lvmid/",
396 sizeof ("lvmid/") - 1);
397 grub_memcpy (lv->idname + sizeof ("lvmid/") - 1,
398 vg_id, GRUB_LVM_ID_STRLEN);
399 lv->idname[sizeof ("lvmid/") - 1 + GRUB_LVM_ID_STRLEN] = '/';
400
401 p = grub_strstr (q, "id = \"");
402 if (p == NULL)
403 {
404 #ifdef GRUB_UTIL
405 grub_util_info ("couldn't find ID\n");
406 #endif
407 goto lvs_fail;
408 }
409 p += sizeof ("id = \"") - 1;
410 grub_memcpy (lv->idname + sizeof ("lvmid/") - 1
411 + GRUB_LVM_ID_STRLEN + 1,
412 p, GRUB_LVM_ID_STRLEN);
413 lv->idname[sizeof ("lvmid/") - 1 + 2 * GRUB_LVM_ID_STRLEN + 1] = '\0';
414 }
415
416 lv->size = 0;
417
418 lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
419 is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
420
421 lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
422 if (p == NULL)
423 {
424 #ifdef GRUB_UTIL
425 grub_util_info ("unknown segment_count\n");
426 #endif
427 goto lvs_fail;
428 }
429 lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
430 seg = lv->segments;
431
432 for (i = 0; i < lv->segment_count; i++)
433 {
434
435 p = grub_strstr (p, "segment");
436 if (p == NULL)
437 {
438 #ifdef GRUB_UTIL
439 grub_util_info ("unknown segment\n");
440 #endif
441 goto lvs_segment_fail;
442 }
443
444 seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
445 if (p == NULL)
446 {
447 #ifdef GRUB_UTIL
448 grub_util_info ("unknown start_extent\n");
449 #endif
450 goto lvs_segment_fail;
451 }
452 seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
453 if (p == NULL)
454 {
455 #ifdef GRUB_UTIL
456 grub_util_info ("unknown extent_count\n");
457 #endif
458 goto lvs_segment_fail;
459 }
460
461 p = grub_strstr (p, "type = \"");
462 if (p == NULL)
463 goto lvs_segment_fail;
464 p += sizeof("type = \"") - 1;
465
466 lv->size += seg->extent_count * vg->extent_size;
467
468 if (grub_memcmp (p, "striped\"",
469 sizeof ("striped\"") - 1) == 0)
470 {
471 struct grub_diskfilter_node *stripe;
472
473 seg->type = GRUB_DISKFILTER_STRIPED;
474 seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
475 if (p == NULL)
476 {
477 #ifdef GRUB_UTIL
478 grub_util_info ("unknown stripe_count\n");
479 #endif
480 goto lvs_segment_fail;
481 }
482
483 if (seg->node_count != 1)
484 seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
485
486 seg->nodes = grub_zalloc (sizeof (*stripe)
487 * seg->node_count);
488 stripe = seg->nodes;
489
490 p = grub_strstr (p, "stripes = [");
491 if (p == NULL)
492 {
493 #ifdef GRUB_UTIL
494 grub_util_info ("unknown stripes\n");
495 #endif
496 goto lvs_segment_fail2;
497 }
498 p += sizeof("stripes = [") - 1;
499
500 for (j = 0; j < seg->node_count; j++)
501 {
502 p = grub_strchr (p, '"');
503 if (p == NULL)
504 continue;
505 q = ++p;
506 while (*q != '"')
507 q++;
508
509 s = q - p;
510
511 stripe->name = grub_malloc (s + 1);
512 if (stripe->name == NULL)
513 goto lvs_segment_fail2;
514
515 grub_memcpy (stripe->name, p, s);
516 stripe->name[s] = '\0';
517
518 p = q + 1;
519
520 stripe->start = grub_lvm_getvalue (&p, ",")
521 * vg->extent_size;
522 if (p == NULL)
523 continue;
524
525 stripe++;
526 }
527 }
528 else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
529 == 0)
530 {
531 seg->type = GRUB_DISKFILTER_MIRROR;
532 seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
533 if (p == NULL)
534 {
535 #ifdef GRUB_UTIL
536 grub_util_info ("unknown mirror_count\n");
537 #endif
538 goto lvs_segment_fail;
539 }
540
541 seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
542 * seg->node_count);
543
544 p = grub_strstr (p, "mirrors = [");
545 if (p == NULL)
546 {
547 #ifdef GRUB_UTIL
548 grub_util_info ("unknown mirrors\n");
549 #endif
550 goto lvs_segment_fail2;
551 }
552 p += sizeof("mirrors = [") - 1;
553
554 for (j = 0; j < seg->node_count; j++)
555 {
556 char *lvname;
557
558 p = grub_strchr (p, '"');
559 if (p == NULL)
560 continue;
561 q = ++p;
562 while (*q != '"')
563 q++;
564
565 s = q - p;
566
567 lvname = grub_malloc (s + 1);
568 if (lvname == NULL)
569 goto lvs_segment_fail2;
570
571 grub_memcpy (lvname, p, s);
572 lvname[s] = '\0';
573 seg->nodes[j].name = lvname;
574 p = q + 1;
575 }
576 /* Only first (original) is ok with in progress pvmove. */
577 if (is_pvmove)
578 seg->node_count = 1;
579 }
580 else if (grub_memcmp (p, "raid", sizeof ("raid") - 1)
581 == 0 && (p[sizeof ("raid") - 1] >= '4'
582 && p[sizeof ("raid") - 1] <= '6')
583 && p[sizeof ("raidX") - 1] == '"')
584 {
585 switch (p[sizeof ("raid") - 1])
586 {
587 case '4':
588 seg->type = GRUB_DISKFILTER_RAID4;
589 seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
590 break;
591 case '5':
592 seg->type = GRUB_DISKFILTER_RAID5;
593 seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC;
594 break;
595 case '6':
596 seg->type = GRUB_DISKFILTER_RAID6;
597 seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC
598 | GRUB_RAID_LAYOUT_MUL_FROM_POS);
599 break;
600 }
601 seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
602
603 if (p == NULL)
604 {
605 #ifdef GRUB_UTIL
606 grub_util_info ("unknown device_count\n");
607 #endif
608 goto lvs_segment_fail;
609 }
610
611 seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
612 if (p == NULL)
613 {
614 #ifdef GRUB_UTIL
615 grub_util_info ("unknown stripe_size\n");
616 #endif
617 goto lvs_segment_fail;
618 }
619
620
621 seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
622 * seg->node_count);
623
624 p = grub_strstr (p, "raids = [");
625 if (p == NULL)
626 {
627 #ifdef GRUB_UTIL
628 grub_util_info ("unknown mirrors\n");
629 #endif
630 goto lvs_segment_fail2;
631 }
632 p += sizeof("raids = [") - 1;
633
634 for (j = 0; j < seg->node_count; j++)
635 {
636 char *lvname;
637
638 p = grub_strchr (p, '"');
639 p = p ? grub_strchr (p + 1, '"') : 0;
640 p = p ? grub_strchr (p + 1, '"') : 0;
641 if (p == NULL)
642 continue;
643 q = ++p;
644 while (*q != '"')
645 q++;
646
647 s = q - p;
648
649 lvname = grub_malloc (s + 1);
650 if (lvname == NULL)
651 goto lvs_segment_fail2;
652
653 grub_memcpy (lvname, p, s);
654 lvname[s] = '\0';
655 seg->nodes[j].name = lvname;
656 p = q + 1;
657 }
658 if (seg->type == GRUB_DISKFILTER_RAID4)
659 {
660 char *tmp;
661 tmp = seg->nodes[0].name;
662 grub_memmove (seg->nodes, seg->nodes + 1,
663 sizeof (seg->nodes[0])
664 * (seg->node_count - 1));
665 seg->nodes[seg->node_count - 1].name = tmp;
666 }
667 }
668 else
669 {
670 #ifdef GRUB_UTIL
671 char *p2;
672 p2 = grub_strchr (p, '"');
673 if (p2)
674 *p2 = 0;
675 grub_util_info ("unknown LVM type %s\n", p);
676 if (p2)
677 *p2 ='"';
678 #endif
679 /* Found a non-supported type, give up and move on. */
680 skip_lv = 1;
681 break;
682 }
683
684 seg++;
685
686 continue;
687 lvs_segment_fail2:
688 grub_free (seg->nodes);
689 lvs_segment_fail:
690 goto fail4;
691 }
692
693 if (p != NULL)
694 p = grub_strchr (p, '}');
695 if (p == NULL)
696 goto lvs_fail;
697 p += 3;
698
699 if (skip_lv)
700 {
701 grub_free (lv->name);
702 grub_free (lv);
703 continue;
704 }
705
706 lv->vg = vg;
707 lv->next = vg->lvs;
708 vg->lvs = lv;
709
710 continue;
711 lvs_fail:
712 grub_free (lv->name);
713 grub_free (lv);
714 goto fail4;
715 }
716 }
717
718 /* Match lvs. */
719 {
720 struct grub_diskfilter_lv *lv1;
721 struct grub_diskfilter_lv *lv2;
722 for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
723 for (i = 0; i < lv1->segment_count; i++)
724 for (j = 0; j < lv1->segments[i].node_count; j++)
725 {
726 if (vg->pvs)
727 for (pv = vg->pvs; pv; pv = pv->next)
728 {
729 if (! grub_strcmp (pv->name,
730 lv1->segments[i].nodes[j].name))
731 {
732 lv1->segments[i].nodes[j].pv = pv;
733 break;
734 }
735 }
736 if (lv1->segments[i].nodes[j].pv == NULL)
737 for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
738 if (grub_strcmp (lv2->name,
739 lv1->segments[i].nodes[j].name) == 0)
740 lv1->segments[i].nodes[j].lv = lv2;
741 }
742
743 }
744 if (grub_diskfilter_vg_register (vg))
745 goto fail4;
746 }
747 else
748 {
749 grub_free (vgname);
750 }
751
752 id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
753 if (!id->uuid)
754 goto fail4;
755 grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN);
756 id->uuidlen = GRUB_LVM_ID_STRLEN;
757 grub_free (metadatabuf);
758 *start_sector = -1;
759 return vg;
760
761 /* Failure path. */
762 fail4:
763 grub_free (vg);
764 fail3:
765 grub_free (vgname);
766
767 fail2:
768 grub_free (metadatabuf);
769 fail:
770 return NULL;
771 }
772
773 \f
774
775 static struct grub_diskfilter grub_lvm_dev = {
776 .name = "lvm",
777 .detect = grub_lvm_detect,
778 .next = 0
779 };
780
781 GRUB_MOD_INIT (lvm)
782 {
783 grub_diskfilter_register_back (&grub_lvm_dev);
784 }
785
786 GRUB_MOD_FINI (lvm)
787 {
788 grub_diskfilter_unregister (&grub_lvm_dev);
789 }