diff options
author | gw25295 <none@none> | 2008-04-11 18:36:28 -0700 |
---|---|---|
committer | gw25295 <none@none> | 2008-04-11 18:36:28 -0700 |
commit | e7cbe64f7a72dae5cb44f100db60ca88f3313c65 (patch) | |
tree | 778467a6522111f338e4644cc2cb895dcecacee4 /usr/src/uts/intel/zfs/spa_boot.c | |
parent | f635d46a9872dc5a02bbbd736f2bf18685c2c221 (diff) | |
download | illumos-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.c | 198 |
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); +} |