On 29.09.2010 00:50, Tim Bray wrote:
> # lvs -a -o +devices
>
>   LV              VG     Attr   LSize   Origin Snap%  Move Log       Copy%  
> Convert Devices                         
>   home            timdeb mwi-ao 100.00g                    home_mlog 100.00   
>       home_mimage_0(0),home_mimage_1(0)
>   [home_mimage_0] timdeb iwi-ao 100.00g                                       
>       /dev/sdb1(0)                    
>   [home_mimage_1] timdeb iwi-ao 100.00g                                       
>       /dev/sdc1(0)                    
>   [home_mlog]     timdeb lwi-ao   4.00m                                       
>       /dev/sda1(4608)                 
>   root            timdeb -wi-ao  18.00g                                       
>       /dev/sda1(0)  
>
>
>   
Please try the attached patch


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

=== modified file 'grub-core/disk/lvm.c'
--- grub-core/disk/lvm.c	2010-11-14 13:13:11 +0000
+++ grub-core/disk/lvm.c	2011-03-28 03:15:58 +0000
@@ -45,6 +45,7 @@
   return grub_strtoul (*p, NULL, 10);
 }
 
+#if 0
 static int
 grub_lvm_checkvalue (char **p, char *str, char *tmpl)
 {
@@ -57,6 +58,7 @@
     return 0;
   return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"');
 }
+#endif
 
 static int
 grub_lvm_check_flag (char *p, char *str, char *flag)
@@ -100,7 +102,7 @@
       struct grub_lvm_lv *lv;
       if (vg->lvs)
 	for (lv = vg->lvs; lv; lv = lv->next)
-	  if (hook (lv->name))
+	  if (lv->visible && hook (lv->name))
 	    return 1;
     }
 
@@ -164,11 +166,10 @@
 }
 
 static grub_err_t
-grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
-		grub_size_t size, char *buf)
+read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
+	 grub_size_t size, char *buf)
 {
   grub_err_t err = 0;
-  struct grub_lvm_lv *lv = disk->data;
   struct grub_lvm_vg *vg = lv->vg;
   struct grub_lvm_segment *seg = lv->segments;
   struct grub_lvm_pv *pv;
@@ -176,6 +177,9 @@
   grub_uint64_t extent;
   unsigned int i;
 
+  if (!lv)
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
+
   extent = grub_divmod64 (sector, vg->extent_size, NULL);
 
   /* Find the right segment.  */
@@ -190,59 +194,88 @@
       seg++;
     }
 
