This is my proposed approach for fixing the partmap detection problem in
LVM/RAID.

The problem: grub-probe just tests for partmap in the target drive directly
(which usually doesn't have any), and not in the physical drives that make
the RAID array (or LVM volume).

My proposed solution:  RAID implements grub_raid_parent, which returns a
linked list of "parent" (alternate naming suggestions welcome!) drives
conforming a specific array.  grub_disk_t abstracts that by providing a
parent() member (for GRUB_UTIL only) on top of it (so e.g. LVM can
implement the same).  grub-probe receives the list from this interface
and probes partmap in each member.

I had in mind something nifty with probe() recursing into itself, in order
to support bizarre combinations like lvm inside dm-raid, but on second
thoughts my current change is not intrusive and wouldn't preclude this kind
of restructuring if someone feels like it.

Comments?

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../old/disk/raid.c ./disk/raid.c
--- ../old/disk/raid.c	2007-12-30 09:52:03.000000000 +0100
+++ ./disk/raid.c	2008-02-06 21:44:30.000000000 +0100
@@ -67,6 +67,26 @@ grub_raid_iterate (int (*hook) (const ch
   return 0;
 }
 
+#ifdef GRUB_UTIL
+static grub_parent_t
+grub_raid_parent (grub_disk_t disk)
+{
+  struct grub_raid_array *array = disk->data;
+  grub_parent_t list = NULL, tmp;
+  int i;
+  
+  for (i = 0; i < array->total_devs; i++)
+    {
+      tmp = grub_malloc (sizeof (*tmp));
+      tmp->disk = array->device[i];
+      tmp->next = list;
+      list = tmp;
+    }
+  
+  return list;
+}
+#endif
+
 static grub_err_t
 grub_raid_open (const char *name, grub_disk_t disk)
 {
@@ -524,6 +544,9 @@ static struct grub_disk_dev grub_raid_de
     .close = grub_raid_close,
     .read = grub_raid_read,
     .write = grub_raid_write,
+#ifdef GRUB_UTIL
+    .parent = grub_raid_parent,
+#endif
     .next = 0
   };
 
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../old/include/grub/disk.h ./include/grub/disk.h
--- ../old/include/grub/disk.h	2008-01-21 00:20:36.000000000 +0100
+++ ./include/grub/disk.h	2008-02-06 21:43:19.000000000 +0100
@@ -40,6 +40,9 @@ enum grub_disk_dev_id
   };
 
 struct grub_disk;
+#ifdef GRUB_UTIL
+struct grub_parent;
+#endif
 
 /* Disk device.  */
 struct grub_disk_dev
@@ -67,6 +70,10 @@ struct grub_disk_dev
   grub_err_t (*write) (struct grub_disk *disk, grub_disk_addr_t sector,
 		       grub_size_t size, const char *buf);
 
+#ifdef GRUB_UTIL
+  struct grub_parent *(*parent) (struct grub_disk *disk);
+#endif
+
   /* The next disk device.  */
   struct grub_disk_dev *next;
 };
@@ -105,6 +112,15 @@ struct grub_disk
 };
 typedef struct grub_disk *grub_disk_t;
 
+#ifdef GRUB_UTIL
+struct grub_parent
+{
+  grub_disk_t disk;
+  struct grub_parent *next;
+};
+typedef struct grub_parent *grub_parent_t;
+#endif
+
 /* The sector size.  */
 #define GRUB_DISK_SECTOR_SIZE	0x200
 #define GRUB_DISK_SECTOR_BITS	9
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../old/util/grub-probe.c ./util/grub-probe.c
--- ../old/util/grub-probe.c	2008-02-06 22:09:01.000000000 +0100
+++ ./util/grub-probe.c	2008-02-06 22:09:20.000000000 +0100
@@ -75,6 +75,31 @@ grub_refresh (void)
 }
 
 static void
+probe_partmap (grub_disk_t disk)
+{
+  char *name;
+  char *underscore;
+  
+  if (disk->partition == NULL)
+    {
+      grub_util_info ("No partition map found for %s", disk->name);
+      return;
+    }
+  
+  name = strdup (disk->partition->partmap->name);
+  if (! name)
+    grub_util_error ("Not enough memory");
+  
+  underscore = strchr (name, '_');
+  if (! underscore)
+    grub_util_error ("Invalid partition map %s", name);
+  
+  *underscore = '\0';
+  printf ("%s\n", name);
+  free (name);
+}
+
+static void
 probe (const char *path)
 {
   char *device_name;
@@ -133,23 +158,17 @@ probe (const char *path)
 
   if (print == PRINT_PARTMAP)
     {
-      char *name;
-      char *underscore;
-      
-      if (dev->disk->partition == NULL)
-        grub_util_error ("Cannot detect partition map for %s", drive_name);
-
-      name = strdup (dev->disk->partition->partmap->name);
-      if (! name)
-	grub_util_error ("not enough memory");
-
-      underscore = strchr (name, '_');
-      if (! underscore)
-	grub_util_error ("Invalid partition map %s", name);
-
-      *underscore = '\0';
-      printf ("%s\n", name);
-      free (name);
+      grub_parent_t list = NULL;
+      /* Check if dev->disk itself is contained in a partmap.  */
+      probe_partmap (dev->disk);
+      /* In case of LVM/RAID, check the parent devices as well.  */
+      if (dev->disk->dev->parent)
+	list = dev->disk->dev->parent (dev->disk);
+      while (list)
+	{
+	  probe_partmap (list->disk);
+	  list = list->next;
+	}
       goto end;
     }
 
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to