summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/zfs/spa_boot.c
diff options
context:
space:
mode:
authorgw25295 <none@none>2008-04-11 18:36:28 -0700
committergw25295 <none@none>2008-04-11 18:36:28 -0700
commite7cbe64f7a72dae5cb44f100db60ca88f3313c65 (patch)
tree778467a6522111f338e4644cc2cb895dcecacee4 /usr/src/uts/intel/zfs/spa_boot.c
parentf635d46a9872dc5a02bbbd736f2bf18685c2c221 (diff)
downloadillumos-gate-e7cbe64f7a72dae5cb44f100db60ca88f3313c65.tar.gz
PSARC 2006/370 ZFS Boot Support
5008936 ZFS and/or zvol should support dumps 5070124 dumpadm -d /dev/... does not enforce block device requirement for savecore 6521468 ZFS Boot support Phase 2 6553503 bfu can't find 'rootdev' from /etc/vfstab on a zfs root filesystem 6574993 zfs_mountroot() may need to call clkset() to set the boot_time kstat 6633197 zvol should not permit newfs or createpool while it's in use by swap or dump 6661127 zfs_name_valid() does not support ZFS_TYPE_POOL 6684121 The changes to smf scripts for supporting canmount=noauto will cause a boot failure. --HG-- rename : usr/src/psm/stand/bootblks/zfs/common/debug-zfs.fth => deleted_files/usr/src/psm/stand/bootblks/zfs/common/debug-zfs.fth rename : usr/src/psm/stand/bootblks/zfs/common/big-zfs.fth => usr/src/psm/stand/bootblks/zfs/common/fs-zfs.fth
Diffstat (limited to 'usr/src/uts/intel/zfs/spa_boot.c')
-rw-r--r--usr/src/uts/intel/zfs/spa_boot.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/usr/src/uts/intel/zfs/spa_boot.c b/usr/src/uts/intel/zfs/spa_boot.c
new file mode 100644
index 0000000000..9407f52353
--- /dev/null
+++ b/usr/src/uts/intel/zfs/spa_boot.c
@@ -0,0 +1,198 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/spa.h>
+#include <sys/sunddi.h>
+
+char *
+spa_get_bootfs()
+{
+ char *zfs_bp;
+
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
+ DDI_PROP_DONTPASS, "zfs-bootfs", &zfs_bp) !=
+ DDI_SUCCESS)
+ return (NULL);
+ return (zfs_bp);
+}
+
+void
+spa_free_bootfs(char *bootfs)
+{
+ ddi_prop_free(bootfs);
+}
+
+/*
+ * Calculate how many device pathnames are in devpath_list.
+ * The devpath_list could look like this:
+ *
+ * "/pci@1f,0/ide@d/disk@0,0:a /pci@1f,o/ide@d/disk@2,0:a"
+ */
+static int
+spa_count_devpath(char *devpath_list)
+{
+ int numpath;
+ char *tmp_path, *blank;
+
+ numpath = 0;
+ tmp_path = devpath_list;
+
+ /* skip leading blanks */
+ while (*tmp_path == ' ')
+ tmp_path++;
+
+ while ((blank = strchr(tmp_path, ' ')) != NULL) {
+
+ numpath++;
+ /* skip contiguous blanks */
+ while (*blank == ' ')
+ blank++;
+ tmp_path = blank;
+ }
+
+ if (strlen(tmp_path) > 0)
+ numpath++;
+
+ return (numpath);
+}
+
+/*
+ * Only allow booting the device if it has the same vdev information as
+ * the most recently updated vdev (highest txg) and is in a valid state.
+ *
+ * GRUB passes online/active device path names, e.g.
+ * "/pci@1f,0/ide@d/disk@0,0:a /pci@1f,o/ide@d/disk@2,0:a"
+ * to the kernel. The best vdev should have the same matching online/active
+ * list as what GRUB passes in.
+ */
+static int
+spa_check_devstate(char *devpath_list, char *dev, nvlist_t *conf)
+{
+ nvlist_t *nvtop, **child;
+ uint_t label_path, grub_path, c, children;
+ char *type;
+
+ VERIFY(nvlist_lookup_nvlist(conf, ZPOOL_CONFIG_VDEV_TREE,
+ &nvtop) == 0);
+ VERIFY(nvlist_lookup_string(nvtop, ZPOOL_CONFIG_TYPE, &type) == 0);
+
+ if (strcmp(type, VDEV_TYPE_DISK) == 0)
+ return (spa_rootdev_validate(nvtop)? 0 : EINVAL);
+
+ ASSERT(strcmp(type, VDEV_TYPE_MIRROR) == 0);
+
+ VERIFY(nvlist_lookup_nvlist_array(nvtop, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0);
+
+ /*
+ * Check if the devpath_list is the same as the path list in conf.
+ * If these two lists are different, then the booting device is not an
+ * up-to-date device that can be booted.
+ */
+ label_path = 0;
+ for (c = 0; c < children; c++) {
+ char *physpath;
+
+ if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_PHYS_PATH,
+ &physpath) != 0)
+ return (EINVAL);
+
+ if (spa_rootdev_validate(child[c])) {
+ if (strstr(devpath_list, physpath) == NULL)
+ return (EINVAL);
+ label_path++;
+ } else {
+ char *blank;
+
+ if (blank = strchr(dev, ' '))
+ *blank = '\0';
+ if (strcmp(physpath, dev) == 0)
+ return (EINVAL);
+ if (blank)
+ *blank = ' ';
+ }
+ }
+
+ grub_path = spa_count_devpath(devpath_list);
+
+ if (label_path != grub_path)
+ return (EINVAL);
+
+ return (0);
+}
+
+/*
+ * Given a list of vdev physpath names, pick the vdev with the most recent txg,
+ * and return the point of the device's physpath in the list and the device's
+ * label configuration. The content of the label would be the most recent
+ * updated information.
+ */
+int
+spa_get_rootconf(char *devpath_list, char **bestdev, nvlist_t **bestconf)
+{
+ nvlist_t *conf = NULL;
+ char *dev = NULL;
+ uint64_t txg = 0;
+ char *devpath, *blank;
+
+ devpath = devpath_list;
+ dev = devpath;
+
+ while (devpath[0] == ' ')
+ devpath++;
+
+ while ((blank = strchr(devpath, ' ')) != NULL) {
+ *blank = '\0';
+ spa_check_rootconf(devpath, &dev, &conf, &txg);
+ *blank = ' ';
+
+ while (*blank == ' ')
+ blank++;
+ devpath = blank;
+ }
+
+ /* for the only or the last devpath in the devpath_list */
+ if (strlen(devpath) > 0)
+ spa_check_rootconf(devpath, &dev, &conf, &txg);
+
+ if (conf == NULL)
+ return (EINVAL);
+
+ /*
+ * dev/conf is the vdev with the most recent txg.
+ * Check if the device is in a bootable state.
+ * dev may have a trailing blank since it points to a string
+ * in the devpath_list.
+ */
+ if (spa_check_devstate(devpath_list, dev, conf) != 0)
+ return (EINVAL);
+
+ *bestdev = dev;
+ *bestconf = conf;
+ return (0);
+}