-  if (seg->stripe_count == 1)
-    {
-      /* This segment is linear, so that's easy.  We just need to find
-	 out the offset in the physical volume and read SIZE bytes
-	 from that.  */
-      struct grub_lvm_stripe *stripe = seg->stripes;
-      grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */
-
-      pv = stripe->pv;
-      seg_offset = ((grub_uint64_t) stripe->start
-		    * (grub_uint64_t) vg->extent_size) + pv->start;
-
-      offset = sector - ((grub_uint64_t) seg->start_extent
-			 * (grub_uint64_t) vg->extent_size) + seg_offset;
-    }
-  else
-    {
-      /* This is a striped segment. We have to find the right PV
-	 similar to RAID0. */
-      struct grub_lvm_stripe *stripe = seg->stripes;
-      grub_uint32_t a, b;
-      grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */
-      unsigned int stripenr;
-
-      offset = sector - ((grub_uint64_t) seg->start_extent
-			 * (grub_uint64_t) vg->extent_size);
-
-      a = grub_divmod64 (offset, seg->stripe_size, NULL);
-      grub_divmod64 (a, seg->stripe_count, &stripenr);
-
-      a = grub_divmod64 (offset, seg->stripe_size * seg->stripe_count, NULL);
-      grub_divmod64 (offset, seg->stripe_size, &b);
-      offset = a * seg->stripe_size + b;
-
-      stripe += stripenr;
-      pv = stripe->pv;
-
-      seg_offset = ((grub_uint64_t) stripe->start
-		    * (grub_uint64_t) vg->extent_size) + pv->start;
-
-      offset += seg_offset;
-    }
-
-  /* Check whether we actually know the physical volume we want to
-     read from.  */
-  if (pv->disk)
-    err = grub_disk_read (pv->disk, offset, 0,
-			  size << GRUB_DISK_SECTOR_BITS, buf);
-  else
-    err = grub_error (GRUB_ERR_UNKNOWN_DEVICE,
-		      "physical volume %s not found", pv->name);
-
-  return err;
+  if (i == lv->segment_count)
+    return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
+
+  switch (seg->type)
+    {
+    case GRUB_LVM_STRIPED:
+      if (seg->stripe_count == 1)
+	{
+	  /* This segment is linear, so that's easy.  We just need to find
+	     out the offset in the physical volume and read SIZE bytes
+	     from that.  */
+	  struct grub_lvm_stripe *stripe = seg->stripes;
+	  grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */
+
+	  pv = stripe->pv;
+	  seg_offset = ((grub_uint64_t) stripe->start
+			* (grub_uint64_t) vg->extent_size) + pv->start;
+
+	  offset = sector - ((grub_uint64_t) seg->start_extent
+			     * (grub_uint64_t) vg->extent_size) + seg_offset;
+	}
+      else
+	{
+	  /* This is a striped segment. We have to find the right PV
+	     similar to RAID0. */
+	  struct grub_lvm_stripe *stripe = seg->stripes;
+	  grub_uint32_t a, b;
+	  grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */
+	  unsigned int stripenr;
+
+	  offset = sector - ((grub_uint64_t) seg->start_extent
+			     * (grub_uint64_t) vg->extent_size);
+
+	  a = grub_divmod64 (offset, seg->stripe_size, NULL);
+	  grub_divmod64 (a, seg->stripe_count, &stripenr);
+
+	  a = grub_divmod64 (offset, seg->stripe_size * seg->stripe_count, NULL);
+	  grub_divmod64 (offset, seg->stripe_size, &b);
+	  offset = a * seg->stripe_size + b;
+
+	  stripe += stripenr;
+	  pv = stripe->pv;
+
+	  seg_offset = ((grub_uint64_t) stripe->start
+			* (grub_uint64_t) vg->extent_size) + pv->start;
+
+	  offset += seg_offset;
+	}
+      /* Check whether we actually know the physical volume we want to
+	 read from.  */
+      if (pv->disk)
+	err = grub_disk_read (pv->disk, offset, 0,
+			      size << GRUB_DISK_SECTOR_BITS, buf);
+      else
+	err = grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+			  "physical volume %s not found", pv->name);
+
+      return err;
+    case GRUB_LVM_MIRROR:
+      i = 0;
+      while (1)
+	{
+	  if (!seg->mirrors[i].lv)
+	    err = grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume '%s'",
+			      seg->mirrors[i].lvname);
+	  else
+	    err = read_lv (seg->mirrors[i].lv, sector, size, buf);
+	  if (!err)
+	    return err;
+	  if (++i >= seg->mirror_count)
+	    return err;
+	  grub_errno = GRUB_ERR_NONE;
+	}
+    }
+  return grub_error (GRUB_ERR_IO, "unknown LVM segment");
+}
+
+static grub_err_t
+grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
+		grub_size_t size, char *buf)
+{
+  return read_lv (disk->data, sector, size, buf);
 }
 
 static grub_err_t
@@ -533,11 +566,7 @@
 
 	      lv->size = 0;
 
-	      if (!grub_lvm_check_flag (p, "status", "VISIBLE"))
-		{
-		  skip_lv = 1;
-		  goto lv_parsed;
-		}
+	      lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
 
 	      lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
 	      if (p == NULL)
