All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kasper Brink <K.Brink@cs.ru.nl>
To: xen-devel@lists.xensource.com
Subject: pv-grub Solaris support
Date: Wed, 12 Oct 2011 22:40:11 +0200	[thread overview]
Message-ID: <20111012204011.GA7518@lilo2.science.ru.nl> (raw)

[-- Attachment #1: Type: text/plain, Size: 1373 bytes --]

Hello all,

I've patched pv-grub to allow it to boot a Solaris PV domU using an
unmodified menu.lst. The attached patch has been tested with various
Solaris versions (Solaris 11 Express, OpenIndiana 151a, OpenSolaris 134,
Nexenta Core 3.0.1; all 64-bit). I appreciate your feedback.

The patch consists mainly of Oracle's grub modifications, which add ZFS
support and Solaris-specific builtins (findroot, bootfs, kernel$, and
module$). I took the relevant code from the "Oracle Solaris 11 Express
2010.11 GPL Source, Part 2" package, downloaded from: 
  http://dlc.sun.com/opensourcecode/solaris/sol-11-exp-201011-GPLSource_2.zip
The kernel$ and module$ builtins were modified to boot Xen PV Solaris
kernels.

The patch is against current xen-unstable. I built and tested pv-grub under 
Xen version 4.0.1 (Debian 4.0.1-2) amd64, with a Linux 2.6.32-5-xen-amd64
(Debian Squeeze) dom0. The location of menu.lst in the domU was specified
with the "extra" variable (e.g. extra="(hd0,0,a)/boot/grub/menu.lst").

Note: I had to create a symlink "xen/include/xen/libelf -> ." (not in the
patch) to build stubdom/libxc-x86_64 succesfully. Is this a bug, or is
there something wrong in my setup?

If you think this code is useful for other users, I'd be happy to see it
included in the Xen repository. Please let me know if there's anything that
needs to be changed.

Best,

Kasper

[-- Attachment #2: pv-grub_solaris.patch --]
[-- Type: text/plain, Size: 150520 bytes --]

diff -r 4b0907c6a08c stubdom/grub.patches/60zfs_solaris.diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stubdom/grub.patches/60zfs_solaris.diff	Wed Oct 12 20:06:15 2011 +0200
@@ -0,0 +1,4793 @@
+This patch adds ZFS support, and the Solaris-specific builtins findroot, bootfs,
+kernel$, and module$, to pv-grub.
+
+It includes the relevant parts of Oracle's changes to grub-0.97, which were
+taken from the "osnet/src/grub-0.97" directory in the "Oracle Solaris 11
+Express 2010.11 GPL Source, Part 2" archive, downloaded from:
+  http://dlc.sun.com/opensourcecode/solaris/sol-11-exp-201011-GPLSource_2.zip
+
+The kernel$ and module$ builtins were modified to boot Xen PV Solaris kernels.
+
+    2011-10-12  Kasper Brink  <K.Brink@cs.ru.nl>
+
+
+diff -urN grub.patch50/AUTHORS grub.zfs_solaris/AUTHORS
+--- grub.patch50/AUTHORS	2011-10-12 19:58:28.795922895 +0200
++++ grub.zfs_solaris/AUTHORS	2011-10-12 19:58:28.951921541 +0200
+@@ -1,7 +1,16 @@
++
++ZFS support added by Sun Microsystems.
++Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++Use is subject to license terms.
++
+ VaX#n8 (real name unknown) wrote shared_src/fsys_ext2fs.c.
+ 
+ Heiko Schroeder rewrote shared_src/stage1.S to be more readable.
+ 
++Solaris VTOC and UFS support added by Sun Microsystems.
++Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
++Use is subject to license terms.
++
+ The following authors assigned copyright on their work to the Free
+ Software Foundation:
+ 
+diff -urN grub.patch50/stage2/builtins.c grub.zfs_solaris/stage2/builtins.c
+--- grub.patch50/stage2/builtins.c	2011-10-12 19:58:28.871922077 +0200
++++ grub.zfs_solaris/stage2/builtins.c	2011-10-12 19:58:29.027921196 +0200
+@@ -109,6 +109,12 @@
+   fallback_entryno = -1;
+   fallback_entries[0] = -1;
+   grub_timeout = -1;
++  current_rootpool[0] = '\0';
++  current_bootfs[0] = '\0';
++  current_bootpath[0] = '\0';
++  current_bootfs_obj = 0;
++  current_devid[0] = '\0';
++  is_zfs_mount = 0;
+ }
+ 
+ /* Check a password for correctness.  Returns 0 if password was
+@@ -1467,16 +1473,56 @@
+ };
+ 
+ \f

+-/* find */
+-/* Search for the filename ARG in all of partitions.  */
++
++void
++set_root (char *root, unsigned long drive, unsigned long part)
++{
++  int bsd_part = (part >> 8) & 0xFF;
++  int pc_slice = part >> 16;
++
++  if (bsd_part == 0xFF) {
++    grub_sprintf (root, "(hd%d,%d)\n", drive - 0x80, pc_slice);
++  } else {
++    grub_sprintf (root, "(hd%d,%d,%c)\n",
++		 drive - 0x80, pc_slice, bsd_part + 'a');
++  }
++}
++
+ static int
+-find_func (char *arg, int flags)
++find_common (char *arg, char *root, int for_root, int flags)
+ {
+-  char *filename = arg;
++  char *filename = NULL;
++  static char argpart[32];
++  static char device[32];
++  char *tmp_argpart = NULL;
+   unsigned long drive;
+   unsigned long tmp_drive = saved_drive;
+   unsigned long tmp_partition = saved_partition;
+   int got_file = 0;
++  static char bootsign[BOOTSIGN_LEN];
++
++  /*
++   * If argument has partition information (findroot command only), then
++   * it can't be a floppy
++   */
++  if (for_root && arg[0] == '(') {
++	tmp_argpart = grub_strchr(arg + 1, ',');
++        if (tmp_argpart == NULL)
++		goto out;
++	grub_strcpy(argpart, tmp_argpart);
++	*tmp_argpart = '\0';
++	arg++;
++        grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
++	filename = bootsign;
++	goto harddisk;
++  } else if (for_root && !grub_strchr(arg, '/')) {
++	/* Boot signature without partition/slice information */
++        grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
++	filename = bootsign;
++  } else {
++	/* plain vanilla find cmd */
++	filename = arg;
++  }
+   
+   /* Floppies.  */
+   for (drive = 0; drive < 8; drive++)
+@@ -1491,14 +1537,19 @@
+ 	  if (grub_open (filename))
+ 	    {
+ 	      grub_close ();
+-	      grub_printf (" (fd%d)\n", drive);
+ 	      got_file = 1;
++	      if (for_root) {
++		 grub_sprintf(root, "(fd%d)", drive);
++		 goto out;
++	      } else
++	         grub_printf (" (fd%d)\n", drive);
+ 	    }
+ 	}
+ 
+       errnum = ERR_NONE;
+     }
+ 
++harddisk:
+   /* Hard disks.  */
+   for (drive = 0x80; drive < 0x88; drive++)
+     {
+@@ -1507,6 +1558,30 @@
+       int type, entry;
+       char buf[SECTOR_SIZE];
+ 
++      if (for_root && tmp_argpart) {
++	grub_sprintf(device, "(hd%d%s", drive - 0x80, argpart);
++	set_device(device);
++        errnum = ERR_NONE;
++	part = current_partition;
++	if (open_device ()) {
++	   saved_drive = current_drive;
++	   saved_partition = current_partition;
++           errnum = ERR_NONE;
++	   if (grub_open (filename)) {
++	      grub_close ();
++	      got_file = 1;
++	      if (is_zfs_mount == 0) {
++	        set_root(root, current_drive, current_partition);
++	        goto out;
++	      } else {
++		best_drive = current_drive;
++		best_part = current_partition;
++	      }
++           }
++	}
++        errnum = ERR_NONE;
++	continue;
++      }
+       current_drive = drive;
+       while (next_partition (drive, 0xFFFFFF, &part, &type,
+ 			     &start, &len, &offset, &entry,
+@@ -1523,19 +1598,22 @@
+ 		  saved_partition = current_partition;
+ 		  if (grub_open (filename))
+ 		    {
+-		      int bsd_part = (part >> 8) & 0xFF;
+-		      int pc_slice = part >> 16;
+-		      
+-		      grub_close ();
+-		      
+-		      if (bsd_part == 0xFF)
+-			grub_printf (" (hd%d,%d)\n",
+-				     drive - 0x80, pc_slice);
+-		      else
+-			grub_printf (" (hd%d,%d,%c)\n",
+-				     drive - 0x80, pc_slice, bsd_part + 'a');
++		      char tmproot[32];
+ 
++		      grub_close ();
+ 		      got_file = 1;
++		      set_root(tmproot, drive, part);
++		      if (for_root) {
++		 	grub_memcpy(root, tmproot, sizeof(tmproot));
++			if (is_zfs_mount == 0) {
++			      goto out;
++			} else {
++			      best_drive = current_drive;
++			      best_part = current_partition;
++			}
++		      } else {
++			grub_printf("%s", tmproot);
++		      }
+ 		    }
+ 		}
+ 	    }
+@@ -1549,8 +1627,16 @@
+       errnum = ERR_NONE;
+     }
+ 
+-  saved_drive = tmp_drive;
+-  saved_partition = tmp_partition;
++out:
++  if (is_zfs_mount && for_root) {
++        set_root(root, best_drive, best_part);
++	buf_drive = -1;
++  } else {
++	saved_drive = tmp_drive;
++	saved_partition = tmp_partition;
++  }
++  if (tmp_argpart)
++	*tmp_argpart = ',';
+ 
+   if (got_file)
+     {
+@@ -1562,6 +1648,14 @@
+   return 1;
+ }
+ 
++/* find */
++/* Search for the filename ARG in all of partitions.  */
++static int
++find_func (char *arg, int flags)
++{
++	return (find_common(arg, NULL, 0, flags));
++}
++
+ static struct builtin builtin_find =
+ {
+   "find",
+@@ -2619,6 +2713,117 @@
+ 
+ 
+ \f

++/*
++ * To boot from a ZFS root filesystem, the kernel$ or module$ commands
++ * must include "-B $ZFS-BOOTFS" to expand to the zfs-bootfs, bootpath,
++ * and diskdevid boot property values for passing to the kernel:
++ *
++ * e.g.
++ * kernel$ /platform/i86pc/kernel/$ISADIR/unix -B $ZFS-BOOTFS,console=ttya
++ *
++ * $ZFS-BOOTFS is expanded to
++ *
++ *    zfs-bootfs=<rootpool-name/zfs-rootfilesystem-object-num>,
++ *    bootpath=<device phys path>,
++ *    diskdevid=<device id>
++ *
++ * if both bootpath and diskdevid can be found.
++ * e.g
++ *    zfs-bootfs=rpool/85,
++ *    bootpath="/pci@0,0/pci1022,7450@a/pci17c2,10@4/sd@0,0:a",
++ *    diskdevid="id1,sd@SSEAGATE_ST336607LC______3JA0LNHE0000741326W6/a"
++ */
++static int
++expand_dollar_bootfs(char *in, char *out)
++{
++	char *token, *tmpout = out;
++	int outlen, blen;
++	int postcomma = 0;
++
++	/* no op if this is not zfs */
++	if (is_zfs_mount == 0)
++		return (0);
++
++	if (current_bootpath[0] == '\0' && current_devid[0] == '\0') {
++		errnum = ERR_NO_BOOTPATH;
++		return (1);
++	}
++
++	outlen = strlen(in);
++	blen = current_bootfs_obj == 0 ? strlen(current_rootpool) :
++	    strlen(current_rootpool) + 11;
++
++	out[0] = '\0';
++	while (token = strstr(in, "$ZFS-BOOTFS")) {
++
++		if ((outlen += blen) >= MAX_CMDLINE) {
++			errnum = ERR_WONT_FIT;
++			return (1);
++		}
++
++		token[0] = '\0';	
++		grub_sprintf(tmpout, "%s", in);
++		token[0] = '$';
++		in = token + 11; /* skip over $ZFS-BOOTFS */
++		tmpout = out + strlen(out);
++
++		/* Note: %u only fits 32 bit integer; */ 
++		if (current_bootfs_obj > 0)
++			grub_sprintf(tmpout, "zfs-bootfs=%s/%u",
++			    current_rootpool, current_bootfs_obj);
++		else
++			grub_sprintf(tmpout, "zfs-bootfs=%s",
++			    current_rootpool);
++		tmpout = out + strlen(out); 
++	}
++
++	/*
++	 * Check to see if 'zfs-bootfs' was explicitly specified on the command
++	 * line so that we can insert the 'bootpath' property.
++	 */
++	if ((tmpout == out) && (token = strstr(in, "zfs-bootfs")) != NULL) {
++		token[0] = '\0';
++		grub_strcpy(tmpout, in);
++		token[0] = 'z';
++		in = token;
++
++		tmpout = out + strlen(out);
++		postcomma = 1;
++	}
++
++	/*
++	 * Set the 'bootpath' property if a ZFS dataset was specified, either
++	 * through '$ZFS-BOOTFS' or an explicit 'zfs-bootfs' setting.
++	 */
++	if (tmpout != out) {
++		if (current_bootpath[0] != '\0') {
++			if ((outlen += 12 + strlen(current_bootpath))
++			    >= MAX_CMDLINE) {
++				errnum = ERR_WONT_FIT;
++				return (1);
++			}
++			grub_sprintf(tmpout,
++			    postcomma ? "bootpath=\"%s\"," : ",bootpath=\"%s\"",
++			    current_bootpath);
++			tmpout = out + strlen(out);
++		}
++
++		if (current_devid[0] != '\0') {
++			if ((outlen += 13 + strlen(current_devid))
++			    >= MAX_CMDLINE) {
++				errnum = ERR_WONT_FIT;
++				return (1);
++			}
++			grub_sprintf(tmpout,
++			    postcomma ? "diskdevid=\"%s\"," : ",diskdevid=\"%s\"",
++			    current_devid);
++		}
++	}
++
++	strncat(out, in, MAX_CMDLINE);
++	return (0);
++}
++
+ /* kernel */
+ static int
+ kernel_func (char *arg, int flags)
+@@ -2707,6 +2912,141 @@
+   " Linux's mem option automatically."
+ };
+ 
++int
++isamd64()
++{
++	static int ret = 0;
++
++#ifdef __x86_64__
++    ret = 1;
++#endif
++
++	return (ret);
++}
++
++static void
++expand_arch (char *arg, char *newarg)
++{
++  char *index;
++
++  newarg[0] = '\0';
++
++  while ((index = strstr(arg, "$ISADIR")) != NULL) {
++
++    index[0] = '\0';
++    strncat(newarg, arg, MAX_CMDLINE);
++    index[0] = '$';
++
++    if (isamd64())
++      strncat(newarg, "amd64", MAX_CMDLINE);
++
++    arg = index + 7;
++  }
++
++  strncat(newarg, arg, MAX_CMDLINE);
++  return;
++}
++
++static int
++substitute_platform_i86xpv (char *arg, char *newarg)
++{
++  char *index;
++
++  newarg[0] = '\0';
++
++  while ((index = strstr(arg, "i86pc")) != NULL) {
++
++    index[0] = '\0';
++    if (!strncat(newarg, arg, MAX_CMDLINE)
++        || !strncat(newarg, "i86xpv", MAX_CMDLINE)) {
++      errnum = ERR_WONT_FIT;
++      return (1);
++    }
++    index[0] = 'i';
++
++    arg = index + 5;  /* length of "i86pc" */
++  }
++
++  if (!strncat(newarg, arg, MAX_CMDLINE)) {
++    errnum = ERR_WONT_FIT;
++    return (1);
++  }
++
++  return (0);
++}
++
++/* kernel$ */
++static int
++kernel_dollar_func (char *arg, int flags)
++{
++  char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
++#ifdef __MINIOS__
++  char tmparg[MAX_CMDLINE];	
++#endif
++
++  grub_printf("loading '%s' ...\n", arg);
++  expand_arch(arg, newarg);
++
++#ifdef __MINIOS__
++  /* replace "i86pc" by "i86xpv" in the kernel filename,
++     to enable pv-grub to use an unmodified menu.lst */
++  if (substitute_platform_i86xpv(newarg,tmparg))
++      return (1);
++
++  /* on ZFS, grub_open the kernel to set the value of current_bootfs_obj */
++  grub_strcpy(newarg,tmparg);
++  nul_terminate(newarg);
++  if (is_zfs_mount) {
++      if (!grub_open(newarg))
++          return (1);
++      grub_close();
++  }
++
++  /* the kernel filename is duplicated as the first argument to the kernel */
++  if (!strncat(newarg, " ", MAX_CMDLINE)
++      || !strncat(newarg, tmparg, MAX_CMDLINE)) {
++      errnum = ERR_WONT_FIT;
++      return (1);
++  }
++
++  grub_strcpy(tmparg,newarg);
++  if (expand_dollar_bootfs(tmparg, newarg)) {
++      grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
++          current_bootfs);
++      return (1);
++  }
++
++  if (kernel_func(newarg, flags))
++      return (1);
++
++  grub_printf("'%s' is loaded\n", newarg);
++#else  /* ! __MINIOS__ */
++  if (kernel_func(newarg, flags))
++	return (1);
++
++  mb_cmdline = (char *)MB_CMDLINE_BUF;
++  if (expand_dollar_bootfs(newarg, mb_cmdline)) {
++	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
++	    current_bootfs);
++	return (1);
++  }
++
++  grub_printf("'%s' is loaded\n", mb_cmdline);
++  mb_cmdline += grub_strlen(mb_cmdline) + 1;
++#endif /* ! __MINIOS__ */
++
++  return (0);
++}
++
++static struct builtin builtin_kernel_dollar =
++{
++  "kernel$",
++  kernel_dollar_func,
++  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "kernel$ [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
++  " Just like kernel, but with $ISADIR expansion."
++};
++
+ \f

+ /* lock */
+ static int
+@@ -2922,6 +3262,50 @@
+   " the `kernel' command."
+ };
+ 
++/* module$ */
++static int
++module_dollar_func (char *arg, int flags)
++{
++  char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
++  char *cmdline_sav;
++
++  grub_printf("loading '%s' ...\n", arg);
++  expand_arch(arg, newarg);
++
++/* Xen PV Solaris kernels ("i86xpv") are not Multiboot-compliant, and expect
++   to receive the boot archive as a Linux-style initial ramdisk. */
++#ifdef __MINIOS__
++  if (initrd_func(newarg, flags))
++	return (1);
++
++  grub_printf("'%s' is loaded\n", newarg);
++#else /* ! __MINIOS__ */
++  cmdline_sav = (char *)mb_cmdline;
++  if (module_func(newarg, flags))
++	return (1);
++
++  if (expand_dollar_bootfs(newarg, cmdline_sav)) {
++	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
++	    current_bootfs);
++	return (1);
++  }
++
++  grub_printf("'%s' is loaded\n", (char *)cmdline_sav);
++  mb_cmdline += grub_strlen(cmdline_sav) + 1;
++#endif /* ! __MINIOS__ */
++
++  return (0);
++}
++
++static struct builtin builtin_module_dollar =
++{
++  "module$",
++  module_dollar_func,
++  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "module FILE [ARG ...]",
++  " Just like module, but with $ISADIR expansion."
++};
++
+ \f

+ /* modulenounzip */
+ static int
+@@ -3469,6 +3853,7 @@
+ static int
+ root_func (char *arg, int flags)
+ {
++  is_zfs_mount = 0;
+   return real_root_func (arg, 1);
+ }
+ 
+@@ -3491,6 +3876,101 @@
+ };
+ 
+ \f

++/* findroot */
++int
++findroot_func (char *arg, int flags)
++{
++  int ret;
++  char root[32];
++
++  if (grub_strlen(arg) >= BOOTSIGN_ARGLEN) {
++  	errnum = ERR_BAD_ARGUMENT;
++	return 1;
++  }
++
++  if (arg[0] == '\0') {
++  	errnum = ERR_BAD_ARGUMENT;
++	return 1;
++  }
++
++  find_best_root = 1;
++  best_drive = 0;
++  best_part = 0;
++  ret = find_common(arg, root, 1, flags);
++  if (ret != 0)
++	return (ret);
++  find_best_root = 0;
++
++  return real_root_func (root, 1);
++}
++
++static struct builtin builtin_findroot =
++{
++  "findroot",
++  findroot_func,
++  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "findroot  <SIGNATURE | (SIGNATURE,partition[,slice])>",
++  "Searches across all partitions for the file name SIGNATURE."
++  " GRUB looks only in the directory /boot/grub/bootsign for the"
++  " filename and it stops as soon as it finds the first instance of"
++  " the file - so to be useful the name of the signature file must be"
++  " unique across all partitions. Once the signature file is found,"
++  " GRUB invokes the \"root\" command on that partition."
++  " An optional partition and slice may be specified to optimize the search."
++};
++
++\f

