diff --git a/disk/lvm.c b/disk/lvm.c index 6707a40..126b494 100644 --- a/disk/lvm.c +++ b/disk/lvm.c @@ -271,15 +271,9 @@ grub_lvm_scan_device (const char *name) dlocn++; mda_offset = grub_le_to_cpu64 (dlocn->offset); mda_size = grub_le_to_cpu64 (dlocn->size); - dlocn++; - if (dlocn->offset) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "We don't support multiple LVM metadata areas"); - - goto fail; - } + /* It's possible to have multiple copies of metadata areas, we just use the + first one. */ /* Allocate buffer space for the circular worst-case scenario. */ metadatabuf = grub_malloc (2 * mda_size); @@ -564,7 +558,10 @@ grub_lvm_scan_device (const char *name) { if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN)) { - pv->disk = grub_disk_open (name); + /* This could happen to LVM on RAID, pv->disk points to the + raid device, we shouldn't change it. */ + if (! pv->disk) + pv->disk = grub_disk_open (name); break; } } diff --git a/disk/raid.c b/disk/raid.c index 941620c..3e832ba 100644 --- a/disk/raid.c +++ b/disk/raid.c @@ -596,56 +596,6 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, static grub_raid_t grub_raid_list; static void -grub_raid_scan_device (int head_only) -{ - auto int hook (const char *name); - int hook (const char *name) - { - grub_disk_t disk; - struct grub_raid_array array; - struct grub_raid *p; - - grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); - - disk = grub_disk_open (name); - if (!disk) - return 0; - - if (disk->total_sectors == GRUB_ULONG_MAX) - { - grub_disk_close (disk); - return 0; - } - - for (p = grub_raid_list; p; p = p->next) - { - if (! p->detect (disk, &array)) - { - if (! insert_array (disk, &array, p->name)) - return 0; - - break; - } - - /* This error usually means it's not raid, no need to display - it. */ - if (grub_errno != GRUB_ERR_OUT_OF_RANGE) - grub_print_error (); - - grub_errno = GRUB_ERR_NONE; - if (head_only) - break; - } - - grub_disk_close (disk); - - return 0; - } - - grub_device_iterate (&hook); -} - -static void free_array (void) { struct grub_raid_array *array; @@ -674,9 +624,38 @@ free_array (void) void grub_raid_register (grub_raid_t raid) { + auto int hook (const char *name); + int hook (const char *name) + { + grub_disk_t disk; + struct grub_raid_array array; + + grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); + + disk = grub_disk_open (name); + if (!disk) + return 0; + + if ((disk->total_sectors != GRUB_ULONG_MAX) && + (! grub_raid_list->detect (disk, &array)) && + (! insert_array (disk, &array, grub_raid_list->name))) + return 0; + + /* This error usually means it's not raid, no need to display + it. */ + if (grub_errno != GRUB_ERR_OUT_OF_RANGE) + grub_print_error (); + + grub_errno = GRUB_ERR_NONE; + + grub_disk_close (disk); + + return 0; + } + raid->next = grub_raid_list; grub_raid_list = raid; - grub_raid_scan_device (1); + grub_device_iterate (&hook); } void @@ -692,13 +671,6 @@ grub_raid_unregister (grub_raid_t raid) } } -void -grub_raid_rescan (void) -{ - free_array (); - grub_raid_scan_device (0); -} - static struct grub_disk_dev grub_raid_dev = { .name = "raid", diff --git a/disk/raid5_recover.c b/disk/raid5_recover.c index a280be1..31cef88 100644 --- a/disk/raid5_recover.c +++ b/disk/raid5_recover.c @@ -32,10 +32,12 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr, int i; size <<= GRUB_DISK_SECTOR_BITS; - buf2 = grub_zalloc (size); + buf2 = grub_malloc (size); if (!buf2) return grub_errno; + grub_memset (buf, 0, size); + for (i = 0; i < (int) array->total_devs; i++) { grub_err_t err; diff --git a/include/grub/raid.h b/include/grub/raid.h index 595ced1..8fa4c38 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -67,7 +67,6 @@ typedef struct grub_raid *grub_raid_t; void grub_raid_register (grub_raid_t raid); void grub_raid_unregister (grub_raid_t raid); -void grub_raid_rescan (void); void grub_raid_block_xor (char *buf1, const char *buf2, int size); typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_raid_array *array, diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 4722269..1bb3706 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -293,7 +292,13 @@ fstest (char **images, int num_disks, int cmd, int n, char **args) grub_util_error ("loopback command fails."); } - grub_raid_rescan (); + grub_lvm_fini (); + grub_mdraid_fini (); + grub_raid_fini (); + grub_raid_init (); + grub_mdraid_init (); + grub_lvm_init (); + switch (cmd) { case CMD_LS: diff --git a/util/grub-probe.c b/util/grub-probe.c index 97d3860..147e41f 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -100,13 +101,21 @@ probe_partmap (grub_disk_t disk) free (name); } +static int +probe_raid_level (grub_disk_t disk) +{ + if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID) + return -1; + + return ((struct grub_raid_array *) disk->data)->level; +} + static void probe (const char *path, char *device_name) { char *drive_name = NULL; char *grub_path = NULL; char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL; - int abstraction_type; grub_device_t dev = NULL; grub_fs_t fs; @@ -132,28 +141,6 @@ probe (const char *path, char *device_name) goto end; } - abstraction_type = grub_util_get_dev_abstraction (device_name); - /* No need to check for errors; lack of abstraction is permissible. */ - - if (print == PRINT_ABSTRACTION) - { - char *abstraction_name; - switch (abstraction_type) - { - case GRUB_DEV_ABSTRACTION_LVM: - abstraction_name = "lvm"; - break; - case GRUB_DEV_ABSTRACTION_RAID: - abstraction_name = "raid mdraid"; - break; - default: - grub_util_info ("did not find LVM/RAID in %s, assuming raw device", device_name); - goto end; - } - printf ("%s\n", abstraction_name); - goto end; - } - drive_name = grub_util_get_grub_dev (device_name); if (! drive_name) grub_util_error ("Cannot find a GRUB drive for %s. Check your device.map.\n", device_name); @@ -169,6 +156,56 @@ probe (const char *path, char *device_name) if (! dev) grub_util_error ("%s", grub_errmsg); + if (print == PRINT_ABSTRACTION) + { + grub_disk_memberlist_t list = NULL, tmp; + const int is_lvm = (dev->disk->dev->id == GRUB_DISK_DEVICE_LVM_ID); + int is_raid = 0; + int is_raid5 = 0; + int is_raid6 = 0; + int raid_level; + + raid_level = probe_raid_level (dev->disk); + if (raid_level >= 0) + { + is_raid = 1; + is_raid5 |= (raid_level == 5); + is_raid6 |= (raid_level == 6); + } + + if ((is_lvm) && (dev->disk->dev->memberlist)) + list = dev->disk->dev->memberlist (dev->disk); + while (list) + { + raid_level = probe_raid_level (list->disk); + if (raid_level >= 0) + { + is_raid = 1; + is_raid5 |= (raid_level == 5); + is_raid6 |= (raid_level == 6); + } + + tmp = list->next; + free (list); + list = tmp; + } + + if (is_raid) + { + printf ("raid\n"); + if (is_raid5) + printf ("raid5rec\n"); + if (is_raid6) + printf ("raid6rec\n"); + printf ("mdraid\n"); + } + + if (is_lvm) + printf ("lvm\n"); + + goto end; + } + if (print == PRINT_PARTMAP) { grub_disk_memberlist_t list = NULL, tmp; @@ -182,6 +219,20 @@ probe (const char *path, char *device_name) while (list) { probe_partmap (list->disk); + /* LVM on RAID */ + if (list->disk->dev->memberlist) + { + grub_disk_memberlist_t sub_list; + + sub_list = list->disk->dev->memberlist (list->disk); + while (sub_list) + { + probe_partmap (sub_list->disk); + tmp = sub_list->next; + free (sub_list); + sub_list = tmp; + } + } tmp = list->next; free (list); list = tmp;