@@ -552,7 +581,6 @@
 
 	      for (i = 0; i < lv->segment_count; i++)
 		{
-		  struct grub_lvm_stripe *stripe;
 
 		  p = grub_strstr (p, "segment");
 		  if (p == NULL)
@@ -580,78 +608,147 @@
 		      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 = ");
+		  p = grub_strstr (p, "type = \"");
 		  if (p == NULL)
-		    {
-#ifdef GRUB_UTIL
-		      grub_util_info ("unknown stripe_count\n");
-#endif
-		      goto lvs_segment_fail;
-		    }
+		    goto lvs_segment_fail;
+		  p += sizeof("type = \"") - 1;
 
 		  lv->size += seg->extent_count * vg->extent_size;
 
-		  if (seg->stripe_count != 1)
-		    seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
-
-		  seg->stripes = grub_malloc (sizeof (*stripe)
-					      * seg->stripe_count);
-		  stripe = seg->stripes;
-
-		  p = grub_strstr (p, "stripes = [");
-		  if (p == NULL)
-		    {
-#ifdef GRUB_UTIL
-		      grub_util_info ("unknown stripes\n");
-#endif
-		      goto lvs_segment_fail2;
-		    }
-		  p += sizeof("stripes = [") - 1;
-
-		  for (j = 0; j < seg->stripe_count; j++)
-		    {
-		      char *pvname;
-
-		      p = grub_strchr (p, '"');
-		      if (p == NULL)
-			continue;
-		      q = ++p;
-		      while (*q != '"')
-			q++;
-
-		      s = q - p;
-
-		      pvname = grub_malloc (s + 1);
-                      if (pvname == NULL)
-                        goto lvs_segment_fail2;
-
-		      grub_memcpy (pvname, p, s);
-		      pvname[s] = '\0';
-
-		      if (vg->pvs)
-			for (pv = vg->pvs; pv; pv = pv->next)
-			  {
-			    if (! grub_strcmp (pvname, pv->name))
+		  if (grub_memcmp (p, "striped\"",
+				   sizeof ("striped\"") - 1) == 0)
+		    {
+		      struct grub_lvm_stripe *stripe;
+
+		      seg->type = GRUB_LVM_STRIPED;
+		      seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = ");
+		      if (p == NULL)
+			{
+#ifdef GRUB_UTIL
+			  grub_util_info ("unknown stripe_count\n");
+#endif
+			  goto lvs_segment_fail;
+			}
+
+		      if (seg->stripe_count != 1)
+			seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
+
+		      seg->stripes = grub_malloc (sizeof (*stripe)
+						  * seg->stripe_count);
+		      stripe = seg->stripes;
+
+		      p = grub_strstr (p, "stripes = [");
+		      if (p == NULL)
+			{
+#ifdef GRUB_UTIL
+			  grub_util_info ("unknown stripes\n");
+#endif
+			  goto lvs_segment_fail2;
+			}
+		      p += sizeof("stripes = [") - 1;
+
+		      for (j = 0; j < seg->stripe_count; j++)
+			{
+			  char *pvname;
+
+			  p = grub_strchr (p, '"');
+			  if (p == NULL)
+			    continue;
+			  q = ++p;
+			  while (*q != '"')
+			    q++;
+
+			  s = q - p;
+
+			  pvname = grub_malloc (s + 1);
+			  if (pvname == NULL)
+			    goto lvs_segment_fail2;
+
+			  grub_memcpy (pvname, p, s);
+			  pvname[s] = '\0';
+
+			  if (vg->pvs)
+			    for (pv = vg->pvs; pv; pv = pv->next)
 			      {
-				stripe->pv = pv;
-				break;
+				if (! grub_strcmp (pvname, pv->name))
+				  {
+				    stripe->pv = pv;
+				    break;
+				  }
 			      }
-			  }
-
-		      grub_free(pvname);
-
-		      stripe->start = grub_lvm_getvalue (&p, ",");
-		      if (p == NULL)
-			continue;
-
-		      stripe++;
+
+			  grub_free(pvname);
+
+			  stripe->start = grub_lvm_getvalue (&p, ",");
+			  if (p == NULL)
+			    continue;
+
+			  stripe++;
+			}
+		    }
+		  else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
+			   == 0)
+		    {
+		      seg->type = GRUB_LVM_MIRROR;
+		      seg->mirror_count = grub_lvm_getvalue (&p, "mirror_count = ");
+		      if (p == NULL)
+			{
+#ifdef GRUB_UTIL
+			  grub_util_info ("unknown mirror_count\n");
+#endif
+			  goto lvs_segment_fail;
+			}
+
+		      seg->mirrors = grub_zalloc (sizeof (seg->mirrors[0])
+						  * seg->mirror_count);
+
+		      p = grub_strstr (p, "mirrors = [");
+		      if (p == NULL)
+			{
+#ifdef GRUB_UTIL
+			  grub_util_info ("unknown mirrors\n");
+#endif
+			  goto lvs_segment_fail2;
+			}
+		      p += sizeof("mirrors = [") - 1;
+
+		      for (j = 0; j < seg->mirror_count; j++)
+			{
+			  char *lvname;
+
+			  p = grub_strchr (p, '"');
+			  if (p == NULL)
+			    continue;
+			  q = ++p;
+			  while (*q != '"')
+			    q++;
+
+			  s = q - p;
+
+			  lvname = grub_malloc (s + 1);
+			  if (lvname == NULL)
+			    goto lvs_segment_fail2;
+
+			  grub_memcpy (lvname, p, s);
+			  lvname[s] = '\0';
+			  seg->mirrors[j].lvname = lvname;
+			  p = q + 1;
+			}
+		    }
+		  else
+		    {
+#ifdef GRUB_UTIL
+		      char *p2;
+		      p2 = grub_strchr (p, '"');
+		      if (p2)
+			*p2 = 0;
+		      grub_util_info ("unknown LVM type %s\n", p);
+		      if (p2)
+			*p2 ='"';
+#endif
+		      /* Found a non-supported type, give up and move on. */
+		      skip_lv = 1;
+		      break;
 		    }
 
 		  seg++;
@@ -663,7 +760,6 @@
 		  goto fail4;
 		}
 