++/*
++ * COMMAND to override the default root filesystem for ZFS
++ *	bootfs pool/fs
++ */
++static int
++bootfs_func (char *arg, int flags)
++{
++	int hdbias = 0;
++	char *biasptr;
++	char *next;
++
++	if (! *arg) {
++	    if (current_bootfs[0] != '\0')
++		grub_printf ("The zfs boot filesystem is set to '%s'.\n",
++				current_bootfs);
++	    else if (current_rootpool[0] != 0 && current_bootfs_obj != 0)
++		grub_printf("The zfs boot filesystem is <default: %s/%u>.",
++				current_rootpool, current_bootfs_obj);
++	    else
++		grub_printf ("The zfs boot filesystem will be derived from "
++			"the default bootfs pool property.\n");
++
++	    return (1);
++	}
++
++	/* Verify the zfs filesystem name */
++	if (arg[0] == '/' || arg[0] == '\0') {
++		errnum = ERR_BAD_ARGUMENT;
++		return 0;
++	}
++	if (current_rootpool[0] != 0 && grub_strncmp(arg,
++	    current_rootpool, strlen(current_rootpool))) {
++		errnum = ERR_BAD_ARGUMENT;
++		return 0;
++	}
++
++	grub_memmove(current_bootfs, arg, MAXNAMELEN);
++
++	return (1);
++}
++
++static struct builtin builtin_bootfs =
++{
++  "bootfs",
++  bootfs_func,
++  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "bootfs [ZFSBOOTFS]",
++  "Set the current zfs boot filesystem to ZFSBOOTFS (rootpool/rootfs)."
++};
++
++\f

