=== modified file 'configure.ac' --- configure.ac 2011-08-19 20:49:48 +0000 +++ configure.ac 2011-10-15 16:42:10 +0000 @@ -916,18 +916,6 @@ AC_CHECK_LIB([lzma], [lzma_code], [Define to 1 if you have the LZMA library.])],) AC_SUBST([LIBLZMA]) -AC_CHECK_LIB([zfs], [libzfs_init], - [LIBZFS="-lzfs" - AC_DEFINE([HAVE_LIBZFS], [1], - [Define to 1 if you have the ZFS library.])],) -AC_SUBST([LIBZFS]) - -AC_CHECK_LIB([nvpair], [nvlist_print], - [LIBNVPAIR="-lnvpair" - AC_DEFINE([HAVE_LIBNVPAIR], [1], - [Define to 1 if you have the NVPAIR library.])],) -AC_SUBST([LIBNVPAIR]) - LIBS="" pkglibrootdir='$(libdir)'/`echo $PACKAGE | sed "$program_transform_name"` === modified file 'grub-core/fs/zfs/zfs.c' --- grub-core/fs/zfs/zfs.c 2011-06-23 22:31:29 +0000 +++ grub-core/fs/zfs/zfs.c 2011-10-15 16:42:10 +0000 @@ -53,6 +53,10 @@ #include #include +#ifdef GRUB_UTIL +#include +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define ZPOOL_PROP_BOOTFS "bootfs" @@ -2179,6 +2183,130 @@ zfs_uuid (grub_device_t device, char **u return GRUB_ERR_NONE; } +struct grub_zfs_vdev +{ + const char *name; + struct grub_zfs_vdev *next; +}; + +struct grub_zfs_pool +{ + grub_uint64_t guid; + char *name; + struct grub_zfs_vdev *vdev_list; + struct grub_zfs_pool *next; +}; + +static struct grub_zfs_pool *zpool_list; + +static int +zfs_scan_device (const char *name) +{ + grub_device_t device; + struct grub_zfs_data *data; + char *nvlist; + grub_uint64_t guid; + char *label; + struct grub_zfs_pool *zpool; + struct grub_zfs_vdev *vdev; + +#ifdef GRUB_UTIL + grub_util_info ("scanning %s for ZFS", name); +#endif + + device = grub_device_open (name); + if (! device) + return 0; + + data = zfs_mount (device); + if (! data) + goto end1; + + if (zfs_fetch_nvlist (data, &nvlist)) + goto end2; + + if (! grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid)) + goto end3; + + label = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); + if (! label) + goto end3; + + vdev = grub_zalloc (sizeof (*vdev)); + vdev->name = grub_strdup (name); + + struct grub_zfs_pool *i; + for (i = zpool_list; i; i = i->next) + { + if (guid == i->guid) + { + /* This vdev belongs to an already-registered pool. */ + vdev->next = i->vdev_list; + i->vdev_list = vdev; + return 0; + } + } + + /* Create a new ZFS pool with this vdev. */ + zpool = grub_zalloc (sizeof (*zpool)); + zpool->guid = guid; + zpool->name = grub_xasprintf ("zfs/%s", label); + zpool->vdev_list = vdev; + + /* Insert it to ZFS pool list. */ + zpool->next = zpool_list; + zpool_list = zpool; + + end3: + grub_free (nvlist); + end2: + zfs_unmount (data); + end1: + grub_device_close (device); + + return 0; +} + +static int +grub_zpool_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull __attribute__ ((unused))) +{ + struct grub_zfs_pool *i; + for (i = zpool_list; i; i = i->next) + { + if (hook (i->name)) + return 1; + } + + return 0; +} + +static grub_err_t +grub_zpool_open (const char *name, grub_disk_t disk) +{ + struct grub_zfs_pool *i; + for (i = zpool_list; i; i = i->next) + { + if (! grub_strcmp (i->name, name)) + { + /* For now just pick the first vdev as lower layer. */ + grub_disk_t lower = grub_disk_open (i->vdev_list->name); + grub_memcpy (disk, lower, sizeof (*disk)); + return GRUB_ERR_NONE; + } + } + + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a ZFS pool"); +} + +static struct grub_disk_dev grub_zpool_dev = + { + .name = "zfs", + .id = GRUB_DISK_DEVICE_ZFS_ID, + .iterate = grub_zpool_iterate, + .open = grub_zpool_open, + }; + /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. @@ -2556,6 +2684,9 @@ static struct grub_fs grub_zfs_fs = { GRUB_MOD_INIT (zfs) { + grub_device_iterate (&zfs_scan_device); + grub_disk_dev_register (&grub_zpool_dev); + grub_fs_register (&grub_zfs_fs); #ifndef GRUB_UTIL my_mod = mod; @@ -2564,5 +2695,9 @@ GRUB_MOD_INIT (zfs) GRUB_MOD_FINI (zfs) { + grub_disk_dev_unregister (&grub_zpool_dev); + zpool_list = NULL; + /* FIXME: free the zpool list. */ + grub_fs_unregister (&grub_zfs_fs); } === modified file 'grub-core/kern/disk.c' --- grub-core/kern/disk.c 2011-08-13 13:00:48 +0000 +++ grub-core/kern/disk.c 2011-10-15 16:42:10 +0000 @@ -267,6 +267,7 @@ grub_disk_open (const char *name) for (dev = grub_disk_dev_list; dev; dev = dev->next) { + disk->dev = dev; if ((dev->open) (raw, disk) == GRUB_ERR_NONE) break; else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE) @@ -289,8 +290,6 @@ grub_disk_open (const char *name) goto fail; } - disk->dev = dev; - if (p) { disk->partition = grub_partition_probe (disk, p + 1); === modified file 'include/grub/disk.h' --- include/grub/disk.h 2011-08-13 13:00:48 +0000 +++ include/grub/disk.h 2011-10-15 16:42:10 +0000 @@ -44,6 +44,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_FILE_ID, GRUB_DISK_DEVICE_CRYPTODISK_ID, GRUB_DISK_DEVICE_ARCDISK_ID, + GRUB_DISK_DEVICE_ZFS_ID, }; struct grub_disk; === modified file 'include/grub/emu/getroot.h' --- include/grub/emu/getroot.h 2011-04-25 12:52:07 +0000 +++ include/grub/emu/getroot.h 2011-10-15 16:42:10 +0000 @@ -27,6 +27,7 @@ enum grub_dev_abstraction_types { GRUB_DEV_ABSTRACTION_RAID, GRUB_DEV_ABSTRACTION_LUKS, GRUB_DEV_ABSTRACTION_GELI, + GRUB_DEV_ABSTRACTION_ZFS, }; char *grub_find_device (const char *dir, dev_t dev); === modified file 'util/getroot.c' --- util/getroot.c 2011-10-15 16:37:55 +0000 +++ util/getroot.c 2011-10-15 16:44:12 +0000 @@ -243,69 +243,6 @@ grub_find_root_device_from_mountinfo (co #endif /* __linux__ */ -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) -static char * -find_root_device_from_libzfs (const char *dir) -{ - char *device = NULL; - char *poolname; - char *poolfs; - - grub_find_zpool_from_dir (dir, &poolname, &poolfs); - if (! poolname) - return NULL; - - { - zpool_handle_t *zpool; - libzfs_handle_t *libzfs; - nvlist_t *config, *vdev_tree; - nvlist_t **children, **path; - unsigned int nvlist_count; - unsigned int i; - - libzfs = grub_get_libzfs_handle (); - if (! libzfs) - return NULL; - - zpool = zpool_open (libzfs, poolname); - config = zpool_get_config (zpool, NULL); - - if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0) - error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); - - if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0) - error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); - assert (nvlist_count > 0); - - while (nvlist_lookup_nvlist_array (children[0], "children", - &children, &nvlist_count) == 0) - assert (nvlist_count > 0); - - for (i = 0; i < nvlist_count; i++) - { - if (nvlist_lookup_string (children[i], "path", &device) != 0) - error (1, errno, "nvlist_lookup_string (\"path\")"); - - struct stat st; - if (stat (device, &st) == 0) - { - device = xstrdup (device); - break; - } - - device = NULL; - } - - zpool_close (zpool); - } - - free (poolname); - if (poolfs) - free (poolfs); - - return device; -} -#endif #ifdef __MINGW32__ @@ -608,11 +545,6 @@ grub_guess_root_device (const char *dir) os_dev = grub_find_root_device_from_mountinfo (dir, NULL); #endif /* __linux__ */ -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - if (!os_dev) - os_dev = find_root_device_from_libzfs (dir); -#endif - if (os_dev) { char *tmp = os_dev; @@ -635,6 +567,28 @@ grub_guess_root_device (const char *dir) free (os_dev); } + /* Check for ZFS. */ + if (!os_dev) + { + char *pool; + char *fs; + + grub_find_zpool_from_dir (dir, &pool, &fs); + + if (pool) + { + os_dev = xasprintf ("zfs/%s", pool); + free (pool); + } + + if (fs) + free (fs); + } + + if (grub_util_check_nodeless_device (os_dev)) + /* This kind of abstraction doesn't provide device nodes. */ + return os_dev; + if (stat (dir, &st) < 0) grub_util_error ("cannot stat `%s'", dir); @@ -884,7 +838,6 @@ grub_util_get_dev_abstraction (const cha #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) const char *abs; abs = grub_util_get_geom_abstraction (os_dev); - grub_util_info ("abstraction of %s is %s", os_dev, abs); if (abs && grub_strcasecmp (abs, "eli") == 0) return GRUB_DEV_ABSTRACTION_GELI; @@ -893,6 +846,9 @@ grub_util_get_dev_abstraction (const cha return GRUB_DEV_ABSTRACTION_LVM; #endif + if (!strncmp (os_dev, "zfs/", sizeof ("zfs/")-1)) + return GRUB_DEV_ABSTRACTION_ZFS; + /* No abstraction found. */ return GRUB_DEV_ABSTRACTION_NONE; } @@ -1107,6 +1063,9 @@ grub_util_pull_device (const char *os_de #endif return; + case GRUB_DEV_ABSTRACTION_ZFS: + return; + default: /* GRUB_DEV_ABSTRACTION_NONE */ grub_util_biosdisk_get_grub_dev (os_dev); return; @@ -1139,6 +1098,12 @@ grub_util_get_grub_dev (const char *os_d break; #endif + case GRUB_DEV_ABSTRACTION_ZFS: + { + grub_dev = xstrdup (os_dev); + } + break; + #ifdef __linux__ case GRUB_DEV_ABSTRACTION_LUKS: { @@ -1317,6 +1282,13 @@ grub_util_get_grub_dev (const char *os_d return grub_dev; } +const int +grub_util_check_nodeless_device (const char *dev) +{ + /* Only ZFS for now. Btrfs might fit here. */ + return ! strncmp (dev, "zfs/", sizeof ("zfs/")-1); +} + const char * grub_util_check_block_device (const char *blk_dev) { @@ -1366,32 +1338,6 @@ get_win32_path (const char *path) } #endif -#ifdef HAVE_LIBZFS -static libzfs_handle_t *__libzfs_handle; - -static void -fini_libzfs (void) -{ - libzfs_fini (__libzfs_handle); -} - -libzfs_handle_t * -grub_get_libzfs_handle (void) -{ - if (! __libzfs_handle) - { - __libzfs_handle = libzfs_init (); - - if (__libzfs_handle) - atexit (fini_libzfs); - } - - return __libzfs_handle; -} -#endif /* HAVE_LIBZFS */ - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) -/* ZFS has similar problems to those of btrfs (see above). */ void grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs) { @@ -1451,7 +1397,6 @@ grub_find_zpool_from_dir (const char *di else *poolfs = xstrdup (""); } -#endif /* This function never prints trailing slashes (so that its output can be appended a slash unconditionally). */ @@ -1463,23 +1408,18 @@ grub_make_system_path_relative_to_its_ro uintptr_t offset = 0; dev_t num; size_t len; - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) char *poolfs = NULL; -#endif /* canonicalize. */ p = canonicalize_file_name (path); if (p == NULL) grub_util_error ("failed to get canonical path of %s", path); -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) /* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */ { char *dummy; grub_find_zpool_from_dir (p, &dummy, &poolfs); } -#endif len = strlen (p) + 1; buf = xstrdup (p); @@ -1531,10 +1471,8 @@ grub_make_system_path_relative_to_its_ro } #endif free (buf2); -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) if (poolfs) return xasprintf ("/%s/@", poolfs); -#endif return xstrdup (""); } else === modified file 'util/grub-probe.c' --- util/grub-probe.c 2011-08-15 22:30:11 +0000 +++ util/grub-probe.c 2011-10-15 16:42:10 +0000 @@ -144,6 +144,9 @@ probe_abstraction (grub_disk_t disk) if (disk->dev->id == GRUB_DISK_DEVICE_LVM_ID) printf ("lvm "); + if (disk->dev->id == GRUB_DISK_DEVICE_ZFS_ID) + printf ("zfs "); + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) grub_util_cryptodisk_print_abstraction (disk); @@ -171,13 +174,16 @@ probe (const char *path, char *device_na if (path == NULL) { + if (! grub_util_check_nodeless_device (device_name)) + { #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) - if (! grub_util_check_char_device (device_name)) - grub_util_error ("%s is not a character device", device_name); + if (! grub_util_check_char_device (device_name)) + grub_util_error ("%s is not a character device", device_name); #else - if (! grub_util_check_block_device (device_name)) - grub_util_error ("%s is not a block device", device_name); + if (! grub_util_check_block_device (device_name)) + grub_util_error ("%s is not a block device", device_name); #endif + } } else {