Author: Sean Finney Description: Fix for lvm2 parsing failures with snapshot logical volumes Forwarded: yes This patch prevents the lvm2 parsing code from prematurely aborting when encountering LV and segment metadata related to snapshot volumes. Instead, the parser will now skip over these as if it never saw them, which is probably the safest thing to do without a major injection of lvm2 support code. Bug-Debian: #574863 --- a/disk/lvm.c 2010-04-27 15:25:12 +0000 +++ b/disk/lvm.c 2010-06-03 16:06:33 +0000 @@ -420,9 +420,11 @@ /* And add all the lvs to the volume group. */ while (1) { - int s; + int s, skip_lv = 0, status_visible = 0; struct grub_lvm_lv *lv; struct grub_lvm_segment *seg; + char *status = NULL, *status_end = NULL; + grub_size_t status_len = 0; while (grub_isspace (*p)) p++; @@ -431,6 +433,8 @@ break; lv = grub_malloc (sizeof (*lv)); + skip_lv = 0; /*Flag to skip snapshots */ + status_visible = 0; /*Flag to skip non-visible LV's */ q = p; while (*q != ' ') @@ -445,6 +449,25 @@ lv->size = 0; + /* read LV status and ignore ones not listed as "VISIBLE" */ + p = grub_strstr (p, "status = "); + if (p == NULL) + goto lvs_fail; + status_end = grub_strchr (p, ']'); + if (status_end == NULL) + goto lvs_fail; + status_len = (status_end - p) + 1; + status = grub_malloc (status_len + 1); + if (status == NULL) + goto lvs_fail; + grub_memcpy (status, p, status_len); + status[status_len] = '\0'; + if (grub_strstr (status, "VISIBLE") != NULL) + status_visible = 1; + grub_free (status); + if (!status_visible) + goto lv_parsed; /* don't bother parsing this one */ + lv->segment_count = grub_lvm_getvalue (&p, "segment_count = "); if (p == NULL) goto lvs_fail; @@ -465,6 +488,19 @@ seg->extent_count = grub_lvm_getvalue (&p, "extent_count = "); if (p == NULL) goto lvs_segment_fail; + + /* Skip LV's that have snapshot segments */ + p = grub_strstr (p, "type = "); + if (p == NULL) + goto lvs_segment_fail; + p += sizeof ("type = ") - 1; + if (!grub_strncmp (p, "\"snapshot\"", 10)) + { + /* Found a snapshot, give up and move on */ + skip_lv=1; + break; + } + seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = "); if (p == NULL) goto lvs_segment_fail; @@ -531,12 +567,20 @@ goto fail4; } + lv_parsed: /* all done with parsing this LV, seek to the end */ if (p != NULL) p = grub_strchr (p, '}'); if (p == NULL) goto lvs_fail; p += 3; + if (skip_lv || ! status_visible) + { + grub_free (lv->name); + grub_free (lv); + continue; + } + lv->number = lv_count++; lv->vg = vg; lv->next = vg->lvs;