+ /* rootnoverify */
+ static int
+ rootnoverify_func (char *arg, int flags)
+@@ -3630,6 +4110,11 @@
+   int saved_offsets[2];
+   int saved_lengths[2];
+ 
++  /* not supported for zfs root */
++  if (is_zfs_mount == 1) {
++	return (0); /* no-op */
++  }
++
+   /* Save sector information about at most two sectors.  */
+   auto void disk_read_savesect_func (int sector, int offset, int length);
+   void disk_read_savesect_func (int sector, int offset, int length)
+@@ -5213,6 +5698,7 @@
+ #endif
+   &builtin_blocklist,
+   &builtin_boot,
++  &builtin_bootfs,
+ #ifdef SUPPORT_NETBOOT
+   &builtin_bootp,
+ #endif /* SUPPORT_NETBOOT */
+@@ -5241,6 +5727,7 @@
+   &builtin_embed,
+   &builtin_fallback,
+   &builtin_find,
++  &builtin_findroot,
+ #ifdef SUPPORT_GRAPHICS
+   &builtin_foreground,
+ #endif
+@@ -5258,6 +5745,7 @@
+   &builtin_install,
+   &builtin_ioprobe,
+   &builtin_kernel,
++  &builtin_kernel_dollar,
+   &builtin_lock,
+   &builtin_makeactive,
+   &builtin_map,
+@@ -5265,6 +5753,7 @@
+   &builtin_md5crypt,
+ #endif /* USE_MD5_PASSWORDS */
+   &builtin_module,
++  &builtin_module_dollar,
+   &builtin_modulenounzip,
+   &builtin_pager,
+   &builtin_partnew,
+diff -urN grub.patch50/stage2/char_io.c grub.zfs_solaris/stage2/char_io.c
+--- grub.patch50/stage2/char_io.c	2011-10-12 19:58:28.871922077 +0200
++++ grub.zfs_solaris/stage2/char_io.c	2011-10-12 19:58:29.027921196 +0200
+@@ -17,6 +17,10 @@
+  *  along with this program; if not, write to the Free Software
+  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++/*
++ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
+ 
+ #include <shared.h>
+ #include <term.h>
+@@ -217,7 +221,7 @@
+     }
+ }
+ 
+-#ifndef STAGE1_5
++#if !defined(STAGE1_5) || defined(FSYS_ZFS)
+ int
+ grub_sprintf (char *buffer, const char *format, ...)
+ {
+@@ -261,8 +265,10 @@
+   *bp = 0;
+   return bp - buffer;
+ }
++#endif /* !defined(STAGE1_5) || defined(FSYS_ZFS) */
+ 
+ 
++#ifndef STAGE1_5
+ void
+ init_page (void)
+ {
+@@ -1013,7 +1019,10 @@
+    a static library supporting minimal standard C functions and link
+    each image with the library. Complicated things should be left to
+    computer, definitely. -okuji  */
+-#if !defined(STAGE1_5) || defined(FSYS_VSTAFS)
++
++/* Make some grub_str* routines available to ZFS plug-in as well */
++
++#if !defined(STAGE1_5) || defined(FSYS_VSTAFS) || defined(FSYS_ZFS)
+ int
+ grub_strcmp (const char *s1, const char *s2)
+ {
+@@ -1029,7 +1038,20 @@
+ 
+   return 0;
+ }
+-#endif /* ! STAGE1_5 || FSYS_VSTAFS */
++
++int
++grub_strncmp(const char *s1, const char *s2, int n)
++{
++        if (s1 == s2)
++                return (0);
++        n++;
++        while (--n != 0 && *s1 == *s2++)
++                if (*s1++ == '\0')
++                        return (0);
++        return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2);
++}
++
++#endif /* ! STAGE1_5 || FSYS_VSTAFS || defined(FSYS_ZFS) */
+ 
+ #ifndef STAGE1_5
+ /* Wait for a keypress and return its code.  */
+@@ -1195,7 +1217,9 @@
+   *str = 0;
+   return ch;
+ }
++#endif
+ 
++#if !defined(STAGE1_5) || defined(FSYS_ZFS)
+ char *
+ grub_strstr (const char *s1, const char *s2)
+ {
+@@ -1228,6 +1252,16 @@
+ 
+   return len;
+ }
++#endif /* !defined(STAGE1_5) || defined(FSYS_ZFS) */
++
++#ifndef STAGE1_5
++char *
++grub_strchr (char *str, char c)
++{
++  for (; *str && (*str != c); str++);
++
++  return (*str ? str : NULL);
++}
+ #endif /* ! STAGE1_5 */
+ 
+ int
+diff -urN grub.patch50/stage2/common.c grub.zfs_solaris/stage2/common.c
+--- grub.patch50/stage2/common.c	2011-10-12 19:58:28.871922077 +0200
++++ grub.zfs_solaris/stage2/common.c	2011-10-12 19:58:29.027921196 +0200
+@@ -88,6 +88,10 @@
+   [ERR_UNRECOGNIZED] = "Unrecognized command",
+   [ERR_WONT_FIT] = "Selected item cannot fit into memory",
+   [ERR_WRITE] = "Disk write error",
++  [ERR_FILESYSTEM_NOT_FOUND] = "File System not found",
++    /* this zfs file system is not found in the pool of the device */
++  [ERR_NO_BOOTPATH] = "No valid boot path found in the zfs label. This may be caused by attempting to boot from an off-lined device.",
++  [ERR_NEWER_VERSION] = "Newer on-disk pool version",
+ };
+ 
+ 
+diff -urN grub.patch50/stage2/disk_io.c grub.zfs_solaris/stage2/disk_io.c
+--- grub.patch50/stage2/disk_io.c	2011-10-12 19:58:28.875921314 +0200
++++ grub.zfs_solaris/stage2/disk_io.c	2011-10-12 19:58:29.031921885 +0200
+@@ -75,6 +75,9 @@
+ # ifdef FSYS_UFS2
+   {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed},
+ # endif
++# ifdef FSYS_ZFS
++  {"zfs", zfs_mount, zfs_read, zfs_open, 0, zfs_embed},
++# endif
+ # ifdef FSYS_ISO9660
+   {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
+ # endif
+@@ -118,6 +121,17 @@
+ 
+ int current_slice;
+ 
++/* ZFS root filesystem for booting */
++char current_rootpool[MAXNAMELEN];
++char current_bootfs[MAXNAMELEN];
++unsigned long long current_bootfs_obj;
++char current_bootpath[MAXPATHLEN];
++char current_devid[MAXPATHLEN];
++int is_zfs_mount;
++unsigned long best_drive;
++unsigned long best_part;
++int find_best_root;
++
+ /* disk buffer parameters */
+ int buf_drive = -1;
+ int buf_track;
+@@ -404,7 +418,7 @@
+ 	  || current_drive == cdrom_drive)
+       && (current_partition & 0xFF) == 0xFF
+       && ((current_partition & 0xFF00) == 0xFF00
+-	  || (current_partition & 0xFF00) < 0x800)
++	  || (current_partition & 0xFF00) < 0x1000)
+       && ((current_partition >> 16) == 0xFF
+ 	  || (current_drive & 0x80)))
+     return 1;
+@@ -581,6 +595,7 @@
+ {
+   /* Forward declarations.  */
+   auto int next_bsd_partition (void);
++  auto int next_solaris_partition(void);
+   auto int next_pc_slice (void);
+ 
+   /* Get next BSD partition in current PC slice.  */
+@@ -640,6 +655,56 @@
+       return 0;
+     }
+ 
++  /* Get next Solaris partition in current PC slice.  */
++  int next_solaris_partition (void)
++    {
++      static unsigned long pcs_start;
++      int i;
++      int sol_part_no = (*partition & 0xFF00) >> 8;
++
++      /* If this is the first time...  */
++      if (sol_part_no == 0xFF)
++	{
++	  /* Check if the Solaris label is within current PC slice.  */
++	  if (*len < SOL_LABEL_LOC + 1)
++	    {
++	      errnum = ERR_BAD_PART_TABLE;
++	      return 0;
++	    }
++
++	  /* Read the Solaris label.  */
++	  if (! rawread (drive, *start + SOL_LABEL_LOC, 0, SECTOR_SIZE, buf))
++	    return 0;
++
++	  /* Check if it is valid.  */
++	  if (! SOL_LABEL_CHECK_MAG (buf))
++	    {
++	      errnum = ERR_BAD_PART_TABLE;
++	      return 0;
++	    }
++	  
++	  sol_part_no = -1;
++	  pcs_start = *start;	/* save the start of pc slice */
++	}
++
++      /* Search next valid Solaris partition.  */
++      for (i = sol_part_no + 1; i < SOL_LABEL_NPARTS; i++)
++	{
++	  if (SOL_PART_EXISTS (buf, i))
++	    {
++	      /* SOL_PART_START is relative to fdisk partition */
++	      *start = SOL_PART_START (buf, i) + pcs_start;
++	      *len = SOL_PART_LENGTH (buf, i);
++	      *partition = (*partition & 0xFF00FF) | (i << 8);
++
++	      return 1;
++	    }
++	}
++
++      errnum = ERR_NO_PART;
++      return 0;
++    }
++
+   /* Get next PC slice. Be careful of that this function may return
+      an empty PC slice (i.e. a partition whose type is zero) as well.  */
+   int next_pc_slice (void)
+@@ -717,6 +782,14 @@
+     return 0;
+ #endif
+ 
++  /* check for Solaris partition */
++  if (*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_SOLARIS (*type & 0xff))
++    {
++      if (next_solaris_partition ())
++	return 1;
++      errnum = ERR_NONE;
++    }
++
+   /* If previous partition is a BSD partition or a PC slice which
+      contains BSD partitions...  */
+   if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
+@@ -830,7 +903,8 @@
+ 		    grub_printf ("   Partition num: %d, ",
+ 				 current_partition >> 16);
+ 
+-		  if (! IS_PC_SLICE_TYPE_BSD (current_slice))
++		  if (! IS_PC_SLICE_TYPE_BSD (current_slice) &&
++		      ! IS_PC_SLICE_TYPE_SOLARIS (current_slice))
+ 		    check_and_print_mount ();
+ 		  else
+ 		    {
+@@ -844,17 +918,17 @@
+ 			  
+ 			  if (! got_part)
+ 			    {
+-			      grub_printf ("[BSD sub-partitions immediately follow]\n");
++			      grub_printf ("[BSD/SOLARIS sub-partitions immediately follow]\n");
+ 			      got_part = 1;
+ 			    }
+ 			  
+-			  grub_printf ("     BSD Partition num: \'%c\', ",
++			  grub_printf ("     BSD/SOLARIS Partition num: \'%c\', ",
+ 				       bsd_part + 'a');
+ 			  check_and_print_mount ();
+ 			}
+ 
+ 		      if (! got_part)
+-			grub_printf (" No BSD sub-partition found, partition type 0x%x\n",
++			grub_printf (" No BSD/SOLARIS sub-partition found, partition type 0x%x\n",
+ 				     saved_slice);
+ 		      
+ 		      if (errnum)
+@@ -880,7 +954,8 @@
+ 				      pc_slice, bsd_part + 'a');
+ 		      print_a_completion (str);
+ 		    }
+-		  else if (! IS_PC_SLICE_TYPE_BSD (current_slice))
++		  else if (! IS_PC_SLICE_TYPE_BSD (current_slice) &&
++		      ! IS_PC_SLICE_TYPE_SOLARIS (current_slice))
+ 		    {
+ 		      char str[8];
+ 		      
+@@ -1038,7 +1113,7 @@
+ 	}
+       else if (*device == ',')
+ 	{
+-	  /* Either an absolute PC or BSD partition. */
++	  /* Either an absolute PC, BSD, or Solaris partition. */
+ 	  disk_choice = 0;
+ 	  part_choice ++;
+ 	  device++;
+@@ -1061,13 +1136,13 @@
+ 	      if (*device == ',')
+ 		device++;
+ 	      
+-	      if (*device >= 'a' && *device <= 'h')
++	      if (*device >= 'a' && *device <= 'p')
+ 		{
+ 		  current_partition = (((*(device++) - 'a') << 8)
+ 				       | (current_partition & 0xFF00FF));
+ 		}
+ 	    }
+-	  else if (*device >= 'a' && *device <= 'h')
++	  else if (*device >= 'a' && *device <= 'p')
+ 	    {
+ 	      part_choice ++;
+ 	      current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF;
+diff -urN grub.patch50/stage2/filesys.h grub.zfs_solaris/stage2/filesys.h
+--- grub.patch50/stage2/filesys.h	2011-10-12 19:58:28.875921314 +0200
++++ grub.zfs_solaris/stage2/filesys.h	2011-10-12 19:58:29.031921885 +0200
+@@ -40,6 +40,16 @@
+ #define FSYS_UFS2_NUM 0
+ #endif
+ 
++#ifdef FSYS_ZFS
++#define FSYS_ZFS_NUM 1
++int zfs_mount (void);
++int zfs_read (char *buf, int len);
++int zfs_open (char *dirname);
++int zfs_embed (int *start_sector, int needed_sectors);
++#else
++#define FSYS_ZFS_NUM 0
++#endif
++
+ #ifdef FSYS_FAT
+ #define FSYS_FAT_NUM 1
+ int fat_mount (void);
+@@ -128,7 +138,7 @@
+ #define NUM_FSYS	\
+   (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM	\
+    + FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM	\
+-   + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
++   + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM + FSYS_ZFS_NUM)
+ #endif
+ 
+ /* defines for the block filesystem info area */
+diff -urN grub.patch50/stage2/fsys_zfs.c grub.zfs_solaris/stage2/fsys_zfs.c
+--- grub.patch50/stage2/fsys_zfs.c	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/fsys_zfs.c	2011-10-12 19:58:29.035921285 +0200
+@@ -0,0 +1,1545 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
++ */
++
++/*
++ * The zfs plug-in routines for GRUB are:
++ *
++ * zfs_mount() - locates a valid uberblock of the root pool and reads
++ *		in its MOS at the memory address MOS.
++ *
++ * zfs_open() - locates a plain file object by following the MOS
++ *		and places its dnode at the memory address DNODE.
++ *
++ * zfs_read() - read in the data blocks pointed by the DNODE.
++ *
++ * ZFS_SCRATCH is used as a working area.
++ *
++ * (memory addr)   MOS      DNODE	ZFS_SCRATCH
++ *		    |         |          |
++ *	    +-------V---------V----------V---------------+
++ *   memory |       | dnode   | dnode    |  scratch      |
++ *	    |       | 512B    | 512B     |  area         |
++ *	    +--------------------------------------------+
++ */
++
++#ifdef	FSYS_ZFS
++
++#include "shared.h"
++#include "filesys.h"
++#include "fsys_zfs.h"
++
++/* cache for a file block of the currently zfs_open()-ed file */
++static void *file_buf = NULL;
++static uint64_t file_start = 0;
++static uint64_t file_end = 0;
++
++/* cache for a dnode block */
++static dnode_phys_t *dnode_buf = NULL;
++static dnode_phys_t *dnode_mdn = NULL;
++static uint64_t dnode_start = 0;
++static uint64_t dnode_end = 0;
++
++static uint64_t pool_guid = 0;
++static uberblock_t current_uberblock;
++static char *stackbase;
++
++decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] =
++{
++	{"inherit", 0},			/* ZIO_COMPRESS_INHERIT */
++	{"on", lzjb_decompress}, 	/* ZIO_COMPRESS_ON */
++	{"off", 0},			/* ZIO_COMPRESS_OFF */
++	{"lzjb", lzjb_decompress},	/* ZIO_COMPRESS_LZJB */
++	{"empty", 0}			/* ZIO_COMPRESS_EMPTY */
++};
++
++static int zio_read_data(blkptr_t *bp, void *buf, char *stack);
++
++/*
++ * Our own version of bcmp().
++ */
++static int
++zfs_bcmp(const void *s1, const void *s2, size_t n)
++{
++	const uchar_t *ps1 = s1;
++	const uchar_t *ps2 = s2;
++
++	if (s1 != s2 && n != 0) {
++		do {
++			if (*ps1++ != *ps2++)
++				return (1);
++		} while (--n != 0);
++	}
++
++	return (0);
++}
++
++/*
++ * Our own version of log2().  Same thing as highbit()-1.
++ */
++static int
++zfs_log2(uint64_t num)
++{
++	int i = 0;
++
++	while (num > 1) {
++		i++;
++		num = num >> 1;
++	}
++
++	return (i);
++}
++
++/* Checksum Functions */
++static void
++zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
++{
++	ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
++}
++
++/* Checksum Table and Values */
++zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
++	NULL,			NULL,			0, 0,	"inherit",
++	NULL,			NULL,			0, 0,	"on",
++	zio_checksum_off,	zio_checksum_off,	0, 0,	"off",
++	zio_checksum_SHA256,	zio_checksum_SHA256,	1, 1,	"label",
++	zio_checksum_SHA256,	zio_checksum_SHA256,	1, 1,	"gang_header",
++	NULL,			NULL,			0, 0,	"zilog",
++	fletcher_2_native,	fletcher_2_byteswap,	0, 0,	"fletcher2",
++	fletcher_4_native,	fletcher_4_byteswap,	1, 0,	"fletcher4",
++	zio_checksum_SHA256,	zio_checksum_SHA256,	1, 0,	"SHA256",
++	NULL,			NULL,			0, 0,	"zilog2",
++};
++
++/*
++ * zio_checksum_verify: Provides support for checksum verification.
++ *
++ * Fletcher2, Fletcher4, and SHA256 are supported.
++ *
++ * Return:
++ * 	-1 = Failure
++ *	 0 = Success
++ */
++static int
++zio_checksum_verify(blkptr_t *bp, char *data, int size)
++{
++	zio_cksum_t zc = bp->blk_cksum;
++	uint32_t checksum = BP_GET_CHECKSUM(bp);
++	int byteswap = BP_SHOULD_BYTESWAP(bp);
++	zio_eck_t *zec = (zio_eck_t *)(data + size) - 1;
++	zio_checksum_info_t *ci = &zio_checksum_table[checksum];
++	zio_cksum_t actual_cksum, expected_cksum;
++
++	/* byteswap is not supported */
++	if (byteswap)
++		return (-1);
++
++	if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
++		return (-1);
++
++	if (ci->ci_eck) {
++		expected_cksum = zec->zec_cksum;
++		zec->zec_cksum = zc;
++		ci->ci_func[0](data, size, &actual_cksum);
++		zec->zec_cksum = expected_cksum;
++		zc = expected_cksum;
++
++	} else {
++		ci->ci_func[byteswap](data, size, &actual_cksum);
++	}
++
++	if ((actual_cksum.zc_word[0] - zc.zc_word[0]) |
++	    (actual_cksum.zc_word[1] - zc.zc_word[1]) |
++	    (actual_cksum.zc_word[2] - zc.zc_word[2]) |
++	    (actual_cksum.zc_word[3] - zc.zc_word[3]))
++		return (-1);
++
++	return (0);
++}
++
++/*
++ * vdev_label_start returns the physical disk offset (in bytes) of
++ * label "l".
++ */
++static uint64_t
++vdev_label_start(uint64_t psize, int l)
++{
++	return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?
++	    0 : psize - VDEV_LABELS * sizeof (vdev_label_t)));
++}
++
++/*
++ * vdev_uberblock_compare takes two uberblock structures and returns an integer
++ * indicating the more recent of the two.
++ * 	Return Value = 1 if ub2 is more recent
++ * 	Return Value = -1 if ub1 is more recent
++ * The most recent uberblock is determined using its transaction number and
++ * timestamp.  The uberblock with the highest transaction number is
++ * considered "newer".  If the transaction numbers of the two blocks match, the
++ * timestamps are compared to determine the "newer" of the two.
++ */
++static int
++vdev_uberblock_compare(uberblock_t *ub1, uberblock_t *ub2)
++{
++	if (ub1->ub_txg < ub2->ub_txg)
++		return (-1);
++	if (ub1->ub_txg > ub2->ub_txg)
++		return (1);
++
++	if (ub1->ub_timestamp < ub2->ub_timestamp)
++		return (-1);
++	if (ub1->ub_timestamp > ub2->ub_timestamp)
++		return (1);
++
++	return (0);
++}
++
++/*
++ * Three pieces of information are needed to verify an uberblock: the magic
++ * number, the version number, and the checksum.
++ *
++ * Currently Implemented: version number, magic number
++ * Need to Implement: checksum
++ *
++ * Return:
++ *     0 - Success
++ *    -1 - Failure
++ */
++static int
++uberblock_verify(uberblock_phys_t *ub, uint64_t offset)
++{
++
++	uberblock_t *uber = &ub->ubp_uberblock;
++	blkptr_t bp;
++
++	BP_ZERO(&bp);
++	BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL);
++	BP_SET_BYTEORDER(&bp, ZFS_HOST_BYTEORDER);
++	ZIO_SET_CHECKSUM(&bp.blk_cksum, offset, 0, 0, 0);
++
++	if (zio_checksum_verify(&bp, (char *)ub, UBERBLOCK_SIZE) != 0)
++		return (-1);
++
++	if (uber->ub_magic == UBERBLOCK_MAGIC &&
++	    uber->ub_version > 0 && uber->ub_version <= SPA_VERSION)
++		return (0);
++
++	return (-1);
++}
++
++/*
++ * Find the best uberblock.
++ * Return:
++ *    Success - Pointer to the best uberblock.
++ *    Failure - NULL
++ */
++static uberblock_phys_t *
++find_bestub(uberblock_phys_t *ub_array, uint64_t sector)
++{
++	uberblock_phys_t *ubbest = NULL;
++	uint64_t offset;
++	int i;
++
++	for (i = 0; i < (VDEV_UBERBLOCK_RING >> VDEV_UBERBLOCK_SHIFT); i++) {
++		offset = (sector << SPA_MINBLOCKSHIFT) +
++		    VDEV_UBERBLOCK_OFFSET(i);
++		if (uberblock_verify(&ub_array[i], offset) == 0) {
++			if (ubbest == NULL) {
++				ubbest = &ub_array[i];
++			} else if (vdev_uberblock_compare(
++			    &(ub_array[i].ubp_uberblock),
++			    &(ubbest->ubp_uberblock)) > 0) {
++				ubbest = &ub_array[i];
++			}
++		}
++	}
++
++	return (ubbest);
++}
++
++/*
++ * Read a block of data based on the gang block address dva,
++ * and put its data in buf.
++ *
++ * Return:
++ *	0 - success
++ *	1 - failure
++ */
++static int
++zio_read_gang(blkptr_t *bp, dva_t *dva, void *buf, char *stack)
++{
++	zio_gbh_phys_t *zio_gb;
++	uint64_t offset, sector;
++	blkptr_t tmpbp;
++	int i;
++
++	zio_gb = (zio_gbh_phys_t *)stack;
++	stack += SPA_GANGBLOCKSIZE;
++	offset = DVA_GET_OFFSET(dva);
++	sector =  DVA_OFFSET_TO_PHYS_SECTOR(offset);
++
++	/* read in the gang block header */
++	if (devread(sector, 0, SPA_GANGBLOCKSIZE, (char *)zio_gb) == 0) {
++		grub_printf("failed to read in a gang block header\n");
++		return (1);
++	}
++
++	/* self checksuming the gang block header */
++	BP_ZERO(&tmpbp);
++	BP_SET_CHECKSUM(&tmpbp, ZIO_CHECKSUM_GANG_HEADER);
++	BP_SET_BYTEORDER(&tmpbp, ZFS_HOST_BYTEORDER);
++	ZIO_SET_CHECKSUM(&tmpbp.blk_cksum, DVA_GET_VDEV(dva),
++	    DVA_GET_OFFSET(dva), bp->blk_birth, 0);
++	if (zio_checksum_verify(&tmpbp, (char *)zio_gb, SPA_GANGBLOCKSIZE)) {
++		grub_printf("failed to checksum a gang block header\n");
++		return (1);
++	}
++
++	for (i = 0; i < SPA_GBH_NBLKPTRS; i++) {
++		if (zio_gb->zg_blkptr[i].blk_birth == 0)
++			continue;
++
++		if (zio_read_data(&zio_gb->zg_blkptr[i], buf, stack))
++			return (1);
++		buf += BP_GET_PSIZE(&zio_gb->zg_blkptr[i]);
++	}
++
++	return (0);
++}
++
++/*
++ * Read in a block of raw data to buf.
++ *
++ * Return:
++ *	0 - success
++ *	1 - failure
++ */
++static int
++zio_read_data(blkptr_t *bp, void *buf, char *stack)
++{
++	int i, psize;
++
++	psize = BP_GET_PSIZE(bp);
++
++	/* pick a good dva from the block pointer */
++	for (i = 0; i < SPA_DVAS_PER_BP; i++) {
++		uint64_t offset, sector;
++
++		if (bp->blk_dva[i].dva_word[0] == 0 &&
++		    bp->blk_dva[i].dva_word[1] == 0)
++			continue;
++
++		if (DVA_GET_GANG(&bp->blk_dva[i])) {
++			if (zio_read_gang(bp, &bp->blk_dva[i], buf, stack) == 0)
++				return (0);
++		} else {
++			/* read in a data block */
++			offset = DVA_GET_OFFSET(&bp->blk_dva[i]);
++			sector =  DVA_OFFSET_TO_PHYS_SECTOR(offset);
++			if (devread(sector, 0, psize, buf))
++				return (0);
++		}
++	}
++
++	return (1);
++}
++
++/*
++ * Read in a block of data, verify its checksum, decompress if needed,
++ * and put the uncompressed data in buf.
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++zio_read(blkptr_t *bp, void *buf, char *stack)
++{
++	int lsize, psize, comp;
++	char *retbuf;
++
++	comp = BP_GET_COMPRESS(bp);
++	lsize = BP_GET_LSIZE(bp);
++	psize = BP_GET_PSIZE(bp);
++
++	if ((unsigned int)comp >= ZIO_COMPRESS_FUNCTIONS ||
++	    (comp != ZIO_COMPRESS_OFF &&
++	    decomp_table[comp].decomp_func == NULL)) {
++		grub_printf("compression algorithm not supported\n");
++		return (ERR_FSYS_CORRUPT);
++	}
++
++	if ((char *)buf < stack && ((char *)buf) + lsize > stack) {
++		grub_printf("not enough memory allocated\n");
++		return (ERR_WONT_FIT);
++	}
++
++	retbuf = buf;
++	if (comp != ZIO_COMPRESS_OFF) {
++		buf = stack;
++		stack += psize;
++	}
++
++	if (zio_read_data(bp, buf, stack)) {
++		grub_printf("zio_read_data failed\n");
++		return (ERR_FSYS_CORRUPT);
++	}
++
++	if (zio_checksum_verify(bp, buf, psize) != 0) {
++		grub_printf("checksum verification failed\n");
++		return (ERR_FSYS_CORRUPT);
++	}
++
++	if (comp != ZIO_COMPRESS_OFF)
++		decomp_table[comp].decomp_func(buf, retbuf, psize, lsize);
++
++	return (0);
++}
++
++/*
++ * Get the block from a block id.
++ * push the block onto the stack.
++ *
++ * Return:
++ * 	0 - success
++ * 	errnum - failure
++ */
++static int
++dmu_read(dnode_phys_t *dn, uint64_t blkid, void *buf, char *stack)
++{
++	int idx, level;
++	blkptr_t *bp_array = dn->dn_blkptr;
++	int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
++	blkptr_t *bp, *tmpbuf;
++
++	bp = (blkptr_t *)stack;
++	stack += sizeof (blkptr_t);
++
++	tmpbuf = (blkptr_t *)stack;
++	stack += 1<<dn->dn_indblkshift;
++
++	for (level = dn->dn_nlevels - 1; level >= 0; level--) {
++		idx = (blkid >> (epbs * level)) & ((1<<epbs)-1);
++		*bp = bp_array[idx];
++		if (level == 0)
++			tmpbuf = buf;
++		if (BP_IS_HOLE(bp)) {
++			grub_memset(buf, 0,
++			    dn->dn_datablkszsec << SPA_MINBLOCKSHIFT);
++			break;
++		} else if (errnum = zio_read(bp, tmpbuf, stack)) {
++			return (errnum);
++		}
++
++		bp_array = tmpbuf;
++	}
++
++	return (0);
++}
++
++/*
++ * mzap_lookup: Looks up property described by "name" and returns the value
++ * in "value".
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++mzap_lookup(mzap_phys_t *zapobj, int objsize, char *name,
++	uint64_t *value)
++{
++	int i, chunks;
++	mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
++
++	chunks = objsize/MZAP_ENT_LEN - 1;
++	for (i = 0; i < chunks; i++) {
++		if (grub_strcmp(mzap_ent[i].mze_name, name) == 0) {
++			*value = mzap_ent[i].mze_value;
++			return (0);
++		}
++	}
++
++	return (ERR_FSYS_CORRUPT);
++}
++
++static uint64_t
++zap_hash(uint64_t salt, const char *name)
++{
++	static uint64_t table[256];
++	const uint8_t *cp;
++	uint8_t c;
++	uint64_t crc = salt;
++
++	if (table[128] == 0) {
++		uint64_t *ct;
++		int i, j;
++		for (i = 0; i < 256; i++) {
++			for (ct = table + i, *ct = i, j = 8; j > 0; j--)
++				*ct = (*ct >> 1) ^ (-(*ct & 1) &
++				    ZFS_CRC64_POLY);
++		}
++	}
++
++	if (crc == 0 || table[128] != ZFS_CRC64_POLY) {
++		errnum = ERR_FSYS_CORRUPT;
++		return (0);
++	}
++
++	for (cp = (const uint8_t *)name; (c = *cp) != '\0'; cp++)
++		crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF];
++
++	/*
++	 * Only use 28 bits, since we need 4 bits in the cookie for the
++	 * collision differentiator.  We MUST use the high bits, since
++	 * those are the onces that we first pay attention to when
++	 * chosing the bucket.
++	 */
++	crc &= ~((1ULL << (64 - 28)) - 1);
++
++	return (crc);
++}
++
++/*
++ * Only to be used on 8-bit arrays.
++ * array_len is actual len in bytes (not encoded le_value_length).
++ * buf is null-terminated.
++ */
++static int
++zap_leaf_array_equal(zap_leaf_phys_t *l, int blksft, int chunk,
++    int array_len, const char *buf)
++{
++	int bseen = 0;
++
++	while (bseen < array_len) {
++		struct zap_leaf_array *la =
++		    &ZAP_LEAF_CHUNK(l, blksft, chunk).l_array;
++		int toread = MIN(array_len - bseen, ZAP_LEAF_ARRAY_BYTES);
++
++		if (chunk >= ZAP_LEAF_NUMCHUNKS(blksft))
++			return (0);
++
++		if (zfs_bcmp(la->la_array, buf + bseen, toread) != 0)
++			break;
++		chunk = la->la_next;
++		bseen += toread;
++	}
++	return (bseen == array_len);
++}
++
++/*
++ * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the
++ * value for the property "name".
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++zap_leaf_lookup(zap_leaf_phys_t *l, int blksft, uint64_t h,
++    const char *name, uint64_t *value)
++{
++	uint16_t chunk;
++	struct zap_leaf_entry *le;
++
++	/* Verify if this is a valid leaf block */
++	if (l->l_hdr.lh_block_type != ZBT_LEAF)
++		return (ERR_FSYS_CORRUPT);
++	if (l->l_hdr.lh_magic != ZAP_LEAF_MAGIC)
++		return (ERR_FSYS_CORRUPT);
++
++	for (chunk = l->l_hash[LEAF_HASH(blksft, h)];
++	    chunk != CHAIN_END; chunk = le->le_next) {
++
++		if (chunk >= ZAP_LEAF_NUMCHUNKS(blksft))
++			return (ERR_FSYS_CORRUPT);
++
++		le = ZAP_LEAF_ENTRY(l, blksft, chunk);
++
++		/* Verify the chunk entry */
++		if (le->le_type != ZAP_CHUNK_ENTRY)
++			return (ERR_FSYS_CORRUPT);
++
++		if (le->le_hash != h)
++			continue;
++
++		if (zap_leaf_array_equal(l, blksft, le->le_name_chunk,
++		    le->le_name_length, name)) {
++
++			struct zap_leaf_array *la;
++			uint8_t *ip;
++
++			if (le->le_int_size != 8 || le->le_value_length != 1)
++				return (ERR_FSYS_CORRUPT);
++
++			/* get the uint64_t property value */
++			la = &ZAP_LEAF_CHUNK(l, blksft,
++			    le->le_value_chunk).l_array;
++			ip = la->la_array;
++
++			*value = (uint64_t)ip[0] << 56 | (uint64_t)ip[1] << 48 |
++			    (uint64_t)ip[2] << 40 | (uint64_t)ip[3] << 32 |
++			    (uint64_t)ip[4] << 24 | (uint64_t)ip[5] << 16 |
++			    (uint64_t)ip[6] << 8 | (uint64_t)ip[7];
++
++			return (0);
++		}
++	}
++
++	return (ERR_FSYS_CORRUPT);
++}
++
++/*
++ * Fat ZAP lookup
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++fzap_lookup(dnode_phys_t *zap_dnode, zap_phys_t *zap,
++    char *name, uint64_t *value, char *stack)
++{
++	zap_leaf_phys_t *l;
++	uint64_t hash, idx, blkid;
++	int blksft = zfs_log2(zap_dnode->dn_datablkszsec << DNODE_SHIFT);
++
++	/* Verify if this is a fat zap header block */
++	if (zap->zap_magic != (uint64_t)ZAP_MAGIC ||
++	    zap->zap_flags != 0)
++		return (ERR_FSYS_CORRUPT);
++
++	hash = zap_hash(zap->zap_salt, name);
++	if (errnum)
++		return (errnum);
++
++	/* get block id from index */
++	if (zap->zap_ptrtbl.zt_numblks != 0) {
++		/* external pointer tables not supported */
++		return (ERR_FSYS_CORRUPT);
++	}
++	idx = ZAP_HASH_IDX(hash, zap->zap_ptrtbl.zt_shift);
++	blkid = ((uint64_t *)zap)[idx + (1<<(blksft-3-1))];
++
++	/* Get the leaf block */
++	l = (zap_leaf_phys_t *)stack;
++	stack += 1<<blksft;
++	if ((1<<blksft) < sizeof (zap_leaf_phys_t))
++		return (ERR_FSYS_CORRUPT);
++	if (errnum = dmu_read(zap_dnode, blkid, l, stack))
++		return (errnum);
++
++	return (zap_leaf_lookup(l, blksft, hash, name, value));
++}
++
++/*
++ * Read in the data of a zap object and find the value for a matching
++ * property name.
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++zap_lookup(dnode_phys_t *zap_dnode, char *name, uint64_t *val, char *stack)
++{
++	uint64_t block_type;
++	int size;
++	void *zapbuf;
++
++	/* Read in the first block of the zap object data. */
++	zapbuf = stack;
++	size = zap_dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
++	stack += size;
++
++	if (errnum = dmu_read(zap_dnode, 0, zapbuf, stack))
++		return (errnum);
++
++	block_type = *((uint64_t *)zapbuf);
++
++	if (block_type == ZBT_MICRO) {
++		return (mzap_lookup(zapbuf, size, name, val));
++	} else if (block_type == ZBT_HEADER) {
++		/* this is a fat zap */
++		return (fzap_lookup(zap_dnode, zapbuf, name,
++		    val, stack));
++	}
++
++	return (ERR_FSYS_CORRUPT);
++}
++
++/*
++ * Get the dnode of an object number from the metadnode of an object set.
++ *
++ * Input
++ *	mdn - metadnode to get the object dnode
++ *	objnum - object number for the object dnode
++ *	buf - data buffer that holds the returning dnode
++ *	stack - scratch area
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++dnode_get(dnode_phys_t *mdn, uint64_t objnum, uint8_t type, dnode_phys_t *buf,
++	char *stack)
++{
++	uint64_t blkid, blksz; /* the block id this object dnode is in */
++	int epbs; /* shift of number of dnodes in a block */
++	int idx; /* index within a block */
++	dnode_phys_t *dnbuf;
++
++	blksz = mdn->dn_datablkszsec << SPA_MINBLOCKSHIFT;
++	epbs = zfs_log2(blksz) - DNODE_SHIFT;
++	blkid = objnum >> epbs;
++	idx = objnum & ((1<<epbs)-1);
++
++	if (dnode_buf != NULL && dnode_mdn == mdn &&
++	    objnum >= dnode_start && objnum < dnode_end) {
++		grub_memmove(buf, &dnode_buf[idx], DNODE_SIZE);
++		VERIFY_DN_TYPE(buf, type);
++		return (0);
++	}
++
++	if (dnode_buf && blksz == 1<<DNODE_BLOCK_SHIFT) {
++		dnbuf = dnode_buf;
++		dnode_mdn = mdn;
++		dnode_start = blkid << epbs;
++		dnode_end = (blkid + 1) << epbs;
++	} else {
++		dnbuf = (dnode_phys_t *)stack;
++		stack += blksz;
++	}
++
++	if (errnum = dmu_read(mdn, blkid, (char *)dnbuf, stack))
++		return (errnum);
++
++	grub_memmove(buf, &dnbuf[idx], DNODE_SIZE);
++	VERIFY_DN_TYPE(buf, type);
++
++	return (0);
++}
++
++/*
++ * Check if this is a special file that resides at the top
++ * dataset of the pool. Currently this is the GRUB menu,
++ * boot signature and boot signature backup.
++ * str starts with '/'.
++ */
++static int
++is_top_dataset_file(char *str)
++{
++	char *tptr;
++
++	if ((tptr = grub_strstr(str, "menu.lst")) &&
++	    (tptr[8] == '\0' || tptr[8] == ' ') &&
++	    *(tptr-1) == '/')
++		return (1);
++
++	if (grub_strncmp(str, BOOTSIGN_DIR"/",
++	    grub_strlen(BOOTSIGN_DIR) + 1) == 0)
++		return (1);
++
++	if (grub_strcmp(str, BOOTSIGN_BACKUP) == 0)
++		return (1);
++
++	return (0);
++}
++
++/*
++ * Get the file dnode for a given file name where mdn is the meta dnode
++ * for this ZFS object set. When found, place the file dnode in dn.
++ * The 'path' argument will be mangled.
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++dnode_get_path(dnode_phys_t *mdn, char *path, dnode_phys_t *dn,
++    char *stack)
++{
++	uint64_t objnum, version;
++	char *cname, ch;
++
++	if (errnum = dnode_get(mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
++	    dn, stack))
++		return (errnum);
++
++	if (errnum = zap_lookup(dn, ZPL_VERSION_STR, &version, stack))
++		return (errnum);
++	if (version > ZPL_VERSION)
++		return (-1);
++
++	if (errnum = zap_lookup(dn, ZFS_ROOT_OBJ, &objnum, stack))
++		return (errnum);
++
++	if (errnum = dnode_get(mdn, objnum, DMU_OT_DIRECTORY_CONTENTS,
++	    dn, stack))
++		return (errnum);
++
++	/* skip leading slashes */
++	while (*path == '/')
++		path++;
++
++	while (*path && !isspace(*path)) {
++
++		/* get the next component name */
++		cname = path;
++		while (*path && !isspace(*path) && *path != '/')
++			path++;
++		ch = *path;
++		*path = 0;   /* ensure null termination */
++
++		if (errnum = zap_lookup(dn, cname, &objnum, stack))
++			return (errnum);
++
++		objnum = ZFS_DIRENT_OBJ(objnum);
++		if (errnum = dnode_get(mdn, objnum, 0, dn, stack))
++			return (errnum);
++
++		*path = ch;
++		while (*path == '/')
++			path++;
++	}
++
++	/* We found the dnode for this file. Verify if it is a plain file. */
++	VERIFY_DN_TYPE(dn, DMU_OT_PLAIN_FILE_CONTENTS);
++
++	return (0);
++}
++
++/*
++ * Get the default 'bootfs' property value from the rootpool.
++ *
++ * Return:
++ *	0 - success
++ *	errnum -failure
++ */
++static int
++get_default_bootfsobj(dnode_phys_t *mosmdn, uint64_t *obj, char *stack)
++{
++	uint64_t objnum = 0;
++	dnode_phys_t *dn = (dnode_phys_t *)stack;
++	stack += DNODE_SIZE;
++
++	if (errnum = dnode_get(mosmdn, DMU_POOL_DIRECTORY_OBJECT,
++	    DMU_OT_OBJECT_DIRECTORY, dn, stack))
++		return (errnum);
++
++	/*
++	 * find the object number for 'pool_props', and get the dnode
++	 * of the 'pool_props'.
++	 */
++	if (zap_lookup(dn, DMU_POOL_PROPS, &objnum, stack))
++		return (ERR_FILESYSTEM_NOT_FOUND);
++
++	if (errnum = dnode_get(mosmdn, objnum, DMU_OT_POOL_PROPS, dn, stack))
++		return (errnum);
++
++	if (zap_lookup(dn, ZPOOL_PROP_BOOTFS, &objnum, stack))
++		return (ERR_FILESYSTEM_NOT_FOUND);
++
++	if (!objnum)
++		return (ERR_FILESYSTEM_NOT_FOUND);
++
++	*obj = objnum;
++	return (0);
++}
++
++/*
++ * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
++ * e.g. pool/rootfs, or a given object number (obj), e.g. the object number
++ * of pool/rootfs.
++ *
++ * If no fsname and no obj are given, return the DSL_DIR metadnode.
++ * If fsname is given, return its metadnode and its matching object number.
++ * If only obj is given, return the metadnode for this object number.
++ *
++ * Return:
++ *	0 - success
++ *	errnum - failure
++ */
++static int
++get_objset_mdn(dnode_phys_t *mosmdn, char *fsname, uint64_t *obj,
++    dnode_phys_t *mdn, char *stack)
++{
++	uint64_t objnum, headobj;
++	char *cname, ch;
++	blkptr_t *bp;
++	objset_phys_t *osp;
++	int issnapshot = 0;
++	char *snapname;
++
++	if (fsname == NULL && obj) {
++		headobj = *obj;
++		goto skip;
++	}
++
++	if (errnum = dnode_get(mosmdn, DMU_POOL_DIRECTORY_OBJECT,
++	    DMU_OT_OBJECT_DIRECTORY, mdn, stack))
++		return (errnum);
++
++	if (errnum = zap_lookup(mdn, DMU_POOL_ROOT_DATASET, &objnum,
++	    stack))
++		return (errnum);
++
++	if (errnum = dnode_get(mosmdn, objnum, DMU_OT_DSL_DIR, mdn, stack))
++		return (errnum);
++
++	if (fsname == NULL) {
++		headobj =
++		    ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_head_dataset_obj;
++		goto skip;
++	}
++
++	/* take out the pool name */
++	while (*fsname && !isspace(*fsname) && *fsname != '/')
++		fsname++;
++
++	while (*fsname && !isspace(*fsname)) {
++		uint64_t childobj;
++
++		while (*fsname == '/')
++			fsname++;
++
++		cname = fsname;
++		while (*fsname && !isspace(*fsname) && *fsname != '/')
++			fsname++;
++		ch = *fsname;
++		*fsname = 0;
++
++		snapname = cname;
++		while (*snapname && !isspace(*snapname) && *snapname != '@')
++			snapname++;
++		if (*snapname == '@') {
++			issnapshot = 1;
++			*snapname = 0;
++		}
++		childobj =
++		    ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_child_dir_zapobj;
++		if (childobj == 0)
++			return (ERR_FILESYSTEM_NOT_FOUND);
++		if (errnum = dnode_get(mosmdn, childobj,
++		    DMU_OT_DSL_DIR_CHILD_MAP, mdn, stack))
++			return (errnum);
++
++		if (zap_lookup(mdn, cname, &objnum, stack))
++			return (ERR_FILESYSTEM_NOT_FOUND);
++
++		if (errnum = dnode_get(mosmdn, objnum, DMU_OT_DSL_DIR,
++		    mdn, stack))
++			return (errnum);
++
++		*fsname = ch;
++		if (issnapshot)
++			*snapname = '@';
++	}
++	headobj = ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_head_dataset_obj;
++	if (obj)
++		*obj = headobj;
++
++skip:
++	if (errnum = dnode_get(mosmdn, headobj, DMU_OT_DSL_DATASET, mdn, stack))
++		return (errnum);
++	if (issnapshot) {
++		uint64_t snapobj;
++
++		snapobj = ((dsl_dataset_phys_t *)DN_BONUS(mdn))->
++		    ds_snapnames_zapobj;
++
++		if (errnum = dnode_get(mosmdn, snapobj,
++		    DMU_OT_DSL_DS_SNAP_MAP, mdn, stack))
++			return (errnum);
++		if (zap_lookup(mdn, snapname + 1, &headobj, stack))
++			return (ERR_FILESYSTEM_NOT_FOUND);
++		if (errnum = dnode_get(mosmdn, headobj,
++		    DMU_OT_DSL_DATASET, mdn, stack))
++			return (errnum);
++		if (obj)
++			*obj = headobj;
++	}
++
++	bp = &((dsl_dataset_phys_t *)DN_BONUS(mdn))->ds_bp;
++	osp = (objset_phys_t *)stack;
++	stack += sizeof (objset_phys_t);
++	if (errnum = zio_read(bp, osp, stack))
++		return (errnum);
++
++	grub_memmove((char *)mdn, (char *)&osp->os_meta_dnode, DNODE_SIZE);
++
++	return (0);
++}
++
++/*
++ * For a given XDR packed nvlist, verify the first 4 bytes and move on.
++ *
++ * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
++ *
++ *      encoding method/host endian     (4 bytes)
++ *      nvl_version                     (4 bytes)
++ *      nvl_nvflag                      (4 bytes)
++ *	encoded nvpairs:
++ *		encoded size of the nvpair      (4 bytes)
++ *		decoded size of the nvpair      (4 bytes)
++ *		name string size                (4 bytes)
++ *		name string data                (sizeof(NV_ALIGN4(string))
++ *		data type                       (4 bytes)
++ *		# of elements in the nvpair     (4 bytes)
++ *		data
++ *      2 zero's for the last nvpair
++ *		(end of the entire list)	(8 bytes)
++ *
++ * Return:
++ *	0 - success
++ *	1 - failure
++ */
++static int
++nvlist_unpack(char *nvlist, char **out)
++{
++	/* Verify if the 1st and 2nd byte in the nvlist are valid. */
++	if (nvlist[0] != NV_ENCODE_XDR || nvlist[1] != HOST_ENDIAN)
++		return (1);
++
++	nvlist += 4;
++	*out = nvlist;
++	return (0);
++}
++
++static char *
++nvlist_array(char *nvlist, int index)
++{
++	int i, encode_size;
++
++	for (i = 0; i < index; i++) {
++		/* skip the header, nvl_version, and nvl_nvflag */
++		nvlist = nvlist + 4 * 2;
++
++		while (encode_size = BSWAP_32(*(uint32_t *)nvlist))
++			nvlist += encode_size; /* goto the next nvpair */
++
++		nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */
++	}
++
++	return (nvlist);
++}
++
++static int
++nvlist_lookup_value(char *nvlist, char *name, void *val, int valtype,
++    int *nelmp)
++{
++	int name_len, type, slen, encode_size;
++	char *nvpair, *nvp_name, *strval = val;
++	uint64_t *intval = val;
++
++	/* skip the header, nvl_version, and nvl_nvflag */
++	nvlist = nvlist + 4 * 2;
++
++	/*
++	 * Loop thru the nvpair list
++	 * The XDR representation of an integer is in big-endian byte order.
++	 */
++	while (encode_size = BSWAP_32(*(uint32_t *)nvlist))  {
++
++		nvpair = nvlist + 4 * 2; /* skip the encode/decode size */
++
++		name_len = BSWAP_32(*(uint32_t *)nvpair);
++		nvpair += 4;
++
++		nvp_name = nvpair;
++		nvpair = nvpair + ((name_len + 3) & ~3); /* align */
++
++		type = BSWAP_32(*(uint32_t *)nvpair);
++		nvpair += 4;
++
++		if ((grub_strncmp(nvp_name, name, name_len) == 0) &&
++		    type == valtype) {
++			int nelm;
++
++			if ((nelm = BSWAP_32(*(uint32_t *)nvpair)) < 1)
++				return (1);
++			nvpair += 4;
++
++			switch (valtype) {
++			case DATA_TYPE_STRING:
++				slen = BSWAP_32(*(uint32_t *)nvpair);
++				nvpair += 4;
++				grub_memmove(strval, nvpair, slen);
++				strval[slen] = '\0';
++				return (0);
++
++			case DATA_TYPE_UINT64:
++				*intval = BSWAP_64(*(uint64_t *)nvpair);
++				return (0);
++
++			case DATA_TYPE_NVLIST:
++				*(void **)val = (void *)nvpair;
++				return (0);
++
++			case DATA_TYPE_NVLIST_ARRAY:
++				*(void **)val = (void *)nvpair;
++				if (nelmp)
++					*nelmp = nelm;
++				return (0);
++			}
++		}
++
++		nvlist += encode_size; /* goto the next nvpair */
++	}
++
++	return (1);
++}
++
++/*
++ * Check if this vdev is online and is in a good state.
++ */
++static int
++vdev_validate(char *nv)
++{
++	uint64_t ival;
++
++	if (nvlist_lookup_value(nv, ZPOOL_CONFIG_OFFLINE, &ival,
++	    DATA_TYPE_UINT64, NULL) == 0 ||
++	    nvlist_lookup_value(nv, ZPOOL_CONFIG_FAULTED, &ival,
++	    DATA_TYPE_UINT64, NULL) == 0 ||
++	    nvlist_lookup_value(nv, ZPOOL_CONFIG_REMOVED, &ival,
++	    DATA_TYPE_UINT64, NULL) == 0)
++		return (ERR_DEV_VALUES);
++
++	return (0);
++}
++
++/*
++ * Get a valid vdev pathname/devid from the boot device.
++ * The caller should already allocate MAXPATHLEN memory for bootpath and devid.
++ */
++static int
++vdev_get_bootpath(char *nv, uint64_t inguid, char *devid, char *bootpath,
++    int is_spare)
++{
++	char type[16];
++
++	if (nvlist_lookup_value(nv, ZPOOL_CONFIG_TYPE, &type, DATA_TYPE_STRING,
++	    NULL))
++		return (ERR_FSYS_CORRUPT);
++
++	if (strcmp(type, VDEV_TYPE_DISK) == 0) {
++		uint64_t guid;
++
++		if (vdev_validate(nv) != 0)
++			return (ERR_NO_BOOTPATH);
++
++		if (nvlist_lookup_value(nv, ZPOOL_CONFIG_GUID,
++		    &guid, DATA_TYPE_UINT64, NULL) != 0)
++			return (ERR_NO_BOOTPATH);
++
++		if (guid != inguid)
++			return (ERR_NO_BOOTPATH);
++
++		/* for a spare vdev, pick the disk labeled with "is_spare" */
++		if (is_spare) {
++			uint64_t spare = 0;
++			(void) nvlist_lookup_value(nv, ZPOOL_CONFIG_IS_SPARE,
++			    &spare, DATA_TYPE_UINT64, NULL);
++			if (!spare)
++				return (ERR_NO_BOOTPATH);
++		}
++
++		if (nvlist_lookup_value(nv, ZPOOL_CONFIG_PHYS_PATH,
++		    bootpath, DATA_TYPE_STRING, NULL) != 0)
++			bootpath[0] = '\0';
++
++		if (nvlist_lookup_value(nv, ZPOOL_CONFIG_DEVID,
++		    devid, DATA_TYPE_STRING, NULL) != 0)
++			devid[0] = '\0';
++
++		if (strlen(bootpath) >= MAXPATHLEN ||
++		    strlen(devid) >= MAXPATHLEN)
++			return (ERR_WONT_FIT);
++
++		return (0);
++
++	} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
++	    strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
++	    (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
++		int nelm, i;
++		char *child;
++
++		if (nvlist_lookup_value(nv, ZPOOL_CONFIG_CHILDREN, &child,
++		    DATA_TYPE_NVLIST_ARRAY, &nelm))
++			return (ERR_FSYS_CORRUPT);
++
++		for (i = 0; i < nelm; i++) {
++			char *child_i;
++
++			child_i = nvlist_array(child, i);
++			if (vdev_get_bootpath(child_i, inguid, devid,
++			    bootpath, is_spare) == 0)
++				return (0);
++		}
++	}
++
++	return (ERR_NO_BOOTPATH);
++}
++
++/*
++ * Check the disk label information and retrieve needed vdev name-value pairs.
++ *
++ * Return:
++ *	0 - success
++ *	ERR_* - failure
++ */
++int
++check_pool_label(uint64_t sector, char *stack, char *outdevid,
++    char *outpath, uint64_t *outguid)
++{
++	vdev_phys_t *vdev;
++	uint64_t pool_state, txg = 0;
++	char *nvlist, *nv;
++	uint64_t diskguid;
++	uint64_t version;
++
++	sector += (VDEV_SKIP_SIZE >> SPA_MINBLOCKSHIFT);
++
++	/* Read in the vdev name-value pair list (112K). */
++	if (devread(sector, 0, VDEV_PHYS_SIZE, stack) == 0)
++		return (ERR_READ);
++
++	vdev = (vdev_phys_t *)stack;
++	stack += sizeof (vdev_phys_t);
++
++	if (nvlist_unpack(vdev->vp_nvlist, &nvlist))
++		return (ERR_FSYS_CORRUPT);
++
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_STATE, &pool_state,
++	    DATA_TYPE_UINT64, NULL))
++		return (ERR_FSYS_CORRUPT);
++
++	if (pool_state == POOL_STATE_DESTROYED)
++		return (ERR_FILESYSTEM_NOT_FOUND);
++
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_NAME,
++	    current_rootpool, DATA_TYPE_STRING, NULL))
++		return (ERR_FSYS_CORRUPT);
++
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_TXG, &txg,
++	    DATA_TYPE_UINT64, NULL))
++		return (ERR_FSYS_CORRUPT);
++
++	/* not an active device */
++	if (txg == 0)
++		return (ERR_NO_BOOTPATH);
++
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_VERSION, &version,
++	    DATA_TYPE_UINT64, NULL))
++		return (ERR_FSYS_CORRUPT);
++	if (version > SPA_VERSION)
++		return (ERR_NEWER_VERSION);
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_VDEV_TREE, &nv,
++	    DATA_TYPE_NVLIST, NULL))
++		return (ERR_FSYS_CORRUPT);
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_GUID, &diskguid,
++	    DATA_TYPE_UINT64, NULL))
++		return (ERR_FSYS_CORRUPT);
++	if (vdev_get_bootpath(nv, diskguid, outdevid, outpath, 0))
++		return (ERR_NO_BOOTPATH);
++	if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_GUID, outguid,
++	    DATA_TYPE_UINT64, NULL))
++		return (ERR_FSYS_CORRUPT);
++	return (0);
++}
++
++/*
++ * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
++ * to the memory address MOS.
++ *
++ * Return:
++ *	1 - success
++ *	0 - failure
++ */
++int
++zfs_mount(void)
++{
++	char *stack;
++	int label = 0;
++	uberblock_phys_t *ub_array, *ubbest;
++	objset_phys_t *osp;
++	char tmp_bootpath[MAXNAMELEN];
++	char tmp_devid[MAXNAMELEN];
++	uint64_t tmp_guid;
++	uint64_t adjpl = (uint64_t)part_length << SPA_MINBLOCKSHIFT;
++	int err = errnum; /* preserve previous errnum state */
++
++	/* if it's our first time here, zero the best uberblock out */
++	if (best_drive == 0 && best_part == 0 && find_best_root) {
++		grub_memset(&current_uberblock, 0, sizeof (uberblock_t));
++		pool_guid = 0;
++	}
++
++	stackbase = ZFS_SCRATCH;
++	stack = stackbase;
++	ub_array = (uberblock_phys_t *)stack;
++	stack += VDEV_UBERBLOCK_RING;
++
++	osp = (objset_phys_t *)stack;
++	stack += sizeof (objset_phys_t);
++	adjpl = P2ALIGN(adjpl, (uint64_t)sizeof (vdev_label_t));
++
++	for (label = 0; label < VDEV_LABELS; label++) {
++
++		/*
++		 * some eltorito stacks don't give us a size and
++		 * we end up setting the size to MAXUINT, further
++		 * some of these devices stop working once a single
++		 * read past the end has been issued. Checking
++		 * for a maximum part_length and skipping the backup
++		 * labels at the end of the slice/partition/device
++		 * avoids breaking down on such devices.
++		 */
++		if (part_length == MAXUINT && label == 2)
++			break;
++
++		uint64_t sector = vdev_label_start(adjpl,
++		    label) >> SPA_MINBLOCKSHIFT;
++
++		/* Read in the uberblock ring (128K). */
++		if (devread(sector  +
++		    ((VDEV_SKIP_SIZE + VDEV_PHYS_SIZE) >>
++		    SPA_MINBLOCKSHIFT), 0, VDEV_UBERBLOCK_RING,
++		    (char *)ub_array) == 0)
++			continue;
++
++		if ((ubbest = find_bestub(ub_array, sector)) != NULL &&
++		    zio_read(&ubbest->ubp_uberblock.ub_rootbp, osp, stack)
++		    == 0) {
++
++			VERIFY_OS_TYPE(osp, DMU_OST_META);
++
++			if (check_pool_label(sector, stack, tmp_devid,
++			    tmp_bootpath, &tmp_guid))
++				continue;
++			if (pool_guid == 0)
++				pool_guid = tmp_guid;
++
++			if (find_best_root && ((pool_guid != tmp_guid) ||
++			    vdev_uberblock_compare(&ubbest->ubp_uberblock,
++			    &(current_uberblock)) <= 0))
++				continue;
++
++			/* Got the MOS. Save it at the memory addr MOS. */
++			grub_memmove(MOS, &osp->os_meta_dnode, DNODE_SIZE);
++			grub_memmove(&current_uberblock,
++			    &ubbest->ubp_uberblock, sizeof (uberblock_t));
++			grub_memmove(current_bootpath, tmp_bootpath,
++			    MAXNAMELEN);
++			grub_memmove(current_devid, tmp_devid,
++			    grub_strlen(tmp_devid));
++			is_zfs_mount = 1;
++			return (1);
++		}
++	}
++
++	/*
++	 * While some fs impls. (tftp) rely on setting and keeping
++	 * global errnums set, others won't reset it and will break
++	 * when issuing rawreads. The goal here is to simply not
++	 * have zfs mount attempts impact the previous state.
++	 */
++	errnum = err;
++	return (0);
++}
++
++/*
++ * zfs_open() locates a file in the rootpool by following the
++ * MOS and places the dnode of the file in the memory address DNODE.
++ *
++ * Return:
++ *	1 - success
++ *	0 - failure
++ */
++int
++zfs_open(char *filename)
++{
++	char *stack;
++	dnode_phys_t *mdn;
++
++	file_buf = NULL;
++	stackbase = ZFS_SCRATCH;
++	stack = stackbase;
++
++	mdn = (dnode_phys_t *)stack;
++	stack += sizeof (dnode_phys_t);
++
++	dnode_mdn = NULL;
++	dnode_buf = (dnode_phys_t *)stack;
++	stack += 1<<DNODE_BLOCK_SHIFT;
++
++	/*
++	 * menu.lst is placed at the root pool filesystem level,
++	 * do not goto 'current_bootfs'.
++	 */
++	if (is_top_dataset_file(filename)) {
++		if (errnum = get_objset_mdn(MOS, NULL, NULL, mdn, stack))
++			return (0);
++
++		current_bootfs_obj = 0;
++	} else {
++		if (current_bootfs[0] == '\0') {
++			/* Get the default root filesystem object number */
++			if (errnum = get_default_bootfsobj(MOS,
++			    &current_bootfs_obj, stack))
++				return (0);
++
++			if (errnum = get_objset_mdn(MOS, NULL,
++			    &current_bootfs_obj, mdn, stack))
++				return (0);
++		} else {
++			if (errnum = get_objset_mdn(MOS, current_bootfs,
++			    &current_bootfs_obj, mdn, stack)) {
++				grub_memset(current_bootfs, 0, MAXNAMELEN);
++				return (0);
++			}
++		}
++	}
++
++	if (dnode_get_path(mdn, filename, DNODE, stack)) {
++		errnum = ERR_FILE_NOT_FOUND;
++		return (0);
++	}
++
++	/* get the file size and set the file position to 0 */
++
++	/*
++	 * For DMU_OT_SA we will need to locate the SIZE attribute
++	 * attribute, which could be either in the bonus buffer
++	 * or the "spill" block.
++	 */
++	if (DNODE->dn_bonustype == DMU_OT_SA) {
++		sa_hdr_phys_t *sahdrp;
++		int hdrsize;
++
++		if (DNODE->dn_bonuslen != 0) {
++			sahdrp = (sa_hdr_phys_t *)DN_BONUS(DNODE);
++		} else {
++			if (DNODE->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
++				blkptr_t *bp = &DNODE->dn_spill;
++				void *buf;
++
++				buf = (void *)stack;
++				stack += BP_GET_LSIZE(bp);
++
++				/* reset errnum to rawread() failure */
++				errnum = 0;
++				if (zio_read(bp, buf, stack) != 0) {
++					return (0);
++				}
++				sahdrp = buf;
++			} else {
++				errnum = ERR_FSYS_CORRUPT;
++				return (0);
++			}
++		}
++		hdrsize = SA_HDR_SIZE(sahdrp);
++		filemax = *(uint64_t *)((char *)sahdrp + hdrsize +
++		    SA_SIZE_OFFSET);
++	} else {
++		filemax = ((znode_phys_t *)DN_BONUS(DNODE))->zp_size;
++	}
++	filepos = 0;
++
++	dnode_buf = NULL;
++	return (1);
++}
++
++/*
++ * zfs_read reads in the data blocks pointed by the DNODE.
++ *
++ * Return:
++ *	len - the length successfully read in to the buffer
++ *	0   - failure
++ */
++int
++zfs_read(char *buf, int len)
++{
++	char *stack;
++	char *tmpbuf;
++	int blksz, length, movesize;
++
++	if (file_buf == NULL) {
++		file_buf = stackbase;
++		stackbase += SPA_MAXBLOCKSIZE;
++		file_start = file_end = 0;
++	}
++	stack = stackbase;
++
++	/*
++	 * If offset is in memory, move it into the buffer provided and return.
++	 */
++	if (filepos >= file_start && filepos+len <= file_end) {
++		grub_memmove(buf, file_buf + filepos - file_start, len);
++		filepos += len;
++		return (len);
++	}
++
++	blksz = DNODE->dn_datablkszsec << SPA_MINBLOCKSHIFT;
++
++	/*
++	 * Entire Dnode is too big to fit into the space available.  We
++	 * will need to read it in chunks.  This could be optimized to
++	 * read in as large a chunk as there is space available, but for
++	 * now, this only reads in one data block at a time.
++	 */
++	length = len;
++	while (length) {
++		/*
++		 * Find requested blkid and the offset within that block.
++		 */
++		uint64_t blkid = filepos / blksz;
++
++		if (errnum = dmu_read(DNODE, blkid, file_buf, stack))
++			return (0);
++
++		file_start = blkid * blksz;
++		file_end = file_start + blksz;
++
++		movesize = MIN(length, file_end - filepos);
++
++		grub_memmove(buf, file_buf + filepos - file_start,
++		    movesize);
++		buf += movesize;
++		length -= movesize;
++		filepos += movesize;
++	}
++
++	return (len);
++}
++
++/*
++ * No-Op
++ */
++int
++zfs_embed(int *start_sector, int needed_sectors)
++{
++	return (1);
++}
++
++#endif /* FSYS_ZFS */
+diff -urN grub.patch50/stage2/fsys_zfs.h grub.zfs_solaris/stage2/fsys_zfs.h
+--- grub.patch50/stage2/fsys_zfs.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/fsys_zfs.h	2011-10-12 19:58:29.039922403 +0200
+@@ -0,0 +1,205 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++#ifndef _FSYS_ZFS_H
++#define	_FSYS_ZFS_H
++
++#ifdef	FSYS_ZFS
++
++#ifndef	FSIMAGE
++typedef unsigned long long uint64_t;
++typedef unsigned int uint32_t;
++typedef unsigned short uint16_t;
++typedef unsigned char uint8_t;
++typedef unsigned char uchar_t;
++
++#if defined(_LP64) || defined(_I32LPx)
++typedef	unsigned long size_t;
++#else
++typedef	unsigned int size_t;
++#endif
++#else
++#include "fsi_zfs.h"
++#endif	/* !FSIMAGE */
++
++#include <zfs-include/zfs.h>
++#include <zfs-include/dmu.h>
++#include <zfs-include/spa.h>
++#include <zfs-include/zio.h>
++#include <zfs-include/zio_checksum.h>
++#include <zfs-include/vdev_impl.h>
++#include <zfs-include/zap_impl.h>
++#include <zfs-include/zap_leaf.h>
++#include <zfs-include/uberblock_impl.h>
++#include <zfs-include/dnode.h>
++#include <zfs-include/dsl_dir.h>
++#include <zfs-include/zfs_acl.h>
++#include <zfs-include/zfs_znode.h>
++#include <zfs-include/dsl_dataset.h>
++#include <zfs-include/zil.h>
++#include <zfs-include/dmu_objset.h>
++#include <zfs-include/sa_impl.h>
++
++/*
++ * Global Memory addresses to store MOS and DNODE data
++ */
++#define	MOS		((dnode_phys_t *) ZFS_ADDR)
++#define	DNODE		(MOS+1) /* move sizeof(dnode_phys_t) bytes */
++#define	ZFS_SCRATCH	((char *)(DNODE+1))
++
++/*
++ * Verify dnode type.
++ * Can only be used in functions returning non-0 for failure.
++ */
++#define	VERIFY_DN_TYPE(dnp, type) \
++	if (type && (dnp)->dn_type != type) { \
++		return (ERR_FSYS_CORRUPT); \
++	}
++
++/*
++ * Verify object set type.
++ * Can only be used in functions returning 0 for failure.
++ */
++#define	VERIFY_OS_TYPE(osp, type) \
++	if (type && (osp)->os_type != type) { \
++		errnum = ERR_FSYS_CORRUPT; \
++		return (0); \
++	}
++
++#define	ZPOOL_PROP_BOOTFS		"bootfs"
++
++/* General macros */
++#define	BSWAP_8(x)	((x) & 0xff)
++#define	BSWAP_16(x)	((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
++#define	BSWAP_32(x)	((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
++#define	BSWAP_64(x)	((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32))
++#define	P2ROUNDUP(x, align)	(-(-(x) & -(align)))
++
++/*
++ * XXX Match these macro up with real zfs once we have nvlist support so that we
++ * can support large sector disks.
++ */
++#define	UBERBLOCK_SIZE		(1ULL << UBERBLOCK_SHIFT)
++#undef	offsetof
++#define	offsetof(t, m)   ((int)&(((t *)0)->m))
++#define	VDEV_UBERBLOCK_SHIFT	UBERBLOCK_SHIFT
++#define	VDEV_UBERBLOCK_OFFSET(n) \
++offsetof(vdev_label_t, vl_uberblock[(n) << VDEV_UBERBLOCK_SHIFT])
++
++typedef struct uberblock uberblock_t;
++
++/* XXX Uberblock_phys_t is no longer in the kernel zfs */
++typedef struct uberblock_phys {
++	uberblock_t	ubp_uberblock;
++	char		ubp_pad[UBERBLOCK_SIZE - sizeof (uberblock_t) -
++				sizeof (zio_eck_t)];
++	zio_eck_t	ubp_zec;
++} uberblock_phys_t;
++
++/*
++ * Macros to get fields in a bp or DVA.
++ */
++#define	P2PHASE(x, align)		((x) & ((align) - 1))
++#define	DVA_OFFSET_TO_PHYS_SECTOR(offset) \
++	((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT)
++
++/*
++ * return x rounded down to an align boundary
++ * eg, P2ALIGN(1200, 1024) == 1024 (1*align)
++ * eg, P2ALIGN(1024, 1024) == 1024 (1*align)
++ * eg, P2ALIGN(0x1234, 0x100) == 0x1200 (0x12*align)
++ * eg, P2ALIGN(0x5600, 0x100) == 0x5600 (0x56*align)
++ */
++#define	P2ALIGN(x, align)		((x) & -(align))
++
++/*
++ * For nvlist manipulation. (from nvpair.h)
++ */
++#define	NV_ENCODE_NATIVE	0
++#define	NV_ENCODE_XDR		1
++#define	HOST_ENDIAN		1	/* for x86 machine */
++#define	DATA_TYPE_UINT64	8
++#define	DATA_TYPE_STRING	9
++#define	DATA_TYPE_NVLIST	19
++#define	DATA_TYPE_NVLIST_ARRAY	20
++
++/*
++ * Decompression Entry - lzjb
++ */
++#ifndef	NBBY
++#define	NBBY	8
++#endif
++
++typedef int zfs_decomp_func_t(void *s_start, void *d_start, size_t s_len,
++			size_t d_len);
++typedef struct decomp_entry {
++	char *name;
++	zfs_decomp_func_t *decomp_func;
++} decomp_entry_t;
++
++/*
++ * FAT ZAP data structures
++ */
++#define	ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */
++#define	ZAP_HASH_IDX(hash, n)	(((n) == 0) ? 0 : ((hash) >> (64 - (n))))
++#define	CHAIN_END	0xffff	/* end of the chunk chain */
++
++/*
++ * The amount of space within the chunk available for the array is:
++ * chunk size - space for type (1) - space for next pointer (2)
++ */
++#define	ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3)
++
++#define	ZAP_LEAF_HASH_SHIFT(bs)	(bs - 5)
++#define	ZAP_LEAF_HASH_NUMENTRIES(bs) (1 << ZAP_LEAF_HASH_SHIFT(bs))
++#define	LEAF_HASH(bs, h) \
++	((ZAP_LEAF_HASH_NUMENTRIES(bs)-1) & \
++	((h) >> (64 - ZAP_LEAF_HASH_SHIFT(bs)-l->l_hdr.lh_prefix_len)))
++
++/*
++ * The amount of space available for chunks is:
++ * block size shift - hash entry size (2) * number of hash
++ * entries - header space (2*chunksize)
++ */
++#define	ZAP_LEAF_NUMCHUNKS(bs) \
++	(((1<<bs) - 2*ZAP_LEAF_HASH_NUMENTRIES(bs)) / \
++	ZAP_LEAF_CHUNKSIZE - 2)
++
++/*
++ * The chunks start immediately after the hash table.  The end of the
++ * hash table is at l_hash + HASH_NUMENTRIES, which we simply cast to a
++ * chunk_t.
++ */
++#define	ZAP_LEAF_CHUNK(l, bs, idx) \
++	((zap_leaf_chunk_t *)(l->l_hash + ZAP_LEAF_HASH_NUMENTRIES(bs)))[idx]
++#define	ZAP_LEAF_ENTRY(l, bs, idx) (&ZAP_LEAF_CHUNK(l, bs, idx).l_entry)
++
++extern void fletcher_2_native(const void *, uint64_t, zio_cksum_t *);
++extern void fletcher_2_byteswap(const void *, uint64_t, zio_cksum_t *);
++extern void fletcher_4_native(const void *, uint64_t, zio_cksum_t *);
++extern void fletcher_4_byteswap(const void *, uint64_t, zio_cksum_t *);
++extern void zio_checksum_SHA256(const void *, uint64_t, zio_cksum_t *);
++extern int lzjb_decompress(void *, void *, size_t, size_t);
++
++#endif	/* FSYS_ZFS */
++
++#endif /* !_FSYS_ZFS_H */
+diff -urN grub.patch50/stage2/pc_slice.h grub.zfs_solaris/stage2/pc_slice.h
+--- grub.patch50/stage2/pc_slice.h	2011-10-12 19:58:28.887921351 +0200
++++ grub.zfs_solaris/stage2/pc_slice.h	2011-10-12 19:58:29.043921841 +0200
+@@ -111,9 +111,12 @@
+ #define PC_SLICE_TYPE_EZD        	0x55
+ #define PC_SLICE_TYPE_MINIX		0x80
+ #define PC_SLICE_TYPE_LINUX_MINIX	0x81
++#define PC_SLICE_TYPE_SOLARIS		0x82	/* also Linux swap! */
+ #define PC_SLICE_TYPE_EXT2FS       	0x83
+ #define PC_SLICE_TYPE_LINUX_EXTENDED	0x85
+ #define PC_SLICE_TYPE_VSTAFS		0x9e
++#define PC_SLICE_TYPE_SOLARIS_BOOT	0xbe	/* Solaris boot (fat) */
++#define PC_SLICE_TYPE_SOLARIS2		0xbf	/* new Solaris type */
+ #define PC_SLICE_TYPE_DELL_UTIL		0xde
+ #define PC_SLICE_TYPE_LINUX_RAID	0xfd
+ 
+@@ -129,6 +132,7 @@
+      || _type == PC_SLICE_TYPE_FAT16_LBA \
+      || _type == PC_SLICE_TYPE_FAT32 \
+      || _type == PC_SLICE_TYPE_FAT32_LBA \
++     || _type == PC_SLICE_TYPE_SOLARIS_BOOT \
+      || _type == PC_SLICE_TYPE_DELL_UTIL; })
+ 
+ #define IS_PC_SLICE_TYPE_EXTENDED(type)	\
+@@ -154,6 +158,9 @@
+ 
+ #define IS_PC_SLICE_TYPE_BSD(type)	IS_PC_SLICE_TYPE_BSD_WITH_FS(type,0)
+ 
++#define IS_PC_SLICE_TYPE_SOLARIS(type)	\
++  (((type) == PC_SLICE_TYPE_SOLARIS) || ((type) == PC_SLICE_TYPE_SOLARIS2))
++
+ /*
+  *  *BSD-style disklabel & partition definitions.
+  *
+@@ -248,4 +255,29 @@
+ #define	FS_EXT2FS	17	/* Linux Extended 2 file system */
+ 
+ 
++/*
++ *  Solaris LABEL definitions. All definitions are relative to the
++ *  current PC_SLICE.
++ */
++#define SOL_LABEL_LOC	1
++#define SOL_LABEL_SIZE	512
++#define SOL_LABEL_MAGIC	0xdabe
++#define SOL_LABEL_MAGIC_OFFSET 0x1fc
++#define SOL_LABEL_NPARTS 0x10
++
++#define SOL_PART_OFFSET 0x48
++
++#define SOL_LABEL_CHECK_MAG(l_ptr) \
++  (*((unsigned short *) (((int) l_ptr) + SOL_LABEL_MAGIC_OFFSET)) \
++   == ((unsigned short) SOL_LABEL_MAGIC ))
++
++#define SOL_PART_START(l_ptr, p) \
++  (*((unsigned long *) (((int) l_ptr) + SOL_PART_OFFSET + (p) * 0xc + 4)))
++
++#define SOL_PART_LENGTH(l_ptr, p) \
++  (*((unsigned long *) (((int) l_ptr) + SOL_PART_OFFSET + (p) * 0xc + 8)))
++
++#define SOL_PART_EXISTS(l_ptr, p) (SOL_PART_LENGTH(l_ptr, p) != 0)
++
++
+ #endif /* _PC_SLICE_H */
+diff -urN grub.patch50/stage2/shared.h grub.zfs_solaris/stage2/shared.h
+--- grub.patch50/stage2/shared.h	2011-10-12 19:58:28.891921946 +0200
++++ grub.zfs_solaris/stage2/shared.h	2011-10-12 19:58:29.047921884 +0200
+@@ -44,11 +44,29 @@
+ # define RAW_SEG(x) (x)
+ #endif
+ 
++/* ZFS will use the top 4 Meg of domain memory for scratch */
++#define ZFS_ADDR         RAW_ADDR((mbi.mem_lower << 10) - ZFS_SCRATCH_SIZE)
++#define ZFS_SCRATCH_SIZE 0x400000
++
++#ifndef MAXPATHLEN
++#define	MAXPATHLEN	1024
++#endif
++
++#define	MAXNAMELEN	256
++#define MIN(x, y) ((x) < (y) ? (x) : (y))
++
++/* Boot signature related defines for the findroot command */
++#define	BOOTSIGN_DIR	"/boot/grub/bootsign"
++#define	BOOTSIGN_ARGLEN	(MAXNAMELEN + 10)	/* (<sign>,0,d) */
++#define	BOOTSIGN_LEN	(sizeof (BOOTSIGN_DIR) + 1 + BOOTSIGN_ARGLEN)
++#define	BOOTSIGN_BACKUP	"/etc/bootsign"
++
+ /*
+  *  Integer sizes
+  */
+ 
+ #define MAXINT     0x7FFFFFFF
++#define	MAXUINT		0xFFFFFFFF
+ 
+ /* Maximum command line size. Before you blindly increase this value,
+    see the comment in char_io.c (get_cmdline).  */
+@@ -212,6 +230,7 @@
+ #define STAGE2_ID_XFS_STAGE1_5		8
+ #define STAGE2_ID_ISO9660_STAGE1_5	9
+ #define STAGE2_ID_UFS2_STAGE1_5		10
++#define STAGE2_ID_ZFS_STAGE1_5		12
+ 
+ #ifndef STAGE1_5
+ # define STAGE2_ID	STAGE2_ID_STAGE2
+@@ -236,6 +255,8 @@
+ #  define STAGE2_ID	STAGE2_ID_ISO9660_STAGE1_5
+ # elif defined(FSYS_UFS2)
+ #  define STAGE2_ID	STAGE2_ID_UFS2_STAGE1_5
++# elif defined(FSYS_ZFS)
++#  define STAGE2_ID	STAGE2_ID_ZFS_STAGE1_5
+ # else
+ #  error "unknown Stage 2"
+ # endif
+@@ -549,6 +570,9 @@
+   ERR_DEV_NEED_INIT,
+   ERR_NO_DISK_SPACE,
+   ERR_NUMBER_OVERFLOW,
++  ERR_FILESYSTEM_NOT_FOUND,
++  ERR_NO_BOOTPATH,
++  ERR_NEWER_VERSION,
+ 
+   MAX_ERR_NUM
+ } grub_error_t;
+@@ -635,6 +659,15 @@
+ 
+ extern unsigned long current_drive;
+ extern unsigned long current_partition;
++extern char current_rootpool[MAXNAMELEN];
++extern char current_bootfs[MAXNAMELEN];
++extern unsigned long long current_bootfs_obj;
++extern char current_bootpath[MAXPATHLEN];
++extern char current_devid[MAXPATHLEN];
++extern int is_zfs_mount;
++extern unsigned long best_drive;
++extern unsigned long best_part;
++extern int find_best_root;
+ 
+ extern int fsys_type;
+ 
+@@ -889,6 +922,7 @@
+ int grub_strcmp (const char *s1, const char *s2);
+ int grub_strlen (const char *str);
+ char *grub_strcpy (char *dest, const char *src);
++char *grub_strchr (char *str, char c);
+ 
+ #ifndef GRUB_UTIL
+ typedef unsigned long grub_jmp_buf[6];
+diff -urN grub.patch50/stage2/stage2.c grub.zfs_solaris/stage2/stage2.c
+--- grub.patch50/stage2/stage2.c	2011-10-12 19:58:28.891921946 +0200
++++ grub.zfs_solaris/stage2/stage2.c	2011-10-12 19:58:29.047921884 +0200
+@@ -871,6 +871,7 @@
+   return pos;
+ }
+ 
++extern int findroot_func (char *arg, int flags);
+ 
+ /* This is the starting function in C.  */
+ void
+@@ -961,11 +962,21 @@
+ 	      if (! is_opened)
+ 		{
+ 		  is_opened = grub_open (config_file);
+-		  errnum = ERR_NONE;
+ 		}
++	      /*
++	       * we're not going to get very far if we weren't able to
++	       * open the config file and this isn't a valid filesystem,
++	       * so look for the config file somewhere else
++	       */
++	      if (!is_opened && errnum == ERR_FSYS_MOUNT &&
++		(findroot_func(config_file, 0) == 0)) {
++		  is_opened = grub_open (config_file);
++	      }
+ 
+-	      if (! is_opened)
++	      if (! is_opened) {
++	        errnum = ERR_NONE;
+ 		break;
++	      }
+ 
+ 	      /* This is necessary, because the menu must be overrided.  */
+ 	      reset ();
+diff -urN grub.patch50/stage2/zfs-include/dmu.h grub.zfs_solaris/stage2/zfs-include/dmu.h
+--- grub.patch50/stage2/zfs-include/dmu.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/dmu.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,120 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_DMU_H
++#define	_SYS_DMU_H
++
++/*
++ * This file describes the interface that the DMU provides for its
++ * consumers.
++ *
++ * The DMU also interacts with the SPA.  That interface is described in
++ * dmu_spa.h.
++ */
++typedef enum dmu_object_type {
++	DMU_OT_NONE,
++	/* general: */
++	DMU_OT_OBJECT_DIRECTORY,	/* ZAP */
++	DMU_OT_OBJECT_ARRAY,		/* UINT64 */
++	DMU_OT_PACKED_NVLIST,		/* UINT8 (XDR by nvlist_pack/unpack) */
++	DMU_OT_PACKED_NVLIST_SIZE,	/* UINT64 */
++	DMU_OT_BPLIST,			/* UINT64 */
++	DMU_OT_BPLIST_HDR,		/* UINT64 */
++	/* spa: */
++	DMU_OT_SPACE_MAP_HEADER,	/* UINT64 */
++	DMU_OT_SPACE_MAP,		/* UINT64 */
++	/* zil: */
++	DMU_OT_INTENT_LOG,		/* UINT64 */
++	/* dmu: */
++	DMU_OT_DNODE,			/* DNODE */
++	DMU_OT_OBJSET,			/* OBJSET */
++	/* dsl: */
++	DMU_OT_DSL_DIR,			/* UINT64 */
++	DMU_OT_DSL_DIR_CHILD_MAP,	/* ZAP */
++	DMU_OT_DSL_DS_SNAP_MAP,		/* ZAP */
++	DMU_OT_DSL_PROPS,		/* ZAP */
++	DMU_OT_DSL_DATASET,		/* UINT64 */
++	/* zpl: */
++	DMU_OT_ZNODE,			/* ZNODE */
++	DMU_OT_OLDACL,			/* OLD ACL */
++	DMU_OT_PLAIN_FILE_CONTENTS,	/* UINT8 */
++	DMU_OT_DIRECTORY_CONTENTS,	/* ZAP */
++	DMU_OT_MASTER_NODE,		/* ZAP */
++	DMU_OT_UNLINKED_SET,		/* ZAP */
++	/* zvol: */
++	DMU_OT_ZVOL,			/* UINT8 */
++	DMU_OT_ZVOL_PROP,		/* ZAP */
++	/* other; for testing only! */
++	DMU_OT_PLAIN_OTHER,		/* UINT8 */
++	DMU_OT_UINT64_OTHER,		/* UINT64 */
++	DMU_OT_ZAP_OTHER,		/* ZAP */
++	/* new object types: */
++	DMU_OT_ERROR_LOG,		/* ZAP */
++	DMU_OT_SPA_HISTORY,		/* UINT8 */
++	DMU_OT_SPA_HISTORY_OFFSETS,	/* spa_his_phys_t */
++	DMU_OT_POOL_PROPS,		/* ZAP */
++	DMU_OT_DSL_PERMS,		/* ZAP */
++	DMU_OT_ACL,			/* ACL */
++	DMU_OT_SYSACL,			/* SYSACL */
++	DMU_OT_FUID,			/* FUID table (Packed NVLIST UINT8) */
++	DMU_OT_FUID_SIZE,		/* FUID table size UINT64 */
++	DMU_OT_NEXT_CLONES,		/* ZAP */
++	DMU_OT_SCRUB_QUEUE,		/* ZAP */
++	DMU_OT_USERGROUP_USED,		/* ZAP */
++	DMU_OT_USERGROUP_QUOTA,		/* ZAP */
++	DMU_OT_USERREFS,		/* ZAP */
++	DMU_OT_DDT_ZAP,			/* ZAP */
++	DMU_OT_DDT_STATS,		/* ZAP */
++	DMU_OT_SA,			/* System attr */
++	DMU_OT_SA_MASTER_NODE,		/* ZAP */
++	DMU_OT_SA_ATTR_REGISTRATION,	/* ZAP */
++	DMU_OT_SA_ATTR_LAYOUTS,		/* ZAP */
++	DMU_OT_NUMTYPES
++} dmu_object_type_t;
++
++typedef enum dmu_objset_type {
++	DMU_OST_NONE,
++	DMU_OST_META,
++	DMU_OST_ZFS,
++	DMU_OST_ZVOL,
++	DMU_OST_OTHER,			/* For testing only! */
++	DMU_OST_ANY,			/* Be careful! */
++	DMU_OST_NUMTYPES
++} dmu_objset_type_t;
++
++/*
++ * The names of zap entries in the DIRECTORY_OBJECT of the MOS.
++ */
++#define	DMU_POOL_DIRECTORY_OBJECT	1
++#define	DMU_POOL_CONFIG			"config"
++#define	DMU_POOL_ROOT_DATASET		"root_dataset"
++#define	DMU_POOL_SYNC_BPLIST		"sync_bplist"
++#define	DMU_POOL_ERRLOG_SCRUB		"errlog_scrub"
++#define	DMU_POOL_ERRLOG_LAST		"errlog_last"
++#define	DMU_POOL_SPARES			"spares"
++#define	DMU_POOL_DEFLATE		"deflate"
++#define	DMU_POOL_HISTORY		"history"
++#define	DMU_POOL_PROPS			"pool_props"
++#define	DMU_POOL_L2CACHE		"l2cache"
++
++#endif	/* _SYS_DMU_H */
+diff -urN grub.patch50/stage2/zfs-include/dmu_objset.h grub.zfs_solaris/stage2/zfs-include/dmu_objset.h
+--- grub.patch50/stage2/zfs-include/dmu_objset.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/dmu_objset.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,38 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_DMU_OBJSET_H
++#define	_SYS_DMU_OBJSET_H
++
++typedef struct objset_phys {
++	dnode_phys_t os_meta_dnode;
++	zil_header_t os_zil_header;
++	uint64_t os_type;
++	uint64_t os_flags;
++	char os_pad[2048 - sizeof (dnode_phys_t)*3 -
++	    sizeof (zil_header_t) - sizeof (uint64_t)*2];
++	dnode_phys_t os_userused_dnode;
++	dnode_phys_t os_groupused_dnode;
++} objset_phys_t;
++
++#endif /* _SYS_DMU_OBJSET_H */
+diff -urN grub.patch50/stage2/zfs-include/dnode.h grub.zfs_solaris/stage2/zfs-include/dnode.h
+--- grub.patch50/stage2/zfs-include/dnode.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/dnode.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,79 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_DNODE_H
++#define	_SYS_DNODE_H
++
++/*
++ * Fixed constants.
++ */
++#define	DNODE_SHIFT		9	/* 512 bytes */
++#define	DN_MIN_INDBLKSHIFT	10	/* 1k */
++#define	DN_MAX_INDBLKSHIFT	14	/* 16k */
++#define	DNODE_BLOCK_SHIFT	14	/* 16k */
++#define	DNODE_CORE_SIZE		64	/* 64 bytes for dnode sans blkptrs */
++#define	DN_MAX_OBJECT_SHIFT	48	/* 256 trillion (zfs_fid_t limit) */
++#define	DN_MAX_OFFSET_SHIFT	64	/* 2^64 bytes in a dnode */
++
++/*
++ * Derived constants.
++ */
++#define	DNODE_SIZE	(1 << DNODE_SHIFT)
++#define	DN_MAX_NBLKPTR	((DNODE_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT)
++#define	DN_MAX_BONUSLEN	(DNODE_SIZE - DNODE_CORE_SIZE - (1 << SPA_BLKPTRSHIFT))
++#define	DN_MAX_OBJECT	(1ULL << DN_MAX_OBJECT_SHIFT)
++
++#define	DNODES_PER_BLOCK_SHIFT	(DNODE_BLOCK_SHIFT - DNODE_SHIFT)
++#define	DNODES_PER_BLOCK	(1ULL << DNODES_PER_BLOCK_SHIFT)
++#define	DNODES_PER_LEVEL_SHIFT	(DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT)
++
++#define	DNODE_FLAG_SPILL_BLKPTR (1<<2)
++
++#define	DN_BONUS(dnp)	((void*)((dnp)->dn_bonus + \
++	(((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))
++
++typedef struct dnode_phys {
++	uint8_t dn_type;		/* dmu_object_type_t */
++	uint8_t dn_indblkshift;		/* ln2(indirect block size) */
++	uint8_t dn_nlevels;		/* 1=dn_blkptr->data blocks */
++	uint8_t dn_nblkptr;		/* length of dn_blkptr */
++	uint8_t dn_bonustype;		/* type of data in bonus buffer */
++	uint8_t	dn_checksum;		/* ZIO_CHECKSUM type */
++	uint8_t	dn_compress;		/* ZIO_COMPRESS type */
++	uint8_t dn_flags;		/* DNODE_FLAG_* */
++	uint16_t dn_datablkszsec;	/* data block size in 512b sectors */
++	uint16_t dn_bonuslen;		/* length of dn_bonus */
++	uint8_t dn_pad2[4];
++
++	/* accounting is protected by dn_dirty_mtx */
++	uint64_t dn_maxblkid;		/* largest allocated block ID */
++	uint64_t dn_used;		/* bytes (or sectors) of disk space */
++
++	uint64_t dn_pad3[4];
++
++	blkptr_t dn_blkptr[1];
++	uint8_t dn_bonus[DN_MAX_BONUSLEN - sizeof (blkptr_t)];
++	blkptr_t dn_spill;
++} dnode_phys_t;
++
++#endif	/* _SYS_DNODE_H */
+diff -urN grub.patch50/stage2/zfs-include/dsl_dataset.h grub.zfs_solaris/stage2/zfs-include/dsl_dataset.h
+--- grub.patch50/stage2/zfs-include/dsl_dataset.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/dsl_dataset.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,55 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_DSL_DATASET_H
++#define	_SYS_DSL_DATASET_H
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++typedef struct dsl_dataset_phys {
++	uint64_t ds_dir_obj;
++	uint64_t ds_prev_snap_obj;
++	uint64_t ds_prev_snap_txg;
++	uint64_t ds_next_snap_obj;
++	uint64_t ds_snapnames_zapobj;	/* zap obj of snaps; ==0 for snaps */
++	uint64_t ds_num_children;	/* clone/snap children; ==0 for head */
++	uint64_t ds_creation_time;	/* seconds since 1970 */
++	uint64_t ds_creation_txg;
++	uint64_t ds_deadlist_obj;
++	uint64_t ds_used_bytes;
++	uint64_t ds_compressed_bytes;
++	uint64_t ds_uncompressed_bytes;
++	uint64_t ds_unique_bytes;	/* only relevant to snapshots */
++	/*
++	 * The ds_fsid_guid is a 56-bit ID that can change to avoid
++	 * collisions.  The ds_guid is a 64-bit ID that will never
++	 * change, so there is a small probability that it will collide.
++	 */
++	uint64_t ds_fsid_guid;
++	uint64_t ds_guid;
++	uint64_t ds_flags;
++	blkptr_t ds_bp;
++	uint64_t ds_pad[8]; /* pad out to 320 bytes for good measure */
++} dsl_dataset_phys_t;
++
++#endif /* _SYS_DSL_DATASET_H */
+diff -urN grub.patch50/stage2/zfs-include/dsl_dir.h grub.zfs_solaris/stage2/zfs-include/dsl_dir.h
+--- grub.patch50/stage2/zfs-include/dsl_dir.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/dsl_dir.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,51 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_DSL_DIR_H
++#define	_SYS_DSL_DIR_H
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++typedef struct dsl_dir_phys {
++	uint64_t dd_creation_time; /* not actually used */
++	uint64_t dd_head_dataset_obj;
++	uint64_t dd_parent_obj;
++	uint64_t dd_clone_parent_obj;
++	uint64_t dd_child_dir_zapobj;
++	/*
++	 * how much space our children are accounting for; for leaf
++	 * datasets, == physical space used by fs + snaps
++	 */
++	uint64_t dd_used_bytes;
++	uint64_t dd_compressed_bytes;
++	uint64_t dd_uncompressed_bytes;
++	/* Administrative quota setting */
++	uint64_t dd_quota;
++	/* Administrative reservation setting */
++	uint64_t dd_reserved;
++	uint64_t dd_props_zapobj;
++	uint64_t dd_deleg_zapobj;	/* dataset permissions */
++	uint64_t dd_pad[20]; /* pad out to 256 bytes for good measure */
++} dsl_dir_phys_t;
++
++#endif /* _SYS_DSL_DIR_H */
+diff -urN grub.patch50/stage2/zfs-include/sa_impl.h grub.zfs_solaris/stage2/zfs-include/sa_impl.h
+--- grub.patch50/stage2/zfs-include/sa_impl.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/sa_impl.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,35 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++#ifndef	_SYS_SA_IMPL_H
++#define	_SYS_SA_IMPL_H
++
++typedef struct sa_hdr_phys {
++	uint32_t sa_magic;
++	uint16_t sa_layout_info;
++	uint16_t sa_lengths[1];
++} sa_hdr_phys_t;
++
++#define	SA_HDR_SIZE(hdr)	BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0)
++#define	SA_SIZE_OFFSET	0x8
++
++#endif	/* _SYS_SA_IMPL_H */
+diff -urN grub.patch50/stage2/zfs-include/spa.h grub.zfs_solaris/stage2/zfs-include/spa.h
+--- grub.patch50/stage2/zfs-include/spa.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/spa.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,352 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#ifndef _SYS_SPA_H
++#define	_SYS_SPA_H
++
++/*
++ * General-purpose 32-bit and 64-bit bitfield encodings.
++ */
++#define	BF32_DECODE(x, low, len)	P2PHASE((x) >> (low), 1U << (len))
++#define	BF64_DECODE(x, low, len)	P2PHASE((x) >> (low), 1ULL << (len))
++#define	BF32_ENCODE(x, low, len)	(P2PHASE((x), 1U << (len)) << (low))
++#define	BF64_ENCODE(x, low, len)	(P2PHASE((x), 1ULL << (len)) << (low))
++
++#define	BF32_GET(x, low, len)		BF32_DECODE(x, low, len)
++#define	BF64_GET(x, low, len)		BF64_DECODE(x, low, len)
++
++#define	BF32_SET(x, low, len, val)	\
++	((x) ^= BF32_ENCODE((x >> low) ^ (val), low, len))
++#define	BF64_SET(x, low, len, val)	\
++	((x) ^= BF64_ENCODE((x >> low) ^ (val), low, len))
++
++#define	BF32_GET_SB(x, low, len, shift, bias)	\
++	((BF32_GET(x, low, len) + (bias)) << (shift))
++#define	BF64_GET_SB(x, low, len, shift, bias)	\
++	((BF64_GET(x, low, len) + (bias)) << (shift))
++
++#define	BF32_SET_SB(x, low, len, shift, bias, val)	\
++	BF32_SET(x, low, len, ((val) >> (shift)) - (bias))
++#define	BF64_SET_SB(x, low, len, shift, bias, val)	\
++	BF64_SET(x, low, len, ((val) >> (shift)) - (bias))
++
++/*
++ * We currently support nine block sizes, from 512 bytes to 128K.
++ * We could go higher, but the benefits are near-zero and the cost
++ * of COWing a giant block to modify one byte would become excessive.
++ */
++#define	SPA_MINBLOCKSHIFT	9
++#define	SPA_MAXBLOCKSHIFT	17
++#define	SPA_MINBLOCKSIZE	(1ULL << SPA_MINBLOCKSHIFT)
++#define	SPA_MAXBLOCKSIZE	(1ULL << SPA_MAXBLOCKSHIFT)
++
++#define	SPA_BLOCKSIZES		(SPA_MAXBLOCKSHIFT - SPA_MINBLOCKSHIFT + 1)
++
++/*
++ * Size of block to hold the configuration data (a packed nvlist)
++ */
++#define	SPA_CONFIG_BLOCKSIZE	(1 << 14)
++
++/*
++ * The DVA size encodings for LSIZE and PSIZE support blocks up to 32MB.
++ * The ASIZE encoding should be at least 64 times larger (6 more bits)
++ * to support up to 4-way RAID-Z mirror mode with worst-case gang block
++ * overhead, three DVAs per bp, plus one more bit in case we do anything
++ * else that expands the ASIZE.
++ */
++#define	SPA_LSIZEBITS		16	/* LSIZE up to 32M (2^16 * 512)	*/
++#define	SPA_PSIZEBITS		16	/* PSIZE up to 32M (2^16 * 512)	*/
++#define	SPA_ASIZEBITS		24	/* ASIZE up to 64 times larger	*/
++
++/*
++ * All SPA data is represented by 128-bit data virtual addresses (DVAs).
++ * The members of the dva_t should be considered opaque outside the SPA.
++ */
++typedef struct dva {
++	uint64_t	dva_word[2];
++} dva_t;
++
++/*
++ * Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
++ */
++typedef struct zio_cksum {
++	uint64_t	zc_word[4];
++} zio_cksum_t;
++
++/*
++ * Each block is described by its DVAs, time of birth, checksum, etc.
++ * The word-by-word, bit-by-bit layout of the blkptr is as follows:
++ *
++ *	64	56	48	40	32	24	16	8	0
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 0	|		vdev1		|ncopy|L|	  ASIZE		|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 1	|G|			 offset1				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 2	|		vdev2		|ncopy|L|	  ASIZE		|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 3	|G|			 offset2				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 4	|		vdev3		|ncopy|L|	  ASIZE		|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 5	|G|			 offset3				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 6	|BDE|lvl| type	| cksum | comp	|     PSIZE	|     LSIZE	|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 7	|                       padding                                 |
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 8	|			padding					|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * 9	|			physical birth txg			|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * a	|			logical birth txg			|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * b	|			fill count				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * c	|			checksum[0]				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * d	|			checksum[1]				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * e	|			checksum[2]				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ * f	|			checksum[3]				|
++ *	+-------+-------+-------+-------+-------+-------+-------+-------+
++ *
++ * Legend:
++ *
++ * vdev		virtual device ID
++ * offset	offset into virtual device
++ * LSIZE	logical size
++ * PSIZE	physical size (after compression)
++ * ASIZE	allocated size (including RAID-Z parity and gang block headers)
++ * L		layout (e.g. standard vs. RAID-Z/mirror hybrid)
++ * ncopy	number of copies if RAID-Z, otherwise 1
++ * cksum	checksum function
++ * comp		compression function
++ * G		gang block indicator
++ * B		byteorder (endianness)
++ * D		dedup
++ * E		encryption
++ * lvl		level of indirection
++ * type		DMU object type
++ * phys birth	txg of block allocation; zero if same as logical birth txg
++ * log. birth	transaction group in which the block was logically born
++ * fill count	number of non-zero blocks under this bp
++ * checksum[4]	256-bit checksum of the data this bp describes
++ *
++ * Special notes for encryption:
++ *
++ * A single bit is used to indicate if the block is encrypted.  This is
++ * sufficient since all blocks in a dataset always share the same encryption
++ * algorithm-keylen-mode.
++ *
++ * When encryption is enabled blk_dva[2] holds the IV.
++ * When encryption is enabled level 0 blocks checksum[2] and checksum[3] hold
++ * the MAC output from the encryption and the normal checksum is truncated
++ * and stored in checksum[0] and checksum[1].
++ *
++ */
++#define	SPA_BLKPTRSHIFT	7		/* blkptr_t is 128 bytes	*/
++#define	SPA_DVAS_PER_BP	3		/* Number of DVAs in a bp	*/
++
++typedef struct blkptr {
++	dva_t		blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */
++	uint64_t	blk_prop;	/* size, compression, type, etc	    */
++	uint64_t	blk_pad[2];	/* Extra space for the future	    */
++	uint64_t	blk_phys_birth;	/* txg when block was allocated	    */
++	uint64_t	blk_birth;	/* transaction group at birth	    */
++	uint64_t	blk_fill;	/* fill count			    */
++	zio_cksum_t	blk_cksum;	/* 256-bit checksum		    */
++} blkptr_t;
++
++/*
++ * DVA layouts.  Normally mirror vdevs contain mirrored data, RAID-Z vdevs
++ * contain RAID-Z data, etc.  However, for latency-sensitive metadata,
++ * we can use a mirrored layout across the children of a RAID-Z vdev.
++ * This ensures that such metadata can be read in a single I/O.
++ */
++typedef enum dva_layout {
++	DVA_LAYOUT_STANDARD = 0,
++	DVA_LAYOUT_RAIDZ_MIRROR
++} dva_layout_t;
++
++/*
++ * Macros to get and set fields in a bp or DVA.
++ */
++#define	DVA_GET_ASIZE(dva)	\
++	BF64_GET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0)
++#define	DVA_SET_ASIZE(dva, x)	\
++	BF64_SET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0, x)
++
++#define	DVA_GET_LAYOUT(dva)	BF64_GET((dva)->dva_word[0], 24, 2)
++#define	DVA_SET_LAYOUT(dva, x)	BF64_SET((dva)->dva_word[0], 24, 2, x)
++
++#define	DVA_GET_COPIES(dva)	BF64_GET_SB((dva)->dva_word[0], 26, 6, 0, 1)
++#define	DVA_SET_COPIES(dva, x)	BF64_SET_SB((dva)->dva_word[0], 26, 6, 0, 1, x)
++
++#define	DVA_MAX_COPIES		(1ULL << 6)
++#define	DVA_MAX_INFLATION	(4ULL)
++
++#define	DVA_GET_VDEV(dva)	BF64_GET((dva)->dva_word[0], 32, 32)
++#define	DVA_SET_VDEV(dva, x)	BF64_SET((dva)->dva_word[0], 32, 32, x)
++
++#define	DVA_GET_OFFSET(dva)	\
++	BF64_GET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)
++#define	DVA_SET_OFFSET(dva, x)	\
++	BF64_SET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0, x)
++
++#define	DVA_GET_GANG(dva)	BF64_GET((dva)->dva_word[1], 63, 1)
++#define	DVA_SET_GANG(dva, x)	BF64_SET((dva)->dva_word[1], 63, 1, x)
++
++#define	DVA_EQUAL(dva1, dva2)	\
++	((dva1)->dva_word[1] == (dva2)->dva_word[1] && \
++	(dva1)->dva_word[0] == (dva2)->dva_word[0])
++
++#define	DVA_IS_VALID(dva)	(DVA_GET_ASIZE(dva) != 0)
++
++#define	DVA_VALID_COPIES(dva)	\
++	(DVA_IS_VALID(dva) ? DVA_GET_COPIES(dva) : 0)
++
++#define	BP_GET_LSIZE(bp)	\
++	BF64_GET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1)
++#define	BP_SET_LSIZE(bp, x)	\
++	BF64_SET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1, x)
++
++#define	BP_GET_PSIZE(bp)	\
++	BF64_GET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1)
++#define	BP_SET_PSIZE(bp, x)	\
++	BF64_SET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1, x)
++
++#define	BP_GET_COMPRESS(bp)		BF64_GET((bp)->blk_prop, 32, 8)
++#define	BP_SET_COMPRESS(bp, x)		BF64_SET((bp)->blk_prop, 32, 8, x)
++
++#define	BP_GET_CHECKSUM(bp)		BF64_GET((bp)->blk_prop, 40, 8)
++#define	BP_SET_CHECKSUM(bp, x)		BF64_SET((bp)->blk_prop, 40, 8, x)
++
++#define	BP_GET_TYPE(bp)			BF64_GET((bp)->blk_prop, 48, 8)
++#define	BP_SET_TYPE(bp, x)		BF64_SET((bp)->blk_prop, 48, 8, x)
++
++#define	BP_GET_LEVEL(bp)		BF64_GET((bp)->blk_prop, 56, 5)
++#define	BP_SET_LEVEL(bp, x)		BF64_SET((bp)->blk_prop, 56, 5, x)
++
++#define	BP_GET_CRYPT(bp)		BF64_GET((bp)->blk_prop, 61, 1)
++#define	BP_SET_CRYPT(bp, x)		BF64_SET((bp)->blk_prop, 61, 1, x)
++#define	BP_IS_ENCRYPTED(bp)		(0 - BP_GET_CRYPT_FLAG(bp))
++
++#define	BP_GET_DEDUP(bp)		BF64_GET((bp)->blk_prop, 62, 1)
++#define	BP_SET_DEDUP(bp, x)		BF64_SET((bp)->blk_prop, 62, 1, x)
++
++#define	BP_GET_BYTEORDER(bp)		(0 - BF64_GET((bp)->blk_prop, 63, 1))
++#define	BP_SET_BYTEORDER(bp, x)		BF64_SET((bp)->blk_prop, 63, 1, x)
++
++#define	BP_PHYSICAL_BIRTH(bp)		\
++	((bp)->blk_phys_birth ? (bp)->blk_phys_birth : (bp)->blk_birth)
++
++#define	BP_SET_BIRTH(bp, logical, physical)	\
++{						\
++	(bp)->blk_birth = (logical);		\
++	(bp)->blk_phys_birth = ((logical) == (physical) ? 0 : (physical)); \
++}
++
++#define	BP_GET_UCSIZE(bp) \
++	((BP_GET_LEVEL(bp) > 0 || dmu_ot[BP_GET_TYPE(bp)].ot_metadata) ? \
++	BP_GET_PSIZE(bp) : BP_GET_LSIZE(bp))
++
++#define	BP_GET_ASIZE(bp)			\
++	(DVA_GET_ASIZE(&(bp)->blk_dva[0]) +	\
++	DVA_GET_ASIZE(&(bp)->blk_dva[1]) +	\
++	(BP_IS_ENCRYPTED(bp) ? 0 : DVA_GET_ASIZE(&(bp)->blk_dva[2])))
++
++#define	BP_GET_NDVAS(bp)			\
++	(DVA_IS_VALID(&(bp)->blk_dva[0]) +	\
++	DVA_IS_VALID(&(bp)->blk_dva[1]) +	\
++	(BP_IS_ENCRYPTED(bp) ? 0 : DVA_IS_VALID(&(bp)->blk_dva[2])))
++
++#define	BP_GET_COPIES(bp)			\
++	(DVA_VALID_COPIES(&(bp)->blk_dva[0]) +	\
++	DVA_VALID_COPIES(&(bp)->blk_dva[1]) +	\
++	(BP_IS_ENCRYPTED(bp) ? 0 : DVA_VALID_COPIES(&(bp)->blk_dva[2])))
++
++#define	BP_COUNT_GANG(bp)			\
++	(DVA_GET_GANG(&(bp)->blk_dva[0]) +	\
++	DVA_GET_GANG(&(bp)->blk_dva[1]) +	\
++	(BP_IS_ENCRYPTED(bp) ? 0 : DVA_GET_GANG(&(bp)->blk_dva[2])))
++
++#define	BP_EQUAL(bp1, bp2)	\
++	(BP_PHYSICAL_BIRTH(bp1) == BP_PHYSICAL_BIRTH(bp2) &&	\
++	DVA_EQUAL(&(bp1)->blk_dva[0], &(bp2)->blk_dva[0]) &&	\
++	DVA_EQUAL(&(bp1)->blk_dva[1], &(bp2)->blk_dva[1]) &&	\
++	DVA_EQUAL(&(bp1)->blk_dva[2], &(bp2)->blk_dva[2]))
++
++#define	ZIO_CHECKSUM_EQUAL(zc1, zc2) \
++	(0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \
++	((zc1).zc_word[1] - (zc2).zc_word[1]) | \
++	((zc1).zc_word[2] - (zc2).zc_word[2]) | \
++	((zc1).zc_word[3] - (zc2).zc_word[3])))
++
++#define	ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3)	\
++{						\
++	(zcp)->zc_word[0] = w0;			\
++	(zcp)->zc_word[1] = w1;			\
++	(zcp)->zc_word[2] = w2;			\
++	(zcp)->zc_word[3] = w3;			\
++}
++
++#define	BP_IDENTITY(bp)		(&(bp)->blk_dva[0])
++#define	BP_IS_GANG(bp)		DVA_GET_GANG(BP_IDENTITY(bp))
++#define	BP_IS_HOLE(bp)		((bp)->blk_birth == 0)
++
++/* BP_IS_RAIDZ(bp) assumes no block compression */
++#define	BP_IS_RAIDZ(bp)		(DVA_GET_ASIZE(&(bp)->blk_dva[0]) > \
++				BP_GET_PSIZE(bp))
++
++#define	BP_ZERO(bp)				\
++{						\
++	(bp)->blk_dva[0].dva_word[0] = 0;	\
++	(bp)->blk_dva[0].dva_word[1] = 0;	\
++	(bp)->blk_dva[1].dva_word[0] = 0;	\
++	(bp)->blk_dva[1].dva_word[1] = 0;	\
++	(bp)->blk_dva[2].dva_word[0] = 0;	\
++	(bp)->blk_dva[2].dva_word[1] = 0;	\
++	(bp)->blk_prop = 0;			\
++	(bp)->blk_pad[0] = 0;			\
++	(bp)->blk_pad[1] = 0;			\
++	(bp)->blk_phys_birth = 0;		\
++	(bp)->blk_birth = 0;			\
++	(bp)->blk_fill = 0;			\
++	ZIO_SET_CHECKSUM(&(bp)->blk_cksum, 0, 0, 0, 0);	\
++}
++/*
++ * Note: the byteorder is either 0 or -1, both of which are palindromes.
++ * This simplifies the endianness handling a bit.
++ */
++#ifdef _BIG_ENDIAN
++#define	ZFS_HOST_BYTEORDER	(0ULL)
++#else
++#define	ZFS_HOST_BYTEORDER	(-1ULL)
++#endif
++
++#define	BP_SHOULD_BYTESWAP(bp)	(BP_GET_BYTEORDER(bp) != ZFS_HOST_BYTEORDER)
++
++#define	BP_SPRINTF_LEN	360
++
++#endif	/* _SYS_SPA_H */
+diff -urN grub.patch50/stage2/zfs-include/uberblock_impl.h grub.zfs_solaris/stage2/zfs-include/uberblock_impl.h
+--- grub.patch50/stage2/zfs-include/uberblock_impl.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/uberblock_impl.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,51 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef _SYS_UBERBLOCK_IMPL_H
++#define	_SYS_UBERBLOCK_IMPL_H
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++/*
++ * The uberblock version is incremented whenever an incompatible on-disk
++ * format change is made to the SPA, DMU, or ZAP.
++ *
++ * Note: the first two fields should never be moved.  When a storage pool
++ * is opened, the uberblock must be read off the disk before the version
++ * can be checked.  If the ub_version field is moved, we may not detect
++ * version mismatch.  If the ub_magic field is moved, applications that
++ * expect the magic number in the first word won't work.
++ */
++#define	UBERBLOCK_MAGIC		0x00bab10c		/* oo-ba-bloc!	*/
++#define	UBERBLOCK_SHIFT		10			/* up to 1K	*/
++
++struct uberblock {
++	uint64_t	ub_magic;	/* UBERBLOCK_MAGIC		*/
++	uint64_t	ub_version;	/* ZFS_VERSION			*/
++	uint64_t	ub_txg;		/* txg of last sync		*/
++	uint64_t	ub_guid_sum;	/* sum of all vdev guids	*/
++	uint64_t	ub_timestamp;	/* UTC time of last sync	*/
++	blkptr_t	ub_rootbp;	/* MOS objset_phys_t		*/
++};
++
++#endif	/* _SYS_UBERBLOCK_IMPL_H */
+diff -urN grub.patch50/stage2/zfs-include/vdev_impl.h grub.zfs_solaris/stage2/zfs-include/vdev_impl.h
+--- grub.patch50/stage2/zfs-include/vdev_impl.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/vdev_impl.h	2011-10-12 19:58:29.055921310 +0200
+@@ -0,0 +1,59 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef _SYS_VDEV_IMPL_H
++#define	_SYS_VDEV_IMPL_H
++
++#define	VDEV_PAD_SIZE 		(8 << 10)
++/* 2 padding areas (vl_pad1 and vl_pad2) to skip */
++#define	VDEV_SKIP_SIZE		VDEV_PAD_SIZE * 2
++#define	VDEV_PHYS_SIZE		(112 << 10)
++#define	VDEV_UBERBLOCK_RING	(128 << 10)
++
++typedef struct vdev_phys {
++	char		vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)];
++	zio_eck_t	vp_zbt;
++} vdev_phys_t;
++
++typedef struct vdev_label {
++	char		vl_pad1[VDEV_PAD_SIZE];			/*  8K	*/
++	char		vl_pad2[VDEV_PAD_SIZE];			/*  8K	*/
++	vdev_phys_t	vl_vdev_phys;				/* 112K	*/
++	char		vl_uberblock[VDEV_UBERBLOCK_RING];	/* 128K	*/
++} vdev_label_t;							/* 256K total */
++
++/*
++ * Size and offset of embedded boot loader region on each label.
++ * The total size of the first two labels plus the boot area is 4MB.
++ */
++#define	VDEV_BOOT_OFFSET	(2 * sizeof (vdev_label_t))
++#define	VDEV_BOOT_SIZE		(7ULL << 19)			/* 3.5M	*/
++
++/*
++ * Size of label regions at the start and end of each leaf device.
++ */
++#define	VDEV_LABEL_START_SIZE	(2 * sizeof (vdev_label_t) + VDEV_BOOT_SIZE)
++#define	VDEV_LABEL_END_SIZE	(2 * sizeof (vdev_label_t))
++#define	VDEV_LABELS		4
++
++#endif	/* _SYS_VDEV_IMPL_H */
+diff -urN grub.patch50/stage2/zfs-include/zap_impl.h grub.zfs_solaris/stage2/zfs-include/zap_impl.h
+--- grub.patch50/stage2/zfs-include/zap_impl.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zap_impl.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,111 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_ZAP_IMPL_H
++#define	_SYS_ZAP_IMPL_H
++
++#define	ZAP_MAGIC 0x2F52AB2ABULL
++
++#define	MZAP_ENT_LEN		64
++#define	MZAP_NAME_LEN		(MZAP_ENT_LEN - 8 - 4 - 2)
++#define	MZAP_MAX_BLKSHIFT	SPA_MAXBLOCKSHIFT
++#define	MZAP_MAX_BLKSZ		(1 << MZAP_MAX_BLKSHIFT)
++
++typedef struct mzap_ent_phys {
++	uint64_t mze_value;
++	uint32_t mze_cd;
++	uint16_t mze_pad;	/* in case we want to chain them someday */
++	char mze_name[MZAP_NAME_LEN];
++} mzap_ent_phys_t;
++
++typedef struct mzap_phys {
++	uint64_t mz_block_type;	/* ZBT_MICRO */
++	uint64_t mz_salt;
++	uint64_t mz_pad[6];
++	mzap_ent_phys_t mz_chunk[1];
++	/* actually variable size depending on block size */
++} mzap_phys_t;
++
++/*
++ * The (fat) zap is stored in one object. It is an array of
++ * 1<<FZAP_BLOCK_SHIFT byte blocks. The layout looks like one of:
++ *
++ * ptrtbl fits in first block:
++ * 	[zap_phys_t zap_ptrtbl_shift < 6] [zap_leaf_t] ...
++ *
++ * ptrtbl too big for first block:
++ * 	[zap_phys_t zap_ptrtbl_shift >= 6] [zap_leaf_t] [ptrtbl] ...
++ *
++ */
++
++#define	ZBT_LEAF		((1ULL << 63) + 0)
++#define	ZBT_HEADER		((1ULL << 63) + 1)
++#define	ZBT_MICRO		((1ULL << 63) + 3)
++/* any other values are ptrtbl blocks */
++
++/*
++ * the embedded pointer table takes up half a block:
++ * block size / entry size (2^3) / 2
++ */
++#define	ZAP_EMBEDDED_PTRTBL_SHIFT(zap) (FZAP_BLOCK_SHIFT(zap) - 3 - 1)
++
++/*
++ * The embedded pointer table starts half-way through the block.  Since
++ * the pointer table itself is half the block, it starts at (64-bit)
++ * word number (1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap)).
++ */
++#define	ZAP_EMBEDDED_PTRTBL_ENT(zap, idx) \
++	((uint64_t *)(zap)->zap_f.zap_phys) \
++	[(idx) + (1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap))]
++
++/*
++ * TAKE NOTE:
++ * If zap_phys_t is modified, zap_byteswap() must be modified.
++ */
++typedef struct zap_phys {
++	uint64_t zap_block_type;	/* ZBT_HEADER */
++	uint64_t zap_magic;		/* ZAP_MAGIC */
++
++	struct zap_table_phys {
++		uint64_t zt_blk;	/* starting block number */
++		uint64_t zt_numblks;	/* number of blocks */
++		uint64_t zt_shift;	/* bits to index it */
++		uint64_t zt_nextblk;	/* next (larger) copy start block */
++		uint64_t zt_blks_copied; /* number source blocks copied */
++	} zap_ptrtbl;
++
++	uint64_t zap_freeblk;		/* the next free block */
++	uint64_t zap_num_leafs;		/* number of leafs */
++	uint64_t zap_num_entries;	/* number of entries */
++	uint64_t zap_salt;		/* salt to stir into hash function */
++	uint64_t zap_normflags;		/* flags for u8_textprep_str() */
++	uint64_t zap_flags;		/* zap_flag_t */
++	/*
++	 * This structure is followed by padding, and then the embedded
++	 * pointer table.  The embedded pointer table takes up second
++	 * half of the block.  It is accessed using the
++	 * ZAP_EMBEDDED_PTRTBL_ENT() macro.
++	 */
++} zap_phys_t;
++
++#endif /* _SYS_ZAP_IMPL_H */
+diff -urN grub.patch50/stage2/zfs-include/zap_leaf.h grub.zfs_solaris/stage2/zfs-include/zap_leaf.h
+--- grub.patch50/stage2/zfs-include/zap_leaf.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zap_leaf.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,102 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_ZAP_LEAF_H
++#define	_SYS_ZAP_LEAF_H
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++#define	ZAP_LEAF_MAGIC 0x2AB1EAF
++
++/* chunk size = 24 bytes */
++#define	ZAP_LEAF_CHUNKSIZE 24
++
++/*
++ * The amount of space within the chunk available for the array is:
++ * chunk size - space for type (1) - space for next pointer (2)
++ */
++#define	ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3)
++
++typedef enum zap_chunk_type {
++	ZAP_CHUNK_FREE = 253,
++	ZAP_CHUNK_ENTRY = 252,
++	ZAP_CHUNK_ARRAY = 251,
++	ZAP_CHUNK_TYPE_MAX = 250
++} zap_chunk_type_t;
++
++/*
++ * TAKE NOTE:
++ * If zap_leaf_phys_t is modified, zap_leaf_byteswap() must be modified.
++ */
++typedef struct zap_leaf_phys {
++	struct zap_leaf_header {
++		uint64_t lh_block_type;		/* ZBT_LEAF */
++		uint64_t lh_pad1;
++		uint64_t lh_prefix;		/* hash prefix of this leaf */
++		uint32_t lh_magic;		/* ZAP_LEAF_MAGIC */
++		uint16_t lh_nfree;		/* number free chunks */
++		uint16_t lh_nentries;		/* number of entries */
++		uint16_t lh_prefix_len;		/* num bits used to id this */
++
++/* above is accessable to zap, below is zap_leaf private */
++
++		uint16_t lh_freelist;		/* chunk head of free list */
++		uint8_t lh_pad2[12];
++	} l_hdr; /* 2 24-byte chunks */
++
++	/*
++	 * The header is followed by a hash table with
++	 * ZAP_LEAF_HASH_NUMENTRIES(zap) entries.  The hash table is
++	 * followed by an array of ZAP_LEAF_NUMCHUNKS(zap)
++	 * zap_leaf_chunk structures.  These structures are accessed
++	 * with the ZAP_LEAF_CHUNK() macro.
++	 */
++
++	uint16_t l_hash[1];
++} zap_leaf_phys_t;
++
++typedef union zap_leaf_chunk {
++	struct zap_leaf_entry {
++		uint8_t le_type; 		/* always ZAP_CHUNK_ENTRY */
++		uint8_t le_int_size;		/* size of ints */
++		uint16_t le_next;		/* next entry in hash chain */
++		uint16_t le_name_chunk;		/* first chunk of the name */
++		uint16_t le_name_length;	/* bytes in name, incl null */
++		uint16_t le_value_chunk;	/* first chunk of the value */
++		uint16_t le_value_length;	/* value length in ints */
++		uint32_t le_cd;			/* collision differentiator */
++		uint64_t le_hash;		/* hash value of the name */
++	} l_entry;
++	struct zap_leaf_array {
++		uint8_t la_type;		/* always ZAP_CHUNK_ARRAY */
++		uint8_t la_array[ZAP_LEAF_ARRAY_BYTES];
++		uint16_t la_next;		/* next blk or CHAIN_END */
++	} l_array;
++	struct zap_leaf_free {
++		uint8_t lf_type;		/* always ZAP_CHUNK_FREE */
++		uint8_t lf_pad[ZAP_LEAF_ARRAY_BYTES];
++		uint16_t lf_next;	/* next in free list, or CHAIN_END */
++	} l_free;
++} zap_leaf_chunk_t;
++
++#endif /* _SYS_ZAP_LEAF_H */
+diff -urN grub.patch50/stage2/zfs-include/zfs.h grub.zfs_solaris/stage2/zfs-include/zfs.h
+--- grub.patch50/stage2/zfs-include/zfs.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zfs.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,107 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#ifndef	_SYS_FS_ZFS_H
++#define	_SYS_FS_ZFS_H
++
++/*
++ * On-disk version number.
++ */
++#define	SPA_VERSION			31ULL
++
++/*
++ * The following are configuration names used in the nvlist describing a pool's
++ * configuration.
++ */
++#define	ZPOOL_CONFIG_VERSION		"version"
++#define	ZPOOL_CONFIG_POOL_NAME		"name"
++#define	ZPOOL_CONFIG_POOL_STATE		"state"
++#define	ZPOOL_CONFIG_POOL_TXG		"txg"
++#define	ZPOOL_CONFIG_POOL_GUID		"pool_guid"
++#define	ZPOOL_CONFIG_CREATE_TXG		"create_txg"
++#define	ZPOOL_CONFIG_TOP_GUID		"top_guid"
++#define	ZPOOL_CONFIG_VDEV_TREE		"vdev_tree"
++#define	ZPOOL_CONFIG_TYPE		"type"
++#define	ZPOOL_CONFIG_CHILDREN		"children"
++#define	ZPOOL_CONFIG_ID			"id"
++#define	ZPOOL_CONFIG_GUID		"guid"
++#define	ZPOOL_CONFIG_PATH		"path"
++#define	ZPOOL_CONFIG_DEVID		"devid"
++#define	ZPOOL_CONFIG_METASLAB_ARRAY	"metaslab_array"
++#define	ZPOOL_CONFIG_METASLAB_SHIFT	"metaslab_shift"
++#define	ZPOOL_CONFIG_ASHIFT		"ashift"
++#define	ZPOOL_CONFIG_ASIZE		"asize"
++#define	ZPOOL_CONFIG_DTL		"DTL"
++#define	ZPOOL_CONFIG_STATS		"stats"
++#define	ZPOOL_CONFIG_WHOLE_DISK		"whole_disk"
++#define	ZPOOL_CONFIG_ERRCOUNT		"error_count"
++#define	ZPOOL_CONFIG_NOT_PRESENT	"not_present"
++#define	ZPOOL_CONFIG_SPARES		"spares"
++#define	ZPOOL_CONFIG_IS_SPARE		"is_spare"
++#define	ZPOOL_CONFIG_NPARITY		"nparity"
++#define	ZPOOL_CONFIG_PHYS_PATH		"phys_path"
++#define	ZPOOL_CONFIG_L2CACHE		"l2cache"
++#define	ZPOOL_CONFIG_HOLE_ARRAY		"hole_array"
++#define	ZPOOL_CONFIG_VDEV_CHILDREN	"vdev_children"
++#define	ZPOOL_CONFIG_IS_HOLE		"is_hole"
++#define	ZPOOL_CONFIG_DDT_HISTOGRAM	"ddt_histogram"
++#define	ZPOOL_CONFIG_DDT_OBJ_STATS	"ddt_object_stats"
++#define	ZPOOL_CONFIG_DDT_STATS		"ddt_stats"
++/*
++ * The persistent vdev state is stored as separate values rather than a single
++ * 'vdev_state' entry.  This is because a device can be in multiple states, such
++ * as offline and degraded.
++ */
++#define	ZPOOL_CONFIG_OFFLINE		"offline"
++#define	ZPOOL_CONFIG_FAULTED		"faulted"
++#define	ZPOOL_CONFIG_DEGRADED		"degraded"
++#define	ZPOOL_CONFIG_REMOVED		"removed"
++
++#define	VDEV_TYPE_ROOT			"root"
++#define	VDEV_TYPE_MIRROR		"mirror"
++#define	VDEV_TYPE_REPLACING		"replacing"
++#define	VDEV_TYPE_RAIDZ			"raidz"
++#define	VDEV_TYPE_DISK			"disk"
++#define	VDEV_TYPE_FILE			"file"
++#define	VDEV_TYPE_MISSING		"missing"
++#define	VDEV_TYPE_HOLE			"hole"
++#define	VDEV_TYPE_SPARE			"spare"
++#define	VDEV_TYPE_L2CACHE		"l2cache"
++
++/*
++ * pool state.  The following states are written to disk as part of the normal
++ * SPA lifecycle: ACTIVE, EXPORTED, DESTROYED, SPARE, L2CACHE.  The remaining
++ * states are software abstractions used at various levels to communicate pool
++ * state.
++ */
++typedef enum pool_state {
++	POOL_STATE_ACTIVE = 0,		/* In active use		*/
++	POOL_STATE_EXPORTED,		/* Explicitly exported		*/
++	POOL_STATE_DESTROYED,		/* Explicitly destroyed		*/
++	POOL_STATE_SPARE,		/* Reserved for hot spare use	*/
++	POOL_STATE_L2CACHE,		/* Level 2 ARC device		*/
++	POOL_STATE_UNINITIALIZED,	/* Internal spa_t state		*/
++	POOL_STATE_UNAVAIL,		/* Internal libzfs state	*/
++	POOL_STATE_POTENTIALLY_ACTIVE	/* Internal libzfs state	*/
++} pool_state_t;
++
++#endif	/* _SYS_FS_ZFS_H */
+diff -urN grub.patch50/stage2/zfs-include/zfs_acl.h grub.zfs_solaris/stage2/zfs-include/zfs_acl.h
+--- grub.patch50/stage2/zfs-include/zfs_acl.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zfs_acl.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,64 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_FS_ZFS_ACL_H
++#define	_SYS_FS_ZFS_ACL_H
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++#ifndef __MINIOS__
++#ifndef _UID_T
++#define	_UID_T
++typedef	unsigned int uid_t;			/* UID type */
++#endif /* _UID_T */
++#endif /* __MINIOS__ */
++
++typedef struct zfs_oldace {
++	uint32_t	z_fuid;		/* "who" */
++	uint32_t	z_access_mask;  /* access mask */
++	uint16_t	z_flags;	/* flags, i.e inheritance */
++	uint16_t	z_type;		/* type of entry allow/deny */
++} zfs_oldace_t;
++
++#define	ACE_SLOT_CNT	6
++
++typedef struct zfs_znode_acl_v0 {
++	uint64_t	z_acl_extern_obj;	  /* ext acl pieces */
++	uint32_t	z_acl_count;		  /* Number of ACEs */
++	uint16_t	z_acl_version;		  /* acl version */
++	uint16_t	z_acl_pad;		  /* pad */
++	zfs_oldace_t	z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
++} zfs_znode_acl_v0_t;
++
++#define	ZFS_ACE_SPACE	(sizeof (zfs_oldace_t) * ACE_SLOT_CNT)
++
++typedef struct zfs_znode_acl {
++	uint64_t	z_acl_extern_obj;	  /* ext acl pieces */
++	uint32_t	z_acl_size;		  /* Number of bytes in ACL */
++	uint16_t	z_acl_version;		  /* acl version */
++	uint16_t	z_acl_count;		  /* ace count */
++	uint8_t		z_ace_data[ZFS_ACE_SPACE]; /* space for embedded ACEs */
++} zfs_znode_acl_t;
++
++
++#endif	/* _SYS_FS_ZFS_ACL_H */
+diff -urN grub.patch50/stage2/zfs-include/zfs_znode.h grub.zfs_solaris/stage2/zfs-include/zfs_znode.h
+--- grub.patch50/stage2/zfs-include/zfs_znode.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zfs_znode.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,69 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_FS_ZFS_ZNODE_H
++#define	_SYS_FS_ZFS_ZNODE_H
++
++#define	MASTER_NODE_OBJ	1
++#define	ZFS_ROOT_OBJ		"ROOT"
++#define	ZPL_VERSION_STR		"VERSION"
++#define	ZFS_SA_ATTRS		"SA_ATTRS"
++
++#define	ZPL_VERSION		5ULL
++
++#define	ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48)
++
++/*
++ * This is the persistent portion of the znode.  It is stored
++ * in the "bonus buffer" of the file.  Short symbolic links
++ * are also stored in the bonus buffer.
++ */
++typedef struct znode_phys {
++	uint64_t zp_atime[2];		/*  0 - last file access time */
++	uint64_t zp_mtime[2];		/* 16 - last file modification time */
++	uint64_t zp_ctime[2];		/* 32 - last file change time */
++	uint64_t zp_crtime[2];		/* 48 - creation time */
++	uint64_t zp_gen;		/* 64 - generation (txg of creation) */
++	uint64_t zp_mode;		/* 72 - file mode bits */
++	uint64_t zp_size;		/* 80 - size of file */
++	uint64_t zp_parent;		/* 88 - directory parent (`..') */
++	uint64_t zp_links;		/* 96 - number of links to file */
++	uint64_t zp_xattr;		/* 104 - DMU object for xattrs */
++	uint64_t zp_rdev;		/* 112 - dev_t for VBLK & VCHR files */
++	uint64_t zp_flags;		/* 120 - persistent flags */
++	uint64_t zp_uid;		/* 128 - file owner */
++	uint64_t zp_gid;		/* 136 - owning group */
++	uint64_t zp_pad[4];		/* 144 - future */
++	zfs_znode_acl_t zp_acl;		/* 176 - 263 ACL */
++	/*
++	 * Data may pad out any remaining bytes in the znode buffer, eg:
++	 *
++	 * |<---------------------- dnode_phys (512) ------------------------>|
++	 * |<-- dnode (192) --->|<----------- "bonus" buffer (320) ---------->|
++	 *			|<---- znode (264) ---->|<---- data (56) ---->|
++	 *
++	 * At present, we only use this space to store symbolic links.
++	 */
++} znode_phys_t;
++
++#endif	/* _SYS_FS_ZFS_ZNODE_H */
+diff -urN grub.patch50/stage2/zfs-include/zil.h grub.zfs_solaris/stage2/zfs-include/zil.h
+--- grub.patch50/stage2/zfs-include/zil.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zil.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,57 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef	_SYS_ZIL_H
++#define	_SYS_ZIL_H
++
++/*
++ * Intent log format:
++ *
++ * Each objset has its own intent log.  The log header (zil_header_t)
++ * for objset N's intent log is kept in the Nth object of the SPA's
++ * intent_log objset.  The log header points to a chain of log blocks,
++ * each of which contains log records (i.e., transactions) followed by
++ * a log block trailer (zil_trailer_t).  The format of a log record
++ * depends on the record (or transaction) type, but all records begin
++ * with a common structure that defines the type, length, and txg.
++ */
++
++/*
++ * Intent log header - this on disk structure holds fields to manage
++ * the log.  All fields are 64 bit to easily handle cross architectures.
++ */
++typedef struct zil_header {
++	uint64_t zh_claim_txg;	/* txg in which log blocks were claimed */
++	uint64_t zh_replay_seq;	/* highest replayed sequence number */
++	blkptr_t zh_log;	/* log chain */
++	uint64_t zh_claim_seq;	/* highest claimed sequence number */
++	uint64_t zh_flags;	/* header flags */
++	uint64_t zh_pad[4];
++} zil_header_t;
++
++/*
++ * zh_flags bit settings
++ */
++#define	ZIL_REPLAY_NEEDED 0x1	/* replay needed - internal only */
++
++#endif	/* _SYS_ZIL_H */
+diff -urN grub.patch50/stage2/zfs-include/zio.h grub.zfs_solaris/stage2/zfs-include/zio.h
+--- grub.patch50/stage2/zfs-include/zio.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zio.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,79 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#ifndef _ZIO_H
++#define	_ZIO_H
++
++#define	ZEC_MAGIC	0x210da7ab10c7a11ULL	/* zio data bloc tail */
++
++typedef struct zio_eck {
++	uint64_t	zec_magic;	/* for validation, endianness	*/
++	zio_cksum_t	zec_cksum;	/* 256-bit checksum		*/
++} zio_eck_t;
++
++/*
++ * Gang block headers are self-checksumming and contain an array
++ * of block pointers.
++ */
++#define	SPA_GANGBLOCKSIZE	SPA_MINBLOCKSIZE
++#define	SPA_GBH_NBLKPTRS	((SPA_GANGBLOCKSIZE - \
++	sizeof (zio_eck_t)) / sizeof (blkptr_t))
++#define	SPA_GBH_FILLER		((SPA_GANGBLOCKSIZE - \
++	sizeof (zio_eck_t) - \
++	(SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\
++	sizeof (uint64_t))
++
++#define	ZIO_GET_IOSIZE(zio)	\
++	(BP_IS_GANG((zio)->io_bp) ? \
++	SPA_GANGBLOCKSIZE : BP_GET_PSIZE((zio)->io_bp))
++
++typedef struct zio_gbh {
++	blkptr_t		zg_blkptr[SPA_GBH_NBLKPTRS];
++	uint64_t		zg_filler[SPA_GBH_FILLER];
++	zio_eck_t		zg_tail;
++} zio_gbh_phys_t;
++
++enum zio_checksum {
++	ZIO_CHECKSUM_INHERIT = 0,
++	ZIO_CHECKSUM_ON,
++	ZIO_CHECKSUM_OFF,
++	ZIO_CHECKSUM_LABEL,
++	ZIO_CHECKSUM_GANG_HEADER,
++	ZIO_CHECKSUM_ZILOG,
++	ZIO_CHECKSUM_FLETCHER_2,
++	ZIO_CHECKSUM_FLETCHER_4,
++	ZIO_CHECKSUM_SHA256,
++	ZIO_CHECKSUM_ZILOG2,
++	ZIO_CHECKSUM_SHA256_MAC,
++	ZIO_CHECKSUM_FUNCTIONS
++};
++
++enum zio_compress {
++	ZIO_COMPRESS_INHERIT = 0,
++	ZIO_COMPRESS_ON,
++	ZIO_COMPRESS_OFF,
++	ZIO_COMPRESS_LZJB,
++	ZIO_COMPRESS_EMPTY,
++	ZIO_COMPRESS_FUNCTIONS
++};
++
++#endif	/* _ZIO_H */
+diff -urN grub.patch50/stage2/zfs-include/zio_checksum.h grub.zfs_solaris/stage2/zfs-include/zio_checksum.h
+--- grub.patch50/stage2/zfs-include/zio_checksum.h	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs-include/zio_checksum.h	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,42 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#ifndef _SYS_ZIO_CHECKSUM_H
++#define	_SYS_ZIO_CHECKSUM_H
++
++/*
++ * Signature for checksum functions.
++ */
++typedef void zio_checksum_t(const void *data, uint64_t size, zio_cksum_t *zcp);
++
++/*
++ * Information about each checksum function.
++ */
++typedef struct zio_checksum_info {
++	zio_checksum_t	*ci_func[2]; /* checksum function for each byteorder */
++	int		ci_correctable;	/* number of correctable bits	*/
++	int		ci_eck;		/* uses zio embedded checksum? */
++	char		*ci_name;	/* descriptive name */
++} zio_checksum_info_t;
++
++#endif	/* _SYS_ZIO_CHECKSUM_H */
+diff -urN grub.patch50/stage2/zfs_fletcher.c grub.zfs_solaris/stage2/zfs_fletcher.c
+--- grub.patch50/stage2/zfs_fletcher.c	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs_fletcher.c	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,95 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++#include "fsys_zfs.h"
++
++
++void
++fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
++{
++	const uint64_t *ip = buf;
++	const uint64_t *ipend = ip + (size / sizeof (uint64_t));
++	uint64_t a0, b0, a1, b1;
++
++	for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) {
++		a0 += ip[0];
++		a1 += ip[1];
++		b0 += a0;
++		b1 += a1;
++	}
++
++	ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
++}
++
++void
++fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
++{
++	const uint64_t *ip = buf;
++	const uint64_t *ipend = ip + (size / sizeof (uint64_t));
++	uint64_t a0, b0, a1, b1;
++
++	for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) {
++		a0 += BSWAP_64(ip[0]);
++		a1 += BSWAP_64(ip[1]);
++		b0 += a0;
++		b1 += a1;
++	}
++
++	ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
++}
++
++void
++fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
++{
++	const uint32_t *ip = buf;
++	const uint32_t *ipend = ip + (size / sizeof (uint32_t));
++	uint64_t a, b, c, d;
++
++	for (a = b = c = d = 0; ip < ipend; ip++) {
++		a += ip[0];
++		b += a;
++		c += b;
++		d += c;
++	}
++
++	ZIO_SET_CHECKSUM(zcp, a, b, c, d);
++}
++
++void
++fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
++{
++	const uint32_t *ip = buf;
++	const uint32_t *ipend = ip + (size / sizeof (uint32_t));
++	uint64_t a, b, c, d;
++
++	for (a = b = c = d = 0; ip < ipend; ip++) {
++		a += BSWAP_32(ip[0]);
++		b += a;
++		c += b;
++		d += c;
++	}
++
++	ZIO_SET_CHECKSUM(zcp, a, b, c, d);
++}
+diff -urN grub.patch50/stage2/zfs_lzjb.c grub.zfs_solaris/stage2/zfs_lzjb.c
+--- grub.patch50/stage2/zfs_lzjb.c	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs_lzjb.c	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,61 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++#include "fsys_zfs.h"
++
++#define	MATCH_BITS	6
++#define	MATCH_MIN	3
++#define	OFFSET_MASK	((1 << (16 - MATCH_BITS)) - 1)
++
++
++/*ARGSUSED*/
++int
++lzjb_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len)
++{
++	uchar_t *src = s_start;
++	uchar_t *dst = d_start;
++	uchar_t *d_end = (uchar_t *)d_start + d_len;
++	uchar_t *cpy, copymap;
++	int copymask = 1 << (NBBY - 1);
++
++	while (dst < d_end) {
++		if ((copymask <<= 1) == (1 << NBBY)) {
++			copymask = 1;
++			copymap = *src++;
++		}
++		if (copymap & copymask) {
++			int mlen = (src[0] >> (NBBY - MATCH_BITS)) + MATCH_MIN;
++			int offset = ((src[0] << NBBY) | src[1]) & OFFSET_MASK;
++			src += 2;
++			if ((cpy = dst - offset) < (uchar_t *)d_start)
++				return (-1);
++			while (--mlen >= 0 && dst < d_end)
++				*dst++ = *cpy++;
++		} else {
++			*dst++ = *src++;
++		}
++	}
++	return (0);
++}
+diff -urN grub.patch50/stage2/zfs_sha256.c grub.zfs_solaris/stage2/zfs_sha256.c
+--- grub.patch50/stage2/zfs_sha256.c	1970-01-01 01:00:00.000000000 +0100
++++ grub.zfs_solaris/stage2/zfs_sha256.c	2011-10-12 19:58:29.059921869 +0200
+@@ -0,0 +1,126 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++/*
++ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++#pragma ident	"%Z%%M%	%I%	%E% SMI"
++
++#include "fsys_zfs.h"
++
++/*
++ * SHA-256 checksum, as specified in FIPS 180-2, available at:
++ * http://csrc.nist.gov/cryptval
++ *
++ * This is a very compact implementation of SHA-256.
++ * It is designed to be simple and portable, not to be fast.
++ */
++
++/*
++ * The literal definitions according to FIPS180-2 would be:
++ *
++ * 	Ch(x, y, z)     (((x) & (y)) ^ ((~(x)) & (z)))
++ * 	Maj(x, y, z)    (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
++ *
++ * We use logical equivalents which require one less op.
++ */
++#define	Ch(x, y, z)	((z) ^ ((x) & ((y) ^ (z))))
++#define	Maj(x, y, z)	(((x) & (y)) ^ ((z) & ((x) ^ (y))))
++#define	Rot32(x, s)	(((x) >> s) | ((x) << (32 - s)))
++#define	SIGMA0(x)	(Rot32(x, 2) ^ Rot32(x, 13) ^ Rot32(x, 22))
++#define	SIGMA1(x)	(Rot32(x, 6) ^ Rot32(x, 11) ^ Rot32(x, 25))
++#define	sigma0(x)	(Rot32(x, 7) ^ Rot32(x, 18) ^ ((x) >> 3))
++#define	sigma1(x)	(Rot32(x, 17) ^ Rot32(x, 19) ^ ((x) >> 10))
++
++static const uint32_t SHA256_K[64] = {
++	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
++	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
++	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
++	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
++	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
++	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
++	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
++	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
++	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
++	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
++	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
++	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
++	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
++	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
++	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
++	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
++};
++
++static void
++SHA256Transform(uint32_t *H, const uint8_t *cp)
++{
++	uint32_t a, b, c, d, e, f, g, h, t, T1, T2, W[64];
++
++	for (t = 0; t < 16; t++, cp += 4)
++		W[t] = (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | cp[3];
++
++	for (t = 16; t < 64; t++)
++		W[t] = sigma1(W[t - 2]) + W[t - 7] +
++		    sigma0(W[t - 15]) + W[t - 16];
++
++	a = H[0]; b = H[1]; c = H[2]; d = H[3];
++	e = H[4]; f = H[5]; g = H[6]; h = H[7];
++
++	for (t = 0; t < 64; t++) {
++		T1 = h + SIGMA1(e) + Ch(e, f, g) + SHA256_K[t] + W[t];
++		T2 = SIGMA0(a) + Maj(a, b, c);
++		h = g; g = f; f = e; e = d + T1;
++		d = c; c = b; b = a; a = T1 + T2;
++	}
++
++	H[0] += a; H[1] += b; H[2] += c; H[3] += d;
++	H[4] += e; H[5] += f; H[6] += g; H[7] += h;
++}
++
++void
++zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp)
++{
++	uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
++	    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
++	uint8_t pad[128];
++	int padsize = size & 63;
++	int i;
++
++	for (i = 0; i < size - padsize; i += 64)
++		SHA256Transform(H, (uint8_t *)buf + i);
++
++	for (i = 0; i < padsize; i++)
++		pad[i] = ((uint8_t *)buf)[i];
++
++	for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++)
++		pad[padsize] = 0;
++
++	for (i = 0; i < 8; i++)
++		pad[padsize++] = (size << 3) >> (56 - 8 * i);
++
++	for (i = 0; i < padsize; i += 64)
++		SHA256Transform(H, pad + i);
++
++	ZIO_SET_CHECKSUM(zcp,
++	    (uint64_t)H[0] << 32 | H[1],
++	    (uint64_t)H[2] << 32 | H[3],
++	    (uint64_t)H[4] << 32 | H[5],
++	    (uint64_t)H[6] << 32 | H[7]);
++}
diff -r 4b0907c6a08c stubdom/grub/Makefile
--- a/stubdom/grub/Makefile	Tue Oct 11 12:02:58 2011 +0100
+++ b/stubdom/grub/Makefile	Wed Oct 12 20:06:15 2011 +0200
@@ -54,6 +54,9 @@
 STAGE2_SOURCES+=fsys_xfs.c
 CPPFLAGS += -DFSYS_XFS=1
 
