Rewrite no_libzfs.patch using a different approach. (Closes: #648539)

This commit is contained in:
Robert Millan 2011-11-13 03:34:01 +01:00
parent 6e1ddd4b2e
commit fdec2d595f
2 changed files with 147 additions and 274 deletions

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
grub2 (1.99-14) unstable; urgency=low
* Rewrite no_libzfs.patch using a different approach. (Closes: #648539)
-- Robert Millan <rmh@debian.org> Sun, 13 Nov 2011 00:14:38 +0100
grub2 (1.99-13) unstable; urgency=low
[ Debconf translations ]

View File

@ -1,216 +1,155 @@
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -53,6 +53,10 @@
#include <grub/zfs/dsl_dataset.h>
#include <grub/deflate.h>
+#ifdef GRUB_UTIL
+#include <grub/emu/misc.h>
+#endif
+
GRUB_MOD_LICENSE ("GPLv3+");
#define ZPOOL_PROP_BOOTFS "bootfs"
@@ -3039,6 +3043,129 @@
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->device_original, &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))
+{
+ 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.
@@ -3490,6 +3617,8 @@
GRUB_MOD_INIT (zfs)
{
COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
+ 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;
@@ -3498,5 +3627,9 @@
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);
}
--- a/grub-core/kern/disk.c
+++ b/grub-core/kern/disk.c
@@ -269,6 +269,7 @@
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)
@@ -283,8 +284,6 @@
goto fail;
}
- disk->dev = dev;
-
if (p)
{
disk->partition = grub_partition_probe (disk, p + 1);
--- a/grub-core/kern/emu/getroot.c
+++ b/grub-core/kern/emu/getroot.c
@@ -626,6 +626,28 @@
return grub_find_device ("/dev/mapper", dev);
}
@@ -32,6 +32,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
+ /* Check for ZFS. */
+ if (!os_dev)
@@ -238,7 +241,67 @@
#endif /* __linux__ */
-#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+static char *
+find_device_from_pool (const char *poolname)
+{
+ char *device;
+ char *cmd;
+ FILE *fp;
+ int ret;
+ char *line;
+ size_t len;
+ int st;
+
+ char name[PATH_MAX], state[256], readlen[256], writelen[256], cksum[256], notes[256];
+ unsigned int dummy;
+
+ asprintf (&cmd, "zpool status %s", poolname);
+ fp = popen (cmd, "r");
+ free (cmd);
+
+ st = 0;
+ while (st < 3)
+ {
+ char *pool;
+ char *fs;
+
+ grub_find_zpool_from_dir (dir, &pool, &fs);
+
+ if (pool)
+ line = NULL;
+ ret = getline (&line, &len, fp);
+ if (ret == -1)
+ {
+ os_dev = xasprintf ("zfs/%s", pool);
+ free (pool);
+ pclose (fp);
+ return NULL;
+ }
+
+ if (fs)
+ free (fs);
+ if (sscanf (line, " %s %s %s %s %s %s", name, state, readlen, writelen, cksum, notes) >= 5)
+ switch (st)
+ {
+ case 0:
+ if (!strcmp (name, "NAME")
+ && !strcmp (state, "STATE")
+ && !strcmp (readlen, "READ")
+ && !strcmp (writelen, "WRITE")
+ && !strcmp (cksum, "CKSUM"))
+ st++;
+ break;
+ case 1:
+ if (!strcmp (name, poolname))
+ st++;
+ break;
+ case 2:
+ if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
+ && !sscanf (name, "raidz%u", &dummy)
+ && !strcmp (state, "ONLINE"))
+ st++;
+ break;
+ }
+
+ free (line);
+ }
+ pclose (fp);
+
+ if (! strncmp (os_dev, "zfs/", sizeof ("zfs/")-1))
+ /* This kind of abstraction doesn't provide device nodes. */
+ return os_dev;
+ asprintf (&device, "/dev/%s", name);
+
if (stat (dir, &st) < 0)
grub_util_error ("cannot stat `%s'", dir);
+ return device;
+}
+
static char *
find_root_device_from_libzfs (const char *dir)
{
@@ -250,49 +313,7 @@
if (! poolname)
return NULL;
@@ -708,7 +730,7 @@
- {
- 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);
- }
+ device = find_device_from_pool (poolname);
free (poolname);
if (poolfs)
@@ -300,7 +321,6 @@
return device;
}
-#endif
#ifdef __MINGW32__
@@ -603,10 +623,8 @@
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)
{
@@ -708,7 +726,7 @@
}
int
@ -219,27 +158,6 @@
{
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
/* User explicitly claims that this drive is visible by BIOS. */
@@ -732,6 +754,9 @@
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;
}
@@ -948,6 +973,10 @@
break;
#endif /* __linux__ */
+ case GRUB_DEV_ABSTRACTION_ZFS:
+ grub_dev = xstrdup (os_dev);
+ break;
+
default: /* GRUB_DEV_ABSTRACTION_NONE */
grub_dev = grub_util_biosdisk_get_grub_dev (os_dev);
}
--- a/grub-core/kern/emu/misc.c
+++ b/grub-core/kern/emu/misc.c
@@ -287,7 +287,6 @@
@ -307,54 +225,3 @@
ret = buf3;
return ret;
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -42,7 +42,8 @@
GRUB_DISK_DEVICE_PXE_ID,
GRUB_DISK_DEVICE_SCSI_ID,
GRUB_DISK_DEVICE_FILE_ID,
- GRUB_DISK_DEVICE_LUKS_ID
+ GRUB_DISK_DEVICE_LUKS_ID,
+ GRUB_DISK_DEVICE_ZFS_ID,
};
struct grub_disk;
--- a/include/grub/emu/getroot.h
+++ b/include/grub/emu/getroot.h
@@ -25,6 +25,7 @@
GRUB_DEV_ABSTRACTION_NONE,
GRUB_DEV_ABSTRACTION_LVM,
GRUB_DEV_ABSTRACTION_RAID,
+ GRUB_DEV_ABSTRACTION_ZFS,
};
char *grub_find_device (const char *dir, dev_t dev);
--- a/util/grub-probe.c
+++ b/util/grub-probe.c
@@ -99,6 +99,8 @@
if (path == NULL)
{
+ if (strncmp (device_name, "zfs/", sizeof ("zfs/")-1))
+ {
#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);
@@ -106,6 +108,7 @@
if (! grub_util_check_block_device (device_name))
grub_util_error ("%s is not a block device", device_name);
#endif
+ }
}
else
{
@@ -188,6 +191,9 @@
if (is_lvm)
printf ("lvm ");
+ if (dev->disk->dev->id == GRUB_DISK_DEVICE_ZFS_ID)
+ printf ("zfs ");
+
printf ("\n");
goto end;