grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Laager <rlaager@wiktel.com>
To: Zachary Bedell <pendorbound@gmail.com>
Cc: grub-devel@gnu.org
Subject: Re: [Patch] Robustly search for ZFS labels & uberblocks
Date: Fri, 27 Jan 2012 20:50:35 -0600	[thread overview]
Message-ID: <1327719035.9477.68.camel@watermelon.coderich.net> (raw)
In-Reply-To: <C2AFC8B8-54EC-4D2C-824D-C01B2070DBF6@gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 665 bytes --]

On Fri, 2012-01-27 at 14:04 -0500, Zachary Bedell wrote:
> I've had to forward port the other changes necessary to support build on Linux.

Attached is the work I've done on this front. This includes the "allow
spaces in zpools" patch I previously submitted to grub-devel. And, the
changes in 10_linux.in are from dajhorn's Ubuntu packages.

I have not yet made anything boot on RAIDZ. I don't know if that's
caused by this patch.

If the changes to getroot.c are accepted upstream, I'd recommend moving
find_device_from_pool() higher up in that file, rather than using the
prototype, but the prototype keeps the patch smaller for now.

-- 
Richard

[-- Attachment #1.2: zfs-on-linux.patch --]
[-- Type: text/x-patch, Size: 6803 bytes --]

Index: grub/util/grub.d/10_linux.in
===================================================================
--- grub.orig/util/grub.d/10_linux.in	2012-01-24 23:44:10.530591000 -0600
+++ grub/util/grub.d/10_linux.in	2012-01-24 23:44:10.706928000 -0600
@@ -56,8 +56,10 @@
   LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
 fi
 
-if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ] \
-    || [ "x`stat -f --printf=%T /`" = xbtrfs ]; then
+LINUX_ROOT_FS=`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`
+LINUX_ROOT_STAT=`stat -f --printf=%T / || true`
+
+if [ "x${LINUX_ROOT_FS}" = xbtrfs -o "x${LINUX_ROOT_STAT}" = xbtrfs ]; then
   rootsubvol="`make_system_path_relative_to_its_root /`"
   rootsubvol="${rootsubvol#/}"
   if [ "x${rootsubvol}" != x ]; then
@@ -76,6 +78,10 @@
     GRUB_CMDLINE_EXTRA="$GRUB_CMDLINE_EXTRA crashkernel=384M-2G:64M,2G-:128M"
 fi
 
+if [ "x${LINUX_ROOT_FS}" = xzfs ]; then
+  GRUB_CMDLINE_LINUX="boot=zfs \$bootfs ${GRUB_CMDLINE_LINUX}"
+fi
+
 linux_entry ()
 {
   os="$1"
@@ -114,6 +120,12 @@
     fi
     printf '%s\n' "${prepare_boot_cache}"
   fi
+  if [ "x${LINUX_ROOT_FS}" = xzfs ]; then
+    cat << EOF
+	insmod zfsinfo
+	zfs-bootfs (\$root) bootfs
+EOF
+  fi
   if [ "x$5" != "xquiet" ]; then
     message="$(gettext_printf "Loading Linux %s ..." ${version})"
     cat << EOF
Index: grub/util/getroot.c
===================================================================
--- grub.orig/util/getroot.c	2012-01-24 23:44:04.105772000 -0600
+++ grub/util/getroot.c	2012-01-27 20:48:50.875006000 -0600
@@ -52,6 +52,8 @@
 #endif
 
 #ifdef __linux__
+# include <stdio.h>
+# include <mntent.h>
 # include <sys/types.h>
 # include <sys/wait.h>
 #endif
@@ -115,6 +117,8 @@
   return path;
 }
 
+static char *find_device_from_pool (const char *poolname);
+
 #ifdef __linux__
 
 #define ESCAPED_PATH_MAX (4 * PATH_MAX)
@@ -263,7 +267,32 @@
       if (!*entries[i].device)
 	continue;
 
-      ret = strdup (entries[i].device);
+      if (strcmp (entries[i].fstype, "zfs") == 0)
+	{
+	  char *poolname = entries[i].device;
+	  char *poolname_i = poolname;
+	  char *poolname_j = poolname;
+	  /* Replace \040 with a space.  Cut at the first slash. */
+	  while (*poolname_j)
+	    {
+	      if (*poolname_j == '/')
+		break;
+	      if (strncmp (poolname_j, "\\040", 4) == 0)
+		{
+		  *poolname_i = ' ';
+		  poolname_i++;
+		  poolname_j += 4;
+		  continue;
+		}
+	      *poolname_i = *poolname_j;
+	      poolname_i++;
+	      poolname_j++;
+	    }
+	  *poolname_i = '\0';
+	  ret = find_device_from_pool (poolname);
+	}
+      else
+	ret = strdup (entries[i].device);
       if (relroot)
 	*relroot = strdup (entries[i].enc_root);
       break;