+STAGE2_SOURCES+=fsys_zfs.c zfs_fletcher.c zfs_lzjb.c zfs_sha256.c
+CPPFLAGS += -DFSYS_ZFS=1
+
 STAGE2_SOURCES:=$(addprefix stage2/,$(STAGE2_SOURCES))
 NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES))
 

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

             reply	other threads:[~2011-10-12 20:40 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-10-12 20:40 Kasper Brink [this message]
2011-10-12 20:51 ` pv-grub Solaris support Fajar A. Nugraha
2011-10-12 21:55   ` Kasper Brink
2011-10-13  0:38 ` Samuel Thibault
2011-10-13  6:41   ` Kasper Brink
2011-10-16 17:45   ` Kasper Brink
2011-10-18 22:19     ` Samuel Thibault
     [not found] ` <4E9697EB.4000204@oracle.com>
2011-10-13 19:51   ` Kasper Brink
2011-10-25 18:06 ` Ian Jackson
2011-10-26  9:21   ` Kasper Brink
2011-10-26 13:00     ` Ian Jackson
2011-11-01 14:11       ` Kasper Brink
2012-03-08 13:58         ` Florian Manschwetus
2012-03-08 15:34           ` Florian Manschwetus
2012-03-14 11:05         ` Ian Jackson

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=20111012204011.GA7518@lilo2.science.ru.nl \
    --to=k.brink@cs.ru.nl \
    --cc=xen-devel@lists.xensource.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.