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 + + +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 @@ + }; + + +-/* 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 @@ + + + ++/* ++ * 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=, ++ * bootpath=, ++ * diskdevid= ++ * ++ * 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." ++}; ++ + + /* 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." ++}; ++ + + /* 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 @@ + }; + + ++/* 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 ", ++ "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." ++}; ++ ++ ++/* ++ * 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 .", ++ 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)." ++}; ++ ++ + /* 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 + #include +@@ -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_indblkshift; ++ ++ for (level = dn->dn_nlevels - 1; level >= 0; level--) { ++ idx = (blkid >> (epbs * level)) & ((1<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<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<= 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< 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(¤t_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(¤t_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<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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * 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<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) /* (,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<= 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_f.zap_phys) \ ++ [(idx) + (1<| ++ * |<-- 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))