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