diff --git a/ChangeLog b/ChangeLog index 200058f29..fab3ecb22 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,53 @@ +2010-07-20 Colin Watson + + * disk/raid.c (insert_array): Use md/%s to name mdadm 1.x devices, + removing the homehost if present. + * kern/emu/getroot.c (get_mdadm_name) [__linux__]: New function. + (grub_util_get_grub_dev): Use md/%s to name mdadm 1.x devices, + removing the homehost if present. + (grub_util_get_grub_dev) [__linux__]: Get the array name from mdadm + if possible. + * util/i386/pc/grub-setup.c (main): Handle md/* devices. + + * disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Add start_sector + parameter. Set its pointer target to 0. + * disk/mdraid_linux.c (grub_mdraid_detect): Add start_sector + parameter. Set its pointer target to 0 for 0.9 metadata, or to the + `data_offset' value from the superblock for 1.x metadata. + * disk/raid.c (grub_raid_read): Offset reads by the start sector of + data on the device. + (insert_array): Record the start sector of data on the device. + (grub_raid_register): Pass start_sector parameters to + grub_raid_list->detect and insert_array. + * include/grub/raid.h (struct grub_raid_array): Add start_sector + member. + (struct grub_raid): Add start_sector parameter to `detect'. + + * disk/mdraid_linux.c (struct grub_raid_super_1x): Remove + __attribute__ ((packed)), leaving a comment. + (grub_mdraid_detect): Split out 0.9 and 1.x detection to ... + (grub_mdraid_detect_09): ... here and ... + (grub_mdraid_detect_1x): ... here. + +2010-07-20 Peter Henn + + * disk/mdraid_linux.c (grub_mdraid_detect): Fix calculation of 1.x + chunk size and disk size, which are already given as sector counts + as distinct from the 0.90 units. Fetch the correct device number + from the role table instead of using the table index. + +2010-07-20 Felix Zielcke + + * disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Set array->name to NULL. + * disk/mdraid_linux.c (grub_raid_super_1x): New structure. + (WriteMostly1): New macro. + Set array->name to NULL for metadata format 0.90. Add support for + metadata 1.x. Fix some comments. + * disk/raid.c (): Add support for name based RAID arrays. Fix a + few comments. + * util/getroot.c (grub_util_get_grub_dev): Add support for + /dev/md/name style devices. + 2010-07-20 Colin Watson * .bzrignore: Ignore 20_linux_xen. diff --git a/disk/dmraid_nvidia.c b/disk/dmraid_nvidia.c index c4e3922cf..d3f45935c 100644 --- a/disk/dmraid_nvidia.c +++ b/disk/dmraid_nvidia.c @@ -89,7 +89,8 @@ struct grub_nv_super } __attribute__ ((packed)); static grub_err_t -grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) +grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector) { grub_disk_addr_t sector; struct grub_nv_super sb; @@ -132,6 +133,7 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) "unsupported RAID level: %d", sb.array.raid_level); } + array->name = NULL; array->number = 0; array->total_devs = sb.array.total_volumes; array->chunk_size = sb.array.stripe_block_size; @@ -144,6 +146,8 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) grub_memcpy (array->uuid, (char *) &sb.array.signature, sizeof (sb.array.signature)); + *start_sector = 0; + return 0; } diff --git a/disk/mdraid_linux.c b/disk/mdraid_linux.c index 306c66a8b..d5a0aad47 100644 --- a/disk/mdraid_linux.c +++ b/disk/mdraid_linux.c @@ -1,7 +1,7 @@ -/* mdraid_linux.c - module to handle linux softraid. */ +/* mdraid_linux.c - module to handle Linux Software RAID. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -159,63 +159,254 @@ struct grub_raid_super_09 struct grub_raid_disk_09 this_disk; } __attribute__ ((packed)); -static grub_err_t -grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array) +/* + * The version-1 superblock : + * All numeric fields are little-endian. + * + * Total size: 256 bytes plus 2 per device. + * 1K allows 384 devices. + */ + +struct grub_raid_super_1x +{ + /* Constant array information - 128 bytes. */ + grub_uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian. */ + grub_uint32_t major_version; /* 1. */ + grub_uint32_t feature_map; /* Bit 0 set if 'bitmap_offset' is meaningful. */ + grub_uint32_t pad0; /* Always set to 0 when writing. */ + + grub_uint8_t set_uuid[16]; /* User-space generated. */ + char set_name[32]; /* Set and interpreted by user-space. */ + + grub_uint64_t ctime; /* Lo 40 bits are seconds, top 24 are microseconds or 0. */ + grub_uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5. */ + grub_uint32_t layout; /* only for raid5 and raid10 currently. */ + grub_uint64_t size; /* Used size of component devices, in 512byte sectors. */ + + grub_uint32_t chunksize; /* In 512byte sectors. */ + grub_uint32_t raid_disks; + grub_uint32_t bitmap_offset; /* Sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + + /* These are only valid with feature bit '4'. */ + grub_uint32_t new_level; /* New level we are reshaping to. */ + grub_uint64_t reshape_position; /* Next address in array-space for reshape. */ + grub_uint32_t delta_disks; /* Change in number of raid_disks. */ + grub_uint32_t new_layout; /* New layout. */ + grub_uint32_t new_chunk; /* New chunk size (512byte sectors). */ + grub_uint8_t pad1[128 - 124]; /* Set to 0 when written. */ + + /* Constant this-device information - 64 bytes. */ + grub_uint64_t data_offset; /* Sector start of data, often 0. */ + grub_uint64_t data_size; /* Sectors in this device that can be used for data. */ + grub_uint64_t super_offset; /* Sector start of this superblock. */ + grub_uint64_t recovery_offset; /* Sectors before this offset (from data_offset) have been recovered. */ + grub_uint32_t dev_number; /* Permanent identifier of this device - not role in raid. */ + grub_uint32_t cnt_corrected_read; /* Number of read errors that were corrected by re-writing. */ + grub_uint8_t device_uuid[16]; /* User-space setable, ignored by kernel. */ + grub_uint8_t devflags; /* Per-device flags. Only one defined... */ + grub_uint8_t pad2[64 - 57]; /* Set to 0 when writing. */ + + /* Array state information - 64 bytes. */ + grub_uint64_t utime; /* 40 bits second, 24 btes microseconds. */ + grub_uint64_t events; /* Incremented when superblock updated. */ + grub_uint64_t resync_offset; /* Data before this offset (from data_offset) known to be in sync. */ + grub_uint32_t sb_csum; /* Checksum upto devs[max_dev]. */ + grub_uint32_t max_dev; /* Size of devs[] array to consider. */ + grub_uint8_t pad3[64 - 32]; /* Set to 0 when writing. */ + + /* Device state information. Indexed by dev_number. + * 2 bytes per device. + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + grub_uint16_t dev_roles[0]; /* Role in array, or 0xffff for a spare, or 0xfffe for faulty. */ +}; +/* Could be __attribute__ ((packed)), but since all members in this struct + are already appropriately aligned, we can omit this and avoid suboptimal + assembly in some cases. */ + +#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */ + +static grub_err_t +grub_mdraid_detect_09 (grub_disk_addr_t sector, + struct grub_raid_super_09 *sb, + struct grub_raid_array *array, + grub_disk_addr_t *start_sector) { - grub_disk_addr_t sector; - grub_uint64_t size; - struct grub_raid_super_09 sb; grub_uint32_t *uuid; - /* The sector where the RAID superblock is stored, if available. */ - size = grub_disk_get_size (disk); - sector = NEW_SIZE_SECTORS (size); - - if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb)) - return grub_errno; - - /* Look whether there is a RAID superblock. */ - if (sb.md_magic != SB_MAGIC) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); - - /* FIXME: Also support version 1.0. */ - if (sb.major_version != 0 || sb.minor_version != 90) + if (sb->major_version != 0 || sb->minor_version != 90) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported RAID version: %d.%d", - sb.major_version, sb.minor_version); + sb->major_version, sb->minor_version); - /* FIXME: Check the checksum. */ + /* FIXME: Check the checksum. */ /* Multipath. */ - if ((int) sb.level == -4) - sb.level = 1; + if ((int) sb->level == -4) + sb->level = 1; - if (sb.level != 0 && sb.level != 1 && sb.level != 4 && - sb.level != 5 && sb.level != 6 && sb.level != 10) + if (sb->level != 0 && sb->level != 1 && sb->level != 4 && + sb->level != 5 && sb->level != 6 && sb->level != 10) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID level: %d", sb.level); + "unsupported RAID level: %d", sb->level); - array->number = sb.md_minor; - array->level = sb.level; - array->layout = sb.layout; - array->total_devs = sb.raid_disks; - array->disk_size = (sb.size) ? sb.size * 2 : sector; - array->chunk_size = sb.chunk_size >> 9; - array->index = sb.this_disk.number; + array->name = NULL; + array->number = sb->md_minor; + array->level = sb->level; + array->layout = sb->layout; + array->total_devs = sb->raid_disks; + array->disk_size = (sb->size) ? sb->size * 2 : sector; + array->chunk_size = sb->chunk_size >> 9; + array->index = sb->this_disk.number; array->uuid_len = 16; array->uuid = grub_malloc (16); if (!array->uuid) - return grub_errno; + return grub_errno; uuid = (grub_uint32_t *) array->uuid; - uuid[0] = sb.set_uuid0; - uuid[1] = sb.set_uuid1; - uuid[2] = sb.set_uuid2; - uuid[3] = sb.set_uuid3; + uuid[0] = sb->set_uuid0; + uuid[1] = sb->set_uuid1; + uuid[2] = sb->set_uuid2; + uuid[3] = sb->set_uuid3; + + *start_sector = 0; return 0; } +static grub_err_t +grub_mdraid_detect_1x (grub_disk_t disk, grub_disk_addr_t sector, + struct grub_raid_super_1x *sb, + struct grub_raid_array *array, + grub_disk_addr_t *start_sector) +{ + grub_uint64_t sb_size; + struct grub_raid_super_1x *real_sb; + + if (sb->major_version != 1) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID version: %d", + sb->major_version); + + /* Multipath. */ + if ((int) sb->level == -4) + sb->level = 1; + + if (sb->level != 0 && sb->level != 1 && sb->level != 4 && + sb->level != 5 && sb->level != 6 && sb->level != 10) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID level: %d", sb->level); + + /* 1.x superblocks don't have a fixed size on disk. So we have to + read it again now that we now the max device count. */ + sb_size = sizeof (struct grub_raid_super_1x) + 2 * grub_le_to_cpu32 (sb->max_dev); + real_sb = grub_malloc (sb_size); + if (! real_sb) + return grub_errno; + + if (grub_disk_read (disk, sector, 0, sb_size, real_sb)) + { + grub_free (real_sb); + return grub_errno; + } + + array->name = grub_strdup (real_sb->set_name); + if (! array->name) + { + grub_free (real_sb); + return grub_errno; + } + + array->number = 0; + array->level = grub_le_to_cpu32 (real_sb->level); + array->layout = grub_le_to_cpu32 (real_sb->layout); + array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks); + array->disk_size = grub_le_to_cpu64 (real_sb->size); + array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize); + if (grub_le_to_cpu32 (real_sb->dev_number) < + grub_le_to_cpu32 (real_sb->max_dev)) + array->index = grub_le_to_cpu16 + (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); + else + array->index = 0xffff; /* disk will be later not used! */ + array->uuid_len = 16; + array->uuid = grub_malloc (16); + if (!array->uuid) + { + grub_free (real_sb); + return grub_errno; + } + + grub_memcpy (array->uuid, real_sb->set_uuid, 16); + + *start_sector = real_sb->data_offset; + + grub_free (real_sb); + return 0; +} + +static grub_err_t +grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector) +{ + grub_disk_addr_t sector; + grub_uint64_t size; + struct grub_raid_super_09 sb_09; + struct grub_raid_super_1x sb_1x; + grub_uint8_t minor_version; + + /* The sector where the mdraid 0.90 superblock is stored, if available. */ + size = grub_disk_get_size (disk); + sector = NEW_SIZE_SECTORS (size); + + if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb_09)) + return grub_errno; + + /* Look whether there is a mdraid 0.90 superblock. */ + if (sb_09.md_magic == SB_MAGIC) + return grub_mdraid_detect_09 (sector, &sb_09, array, start_sector); + + /* Check for an 1.x superblock. + * It's always aligned to a 4K boundary + * and depending on the minor version it can be: + * 0: At least 8K, but less than 12K, from end of device + * 1: At start of device + * 2: 4K from start of device. + */ + + for (minor_version = 0; minor_version < 3; ++minor_version) + { + switch (minor_version) + { + case 0: + sector = (size - 8 * 2) & ~(4 * 2 - 1); + break; + case 1: + sector = 0; + break; + case 2: + sector = 4 * 2; + break; + } + + if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), + &sb_1x)) + return grub_errno; + + if (sb_1x.magic == SB_MAGIC) + return grub_mdraid_detect_1x (disk, sector, &sb_1x, array, + start_sector); + } + + /* Neither 0.90 nor 1.x. */ + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); +} + static struct grub_raid grub_mdraid_dev = { .name = "mdraid", .detect = grub_mdraid_detect, diff --git a/disk/raid.c b/disk/raid.c index 2d544afdc..43d2a29ff 100644 --- a/disk/raid.c +++ b/disk/raid.c @@ -1,7 +1,7 @@ /* raid.c - module to read RAID arrays. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -254,7 +254,8 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; err = grub_disk_read (array->device[k], - read_sector + j * far_ofs + b, + array->start_sector[k] + + read_sector + j * far_ofs + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); @@ -366,7 +367,8 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; err = grub_disk_read (array->device[disknr], - read_sector + b, 0, + array->start_sector[disknr] + + read_sector + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); @@ -475,12 +477,12 @@ grub_raid_write (grub_disk_t disk __attribute ((unused)), static grub_err_t insert_array (grub_disk_t disk, struct grub_raid_array *new_array, - const char *scanner_name) + grub_disk_addr_t start_sector, const char *scanner_name) { struct grub_raid_array *array = 0, *p; /* See whether the device is part of an array we have already seen a - device from. */ + device from. */ for (p = array_list; p != NULL; p = p->next) if ((p->uuid_len == new_array->uuid_len) && (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len))) @@ -491,7 +493,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* Do some checks before adding the device to the array. */ /* FIXME: Check whether the update time of the superblocks are - the same. */ + the same. */ if (array->total_devs == array->nr_devs) /* We found more members of the array than the array @@ -502,7 +504,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, if (array->device[new_array->index] != NULL) /* We found multiple devices with the same number. Again, - this shouldn't happen.*/ + this shouldn't happen. */ grub_dprintf ("raid", "Found two disks with the number %d?!?", new_array->number); @@ -524,46 +526,72 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, *array = *new_array; array->nr_devs = 0; grub_memset (&array->device, 0, sizeof (array->device)); + grub_memset (&array->start_sector, 0, sizeof (array->start_sector)); - /* Check whether we don't have multiple arrays with the same number. */ + if (array->name) + goto skip_duplicate_check; + /* Check whether we don't have multiple arrays with the same number. */ for (p = array_list; p != NULL; p = p->next) { - if (p->number == array->number) - break; + if (p->number == array->number) + break; } if (p) { - /* The number is already in use, so we need to find an new number. */ + /* The number is already in use, so we need to find a new one. */ int i = 0; - while (1) - { - for (p = array_list; p != NULL; p = p->next) - { - if (p->number == i) - break; - } + while (1) + { + for (p = array_list; p != NULL; p = p->next) + { + if (p->number == i) + break; + } - if (!p) - { - /* We found an unused number. */ - array->number = i; - break; - } + if (! p) + { + /* We found an unused number. */ + array->number = i; + break; + } - i++; - } - } - - array->name = grub_xasprintf ("md%d", array->number); + i++; + } + } + skip_duplicate_check: + /* mdraid 1.x superblocks have only a name stored not a number. + Use it directly as GRUB device. */ if (! array->name) - { - grub_free (array->uuid); - grub_free (array); + { + array->name = grub_xasprintf ("md%d", array->number); + if (! array->name) + { + grub_free (array->uuid); + grub_free (array); - return grub_errno; - } + return grub_errno; + } + } + else + { + /* Strip off the homehost if present. */ + char *colon = grub_strchr (array->name, ':'); + char *new_name = grub_xasprintf ("md/%s", + colon ? colon + 1 : array->name); + + if (! new_name) + { + grub_free (array->uuid); + grub_free (array); + + return grub_errno; + } + + grub_free (array->name); + array->name = new_name; + } grub_dprintf ("raid", "Found array %s (%s)\n", array->name, scanner_name); @@ -580,6 +608,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* Add the device to the array. */ array->device[new_array->index] = disk; + array->start_sector[new_array->index] = start_sector; array->nr_devs++; return 0; @@ -621,6 +650,7 @@ grub_raid_register (grub_raid_t raid) { grub_disk_t disk; struct grub_raid_array array; + grub_disk_addr_t start_sector; grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); @@ -629,8 +659,8 @@ grub_raid_register (grub_raid_t raid) return 0; if ((disk->total_sectors != GRUB_ULONG_MAX) && - (! grub_raid_list->detect (disk, &array)) && - (! insert_array (disk, &array, grub_raid_list->name))) + (! grub_raid_list->detect (disk, &array, &start_sector)) && + (! insert_array (disk, &array, start_sector, grub_raid_list->name))) return 0; /* This error usually means it's not raid, no need to display diff --git a/include/grub/raid.h b/include/grub/raid.h index 8fa4c3814..711a7f79c 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -1,7 +1,7 @@ /* raid.h - On disk structures for RAID. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,8 @@ struct grub_raid_array char *name; /* That will be "md". */ unsigned int nr_devs; /* The number of devices we've found so far. */ grub_disk_t device[GRUB_RAID_MAX_DEVICES]; /* Array of total_devs devices. */ + grub_disk_addr_t start_sector[GRUB_RAID_MAX_DEVICES]; + /* Start of each device, in 512 byte sectors. */ struct grub_raid_array *next; }; @@ -58,7 +60,8 @@ struct grub_raid { const char *name; - grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array); + grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector); struct grub_raid *next; }; diff --git a/kern/emu/getroot.c b/kern/emu/getroot.c index 24b2cd486..9f89bf657 100644 --- a/kern/emu/getroot.c +++ b/kern/emu/getroot.c @@ -1,7 +1,7 @@ /* getroot.c - Get root device */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,11 @@ #include #endif +#ifdef __linux__ +# include +# include +#endif + #include #include #include @@ -516,10 +521,89 @@ grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) return GRUB_DEV_ABSTRACTION_NONE; } +#ifdef __linux__ +static char * +get_mdadm_name (const char *os_dev) +{ + int mdadm_pipe[2]; + pid_t mdadm_pid; + char *name = NULL; + + if (pipe (mdadm_pipe) < 0) + { + grub_util_warn ("Unable to create pipe for mdadm: %s", strerror (errno)); + return NULL; + } + + mdadm_pid = fork (); + if (mdadm_pid < 0) + grub_util_warn ("Unable to fork mdadm: %s", strerror (errno)); + else if (mdadm_pid == 0) + { + /* Child. */ + char *argv[5]; + + close (mdadm_pipe[0]); + dup2 (mdadm_pipe[1], STDOUT_FILENO); + close (mdadm_pipe[1]); + + /* execvp has inconvenient types, hence the casts. None of these + strings will actually be modified. */ + argv[0] = (char *) "mdadm"; + argv[1] = (char *) "--detail"; + argv[2] = (char *) "--export"; + argv[3] = (char *) os_dev; + argv[4] = NULL; + execvp ("mdadm", argv); + exit (127); + } + else + { + /* Parent. Read mdadm's output. */ + FILE *mdadm; + char *buf = NULL; + size_t len = 0; + + close (mdadm_pipe[1]); + mdadm = fdopen (mdadm_pipe[0], "r"); + if (! mdadm) + { + grub_util_warn ("Unable to open stream from mdadm: %s", + strerror (errno)); + goto out; + } + + while (getline (&buf, &len, mdadm) > 0) + { + if (strncmp (buf, "MD_NAME=", sizeof ("MD_NAME=") - 1) == 0) + { + char *name_start, *colon; + size_t name_len; + + free (name); + name_start = buf + sizeof ("MD_NAME=") - 1; + /* Strip off the homehost if present. */ + colon = strchr (name_start, ':'); + name = strdup (colon ? colon + 1 : name_start); + name_len = strlen (name); + if (name[name_len - 1] == '\n') + name[name_len - 1] = '\0'; + } + } + +out: + close (mdadm_pipe[0]); + waitpid (mdadm_pid, NULL, 0); + } + + return name; +} +#endif /* __linux__ */ + char * grub_util_get_grub_dev (const char *os_dev) { - char *grub_dev; + char *grub_dev = NULL; switch (grub_util_get_dev_abstraction (os_dev)) { @@ -600,9 +684,36 @@ grub_util_get_grub_dev (const char *os_dev) grub_dev = xasprintf ("md%s", p); free (p); } + else if (os_dev[7] == '/') + { + /* mdraid 1.x with a free name. */ + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md/") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + asprintf (&grub_dev, "md/%s", p); + free (p); + } else grub_util_error ("unknown kind of RAID device `%s'", os_dev); +#ifdef __linux__ + { + char *mdadm_name = get_mdadm_name (os_dev); + + if (mdadm_name) + { + free (grub_dev); + asprintf (&grub_dev, "md/%s", mdadm_name); + free (mdadm_name); + } + } +#endif /* __linux__ */ + break; default: /* GRUB_DEV_ABSTRACTION_NONE */ diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 8b2f52bb4..524572fad 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -812,14 +812,14 @@ main (int argc, char *argv[]) must_embed = 1; if (root_dev[0] == 'm' && root_dev[1] == 'd' - && root_dev[2] >= '0' && root_dev[2] <= '9') + && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/')) { /* FIXME: we can avoid this on RAID1. */ must_embed = 1; } if (dest_dev[0] == 'm' && dest_dev[1] == 'd' - && dest_dev[2] >= '0' && dest_dev[2] <= '9') + && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/')) { char **devicelist; int i;