On 06/03/2010 08:41 PM, sean finney wrote:
> and here is a slightly updated patch.  there is no functional change in the
> code, i have only reformatted the whitespace etc so that the code matches
> with the style of the surrounding code.
>
> i have also tested this now on my primary testing system and haven't
> noticed any problems.
>
>   
I've cleaned up your patch using my more generic string parsing
functions. Could you test attached patch?
>       sean
>
> On Thu, Jun 03, 2010 at 12:41:32AM +0200, sean finney wrote:
>   
>> okay, I think the attached patch should fix the problem.
>>
>> I haven't tested it thoroughly, though my system does boot.  It seems
>> there may be a seperate issue with os-prober that results in some junk
>> entries being added to grub.conf if the snapshot volumes happen to be
>> root filesystems, but that probably needs to be taken up seperately and
>> the critical aspect of the bug is fixed anyway.
>>
>>
>>      sean
>>     
>   
>> Author: Sean Finney <sean...@debian.org>
>> Description: Fix for lvm2 parsing failures with snapshot logical volumes
>>
>> 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
>> --- disk/lvm.c       2010-04-27 15:25:12 +0000
>> +++ disk/lvm.c       2010-06-02 22:12:58 +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,18 @@
>>                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 +566,19 @@
>>                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;
>>
>>     
>
>
>
>   
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>   


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

=== modified file 'disk/lvm.c'
--- disk/lvm.c	2010-04-27 15:25:12 +0000
+++ disk/lvm.c	2010-06-29 05:27:15 +0000
@@ -46,6 +46,52 @@ grub_lvm_getvalue (char **p, char *str)
 }
 
 static int
+grub_lvm_checkvalue (char **p, char *str, char *tmpl)
+{
+  int tmpllen = grub_strlen (tmpl);
+  *p = grub_strstr (*p, str);
+  if (! *p)
+    return 0;
+  *p += grub_strlen (str);
+  if (**p != '"')
+    return 0;
+  return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"');
+}
+
+static int
+grub_lvm_check_flag (char *p, char *str, char *flag)
+{
+  int len_str = grub_strlen (str), len_flag = grub_strlen (flag);
+  while (1)
+    {
+      char *q;
+      p = grub_strstr (p, str);
+      if (! p)
+	return 0;
+      p += len_str;
+      if (grub_memcmp (p, " = [", sizeof (" = [") - 1) != 0)
+	continue;
+      q = p + sizeof (" = [") - 1;
+      while (1)
+	{
+	  while (grub_isspace (*q))
+	    q++;
+	  if (*q != '"')
+	    return 0;
+	  q++;
+	  if (grub_memcmp (q, flag, len_flag) == 0 && q[len_flag] == '"')
+	    return 1;
+	  while (*q != '"')
+	    q++;
+	  q++;
+	  if (*q == ']')
+	    return 0;
+	  q++;
+	}
+    }
+}
+
+static int
 grub_lvm_iterate (int (*hook) (const char *name))
 {
   struct grub_lvm_vg *vg;
@@ -421,6 +467,7 @@ grub_lvm_scan_device (const char *name)
 	  while (1)
 	    {
 	      int s;
+	      int skip_lv = 0;
 	      struct grub_lvm_lv *lv;
 	      struct grub_lvm_segment *seg;
 
@@ -445,6 +492,12 @@ grub_lvm_scan_device (const char *name)
 
 	      lv->size = 0;
 
+	      if (!grub_lvm_check_flag (p, "status", "VISIBLE"))
+		{
+		  skip_lv = 1;
+		  goto lv_parsed;
+		}
+
 	      lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
 	      if (p == NULL)
 		goto lvs_fail;
@@ -465,6 +518,14 @@ grub_lvm_scan_device (const char *name)
 		  seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
 		  if (p == NULL)
 		    goto lvs_segment_fail;
+
+		  if (grub_lvm_checkvalue (&p, "type = ", "snapshot"))
+		    {
+		      /* 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 +592,20 @@ grub_lvm_scan_device (const char *name)
 		  goto fail4;
 		}
 
+	    lv_parsed:
 	      if (p != NULL)
 		p = grub_strchr (p, '}');
 	      if (p == NULL)
 		goto lvs_fail;
 	      p += 3;
 
+	      if (skip_lv)
+		{
+		  grub_free (lv->name);
+		  grub_free (lv);
+		  continue;
+		}
+
 	      lv->number = lv_count++;
 	      lv->vg = vg;
 	      lv->next = vg->lvs;

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to