@@ -280,13 +309,25 @@
 static char *
 find_root_device_from_libzfs (const char *dir)
 {
-  char *device = NULL;
+  char *device;
   char *poolname;
   char *poolfs;
 
   grub_find_zpool_from_dir (dir, &poolname, &poolfs);
   if (! poolname)
     return NULL;
+  if (poolfs)
+    free (poolfs);
+
+  device = find_device_from_pool(poolname);
+  free(poolname);
+  return device;
+}
+
+static char *
+find_device_from_pool (const char *poolname)
+{
+  char *device = NULL;
 
 #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
   {
@@ -357,7 +398,7 @@
     char cksum[257], notes[257];
     unsigned int dummy;
 
-    cmd = xasprintf ("zpool status %s", poolname);
+    cmd = xasprintf ("zpool status \"%s\"", poolname);
     fp = popen (cmd, "r");
     free (cmd);
 
@@ -382,7 +423,10 @@
 		st++;
 	      break;
 	    case 1:
-	      if (!strcmp (name, poolname))
+	      /* Use strncmp() because poolname can technically have trailing
+	         spaces, which the sscanf() above will not catch.  Since we've
+	         asked about this pool specifically, this should be safe. */
+	      if (!strncmp (name, poolname, strlen(name)))
 		st++;
 	      break;
 	    case 2:
@@ -395,17 +439,71 @@
 	
 	free (line);
       }
+
+#ifdef __linux__
+    /* The name returned by zpool isn't necessarily directly under /dev. */
+    {
+      const char *disk_naming_schemes[] = {
+	"/dev/disk/by-id/%s",
+	"/dev/disk/by-path/%s",
+	"/dev/disk/by-uuid/%s",
+	"/dev/disk/by-partuuid/%s",
+	"/dev/disk/by-label/%s",
+	"/dev/disk/by-partlabel/%s",
+	"/dev/%s",
+	NULL
+      };
+      const char **disk_naming_scheme = disk_naming_schemes;
+
+      for (; *disk_naming_scheme ; disk_naming_scheme++)
+	{
+	  struct stat sb;
+	  device = xasprintf (*disk_naming_scheme, name);
+	  if (stat (device, &sb) == 0)
+	    {
+	      char *real_device;
+	      const char *c;
+	      char *first_partition;
+
+	      /* Resolve the symlink to something like /dev/sda. */
+	      real_device = realpath (device, NULL);
+	      free (device);
+
+	      /* It ends in a number; assume it's a partition and stop. */
+	      for (c = real_device ; *(c+1) ; c++);
+	      if (*c >= '0' && *c <= '9')
+		{
+		  device = real_device;
+		  break;
+		}
+
+	      /* Otherwise, it might be a partitioned wholedisk vdev. */
+	      first_partition = xasprintf ("%s1", real_device);
+	      if (stat (first_partition, &sb) == 0)
+		{
+		  free (real_device);
+		  device = first_partition;
+		  break;
+		}
+
+	      /* The device is not partitioned. */
+	      free (device);
+	      device = real_device;
+	      break;
+	    }
+	  free (device);
+	  device = NULL;
+	}
+    }
+#else
     device = xasprintf ("/dev/%s", name);
+#endif /* !__linux__ */
 
  fail:
     pclose (fp);
   }
 #endif
 
-  free (poolname);
-  if (poolfs)
-    free (poolfs);
-
   return device;
 }
 
@@ -708,10 +806,10 @@
 #ifdef __linux__
   if (!os_dev)
     os_dev = grub_find_root_device_from_mountinfo (dir, NULL);
-#endif /* __linux__ */
-
+#else
   if (!os_dev)
     os_dev = find_root_device_from_libzfs (dir);
+#endif /* !__linux__ */
 
   if (os_dev)
     {
@@ -1484,6 +1582,37 @@
 	    break;
 	  }
       }
+
+    fclose (mnttab);
+  }
+#elif defined(__linux__)
+  {
+    struct stat st;
+    struct mntent *mnt;
+    FILE *mnttab;
+
+    if (stat (dir, &st) != 0)
+      return;
+
+    mnttab = fopen ("/proc/mounts", "r");
+    if (! mnttab)
+      mnttab = fopen ("/etc/mtab", "r");
+    if (! mnttab)
+      return;
+
+    while ((mnt = getmntent (mnttab)) != NULL)
+      {
+	struct stat mnt_st;
+	if (strcmp (mnt->mnt_type, "zfs") != 0)
+	  continue;
+	if (stat (mnt->mnt_dir, &mnt_st) != 0)
+	  continue;
+	if (mnt_st.st_dev == st.st_dev)
+	  {
+	    *poolname = xstrdup (mnt->mnt_fsname);
+	    break;
+	  }
+      }
 
     fclose (mnttab);
   }

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

  parent reply	other threads:[~2012-01-28  2:50 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-19 18:45 [Patch] Robustly search for ZFS labels & uberblocks Zachary Bedell
2011-09-28 21:20 ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-19 11:36   ` Richard Laager
2012-01-22 14:18     ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-22 20:31       ` Richard Laager
2012-01-24  7:12       ` Richard Laager
2012-01-27 19:04       ` Zachary Bedell
2012-01-27 22:22         ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-28  2:50         ` Richard Laager [this message]
2012-01-28 12:51           ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-28 16:50             ` Richard Laager
2012-01-28 17:06               ` Darik Horn
2012-01-28 17:39                 ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-28 18:33             ` Richard Laager
2012-01-28 19:21               ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-29 22:42               ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-31  8:45                 ` Richard Laager
2012-02-02 11:13                   ` Richard Laager
2012-02-03 10:02                     ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-02-03  9:52                   ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-02-03 11:20                     ` Richard Laager
2012-01-28 18:40             ` Darik Horn
2012-01-28 19:27               ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-30  1:22             ` Richard Laager
2012-01-30  1:43               ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-11-03 14:45 ` Vladimir 'φ-coder/phcoder' Serbinenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1327719035.9477.68.camel@watermelon.coderich.net \
    --to=rlaager@wiktel.com \
    --cc=grub-devel@gnu.org \
    --cc=pendorbound@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).