Package: grub-common
Version: 1.98+20100804-2
Severity: important
Tags: patch sid squeeze

Hello,

current versions of grub-probe in squeeze and sid have problems with DMRAID
partitions.  The problems are demonstrated below. As a result, grub
lenny->squeeze upgrade failed leaving my system without a bootloader. While
grub-common/lenny had no support for DMRAID at all, it would be a pity to
release current grub-common with half working DMRAID support. Therefore, it
would be great if the bug was fixed in squeeze. A proposed patch is attached
to this mail. Please forward the bug and/or the patch upstream.

As you see, the root is mounted on the DMRAID partition.
$ mount 

/dev/mapper/pdc_bacfhgjjjc1 on / type ext3 (rw,errors=remount-ro)
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
fusectl on /sys/fs/fuse/connections type fusectl (rw)
/dev/mapper/lvmmain-usr on /usr type ext3 (rw,errors=remount-ro)
/dev/mapper/lvmmain-var on /var type ext3 (rw,errors=remount-ro)
/dev/mapper/lvmmain-home on /home type ext3 (rw,errors=remount-ro)
/dev/mapper/lvmmain-data on /mnt/data type ext3 
(rw,user_xattr,errors=remount-ro)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc 
(rw,noexec,nosuid,nodev)

$ cat /boot/grub/device.map

(fd0)   /dev/fd0
(hd0)   /dev/disk/by-id/ata-WDC_WD800BB-00DKA0_WD-WMAHL3755817
(hd1)   /dev/disk/by-id/ata-WDC_WD800BB-00DKA0_WD-WMAHL3848610
(hd2)   /dev/mapper/pdc_bacfhgjjjc

$ ls -l /dev/mapper
total 0
crw------- 1 root root 10, 59 Rgp 24 13:19 control
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 lvmmain-data -> ../dm-6
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 lvmmain-home -> ../dm-5
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 lvmmain-swap -> ../dm-7
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 lvmmain-usr -> ../dm-4
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 lvmmain-var -> ../dm-3
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 pdc_bacfhgjjjc -> ../dm-0
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 pdc_bacfhgjjjc1 -> ../dm-1
lrwxrwxrwx 1 root root      7 Rgp 24 13:19 pdc_bacfhgjjjc2 -> ../dm-2

The attached patch fixes the following issues. The first two prevent
grub-install from working when / is mounted to a partition on the DMRAID disk.

Before patching (1.98+20100804-4):

# grub-probe --device-map=/boot/grub/device.map --target=drive -d 
/dev/mapper/pdc_bacfhgjjjc1
grub-probe: error: cannot find a GRUB drive for /dev/mapper/pdc_bacfhgjjjc1.  
Check your device.map.

# grub-probe --device-map=/boot/grub/device.map --target=fs /
grub-probe: error: cannot find a GRUB drive for /dev/mapper/pdc_bacfhgjjjc1.  
Check your device.map.

# grub-probe --device-map=/boot/grub/device.map --target=drive -d /dev/dm-1
(/dev/dm-1)

# grub-probe --device-map=/boot/grub/device.map --target=drive -d 
/dev/mapper/pdc_bacfhgjjjc
(hd2)

# grub-probe --device-map=/boot/grub/device.map --target=drive -d /dev/dm-0
(hd2)

After patching:

# grub-probe --device-map=/boot/grub/device.map --target=drive -d 
/dev/mapper/pdc_bacfhgjjjc1
(hd2,msdos1)

# grub-probe --device-map=/boot/grub/device.map --target=fs /
ext2

# grub-probe --device-map=/boot/grub/device.map --target=drive -d /dev/dm-1
(hd2,msdos1)

# grub-probe --device-map=/boot/grub/device.map --target=drive -d 
/dev/mapper/pdc_bacfhgjjjc
(hd2)

# grub-probe --device-map=/boot/grub/device.map --target=drive -d /dev/dm-0
(hd2)

The patch also fixes a memory leak which I discovered when fixing the above
(error message originates from libdevmapper):

# grub-probe --device-map=/boot/grub/device.map --target=fs /
ext2
You have a memory leak (not released memory pool):
 [0x88157e0]


-- 
Modestas Vainius <[email protected]>
From: Modestas Vainius <[email protected]>
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)

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to