All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.