-	    lv_parsed:
 	      if (p != NULL)
 		p = grub_strchr (p, '}');
 	      if (p == NULL)
@@ -690,6 +786,20 @@
 	    }
 	}
 
+      /* Match mirrors  */
+      {
+	struct grub_lvm_lv *lv1;
+	struct grub_lvm_lv *lv2;
+	for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
+	  for (i = 0; i < lv1->segment_count; i++)
+	    if (lv1->segments[i].type == GRUB_LVM_MIRROR)
+	      for (j = 0; j < lv1->segments[i].mirror_count; j++)
+		for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
+		  if (grub_strcmp (lv2->name + grub_strlen (vg->name) + 1,
+				   lv1->segments[i].mirrors[j].lvname) == 0)
+		    lv1->segments[i].mirrors[j].lv = lv2;
+      }
+
 	vg->next = vg_list;
 	vg_list = vg;
     }

=== modified file 'include/grub/lvm.h'
--- include/grub/lvm.h	2009-06-10 21:04:23 +0000
+++ include/grub/lvm.h	2011-03-28 03:08:11 +0000
@@ -47,6 +47,9 @@
   unsigned int number;
   unsigned int segment_count;
   grub_uint64_t size;
+
+  int visible;
+
   struct grub_lvm_segment *segments; /* Pointer to segment_count segments. */
   struct grub_lvm_vg *vg;
   struct grub_lvm_lv *next;
@@ -55,6 +58,11 @@
 struct grub_lvm_segment {
   unsigned int start_extent;
   unsigned int extent_count;
+  enum { GRUB_LVM_STRIPED, GRUB_LVM_MIRROR } type; 
+
+  unsigned int mirror_count;
+  struct grub_lvm_mirror *mirrors;
+
   unsigned int stripe_count;
   unsigned int stripe_size;
   struct grub_lvm_stripe *stripes; /* Pointer to stripe_count stripes. */
@@ -65,6 +73,11 @@
   struct grub_lvm_pv *pv;
 };
 
+struct grub_lvm_mirror {
+  char *lvname;
+  struct grub_lvm_lv *lv;
+};
+
 #define GRUB_LVM_LABEL_SIZE GRUB_DISK_SECTOR_SIZE
 #define GRUB_LVM_LABEL_SCAN_SECTORS 4L
 

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to