From: Modestas Vainius Subject: fix DMRAID support in grub-probe Forwarded: no Last-Update: 2010-08-24 /dev/mapper/* are symlinks to /dev/dm-* and convert_system_partition_to_system_disk() checks against fully a canonicalized real path. Therefore, it should look for dm-* when identifying DMRAID devices. Likewise, return the same form (/dev/mapper/* or /dev/dm-$minor) which was asked for in the input. This is needed since strcmp() is typically used by the callers to check if returned device is the same as given. While at it, the patch also fixes a memory pool leak in dm_* related code. devmapper library complains loudly about memory pool leaks. --- a/kern/emu/hostdisk.c +++ b/kern/emu/hostdisk.c @@ -1157,13 +1157,14 @@ convert_system_partition_to_system_disk #ifdef HAVE_DEVICE_MAPPER /* If this is a DM-RAID device. */ - if ((strncmp ("mapper/", p, 7) == 0)) + if ((strncmp ("mapper/", p, 7) == 0) + || (strncmp("dm-", p, 3) == 0)) { - static struct dm_tree *tree = NULL; + struct dm_tree *tree = NULL; uint32_t maj, min; - struct dm_tree_node *node, *child; + struct dm_tree_node *node, *child, *mapper_node = NULL; void *handle; - const char *node_uuid, *mapper_name, *child_uuid, *child_name; + const char *node_uuid, *child_uuid; if (! tree) tree = dm_tree_create (); @@ -1171,6 +1172,7 @@ convert_system_partition_to_system_disk if (! tree) { grub_dprintf ("hostdisk", "dm_tree_create failed\n"); + free(path); return NULL; } @@ -1179,29 +1181,29 @@ convert_system_partition_to_system_disk if (! dm_tree_add_dev (tree, maj, min)) { grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n"); - return NULL; + goto devmapper_out; } node = dm_tree_find_node (tree, maj, min); if (! node) { grub_dprintf ("hostdisk", "dm_tree_find_node failed\n"); - return NULL; + goto devmapper_out; } node_uuid = dm_tree_node_get_uuid (node); if (! node_uuid) { grub_dprintf ("hostdisk", "%s has no DM uuid\n", path); - return NULL; + goto devmapper_out; } else if (strncmp (node_uuid, "DMRAID-", 7) != 0) { grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path); - return NULL; + goto devmapper_out; } handle = NULL; - mapper_name = NULL; + mapper_node = node; /* Counter-intuitively, device-mapper refers to the disk-like device containing a DM-RAID partition device as a "child" of the partition device. */ @@ -1222,26 +1224,47 @@ convert_system_partition_to_system_disk grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path); goto devmapper_out; } - child_name = dm_tree_node_get_name (child); - if (! child_name) + mapper_node = child; + +devmapper_out: + if (! mapper_node) { - grub_dprintf ("hostdisk", "%s child has no DM name\n", path); - goto devmapper_out; + /* Unable get info about parent node */ + free(path); + dm_tree_free(tree); + return NULL; } - mapper_name = child_name; -devmapper_out: - if (! mapper_name) + if ((strncmp ("/dev/dm-", os_dev, 8) == 0)) { - /* This is a DM-RAID disk, not a partition. */ - mapper_name = dm_tree_node_get_name (node); - if (! mapper_name) + /* Give a dm-$minor */ + const struct dm_info *info; + info = dm_tree_node_get_info (mapper_node); + if (! info) + { + grub_dprintf ("hostdisk", "%s has no DM info\n", path); + free(path); + dm_tree_free(tree); + return NULL; + } + snprintf (path, PATH_MAX, "/dev/dm-%u", info->minor); + } + else + { + /* Otherwise give a long name that is more user-friendly */ + const char *name; + name = dm_tree_node_get_name (mapper_node); + if (! name) { grub_dprintf ("hostdisk", "%s has no DM name\n", path); + free(path); + dm_tree_free(tree); return NULL; } + snprintf (path, PATH_MAX, "/dev/mapper/%s", name); } - return xasprintf ("/dev/mapper/%s", mapper_name); + dm_tree_free (tree); + return path; } #endif /* HAVE_DEVICE_MAPPER */ } @@ -1354,6 +1377,21 @@ find_system_device (const char *os_dev, os_disk = convert_system_partition_to_system_disk (os_dev, st); if (! os_disk) return -1; +#ifdef __linux__ + /* On Linux, map[i].device is passed through realpath(). See + read_device_map(). Hence use realpath'ed os_disk for strcmp() */ + { + char *rp; + rp = xmalloc (PATH_MAX); + if (realpath (os_disk, rp)) + { + free(os_disk); + os_disk = rp; + } + else + free(rp); + } +#endif for (i = 0; i < ARRAY_SIZE (map); i++) if (! map[i].device)