1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/spa.h> 30 #include <sys/bootconf.h> 31 32 char * 33 spa_get_bootfs() 34 { 35 int proplen; 36 char *zfs_bp; 37 38 proplen = BOP_GETPROPLEN(bootops, "zfs-bootfs"); 39 if (proplen == 0) 40 return (NULL); 41 42 zfs_bp = kmem_zalloc(proplen, KM_SLEEP); 43 if (BOP_GETPROP(bootops, "zfs-bootfs", zfs_bp) == -1) { 44 kmem_free(zfs_bp, proplen); 45 return (NULL); 46 } 47 48 return (zfs_bp); 49 } 50 51 void 52 spa_free_bootfs(char *bootfs) 53 { 54 kmem_free(bootfs, strlen(bootfs) + 1); 55 } 56 57 /* 58 * Given the boot device physpath, check if the device is in a valid state. 59 * If so, return the configuration from the vdev label. 60 */ 61 int 62 spa_get_rootconf(char *devpath, char **bestdev, nvlist_t **bestconf) 63 { 64 nvlist_t *conf = NULL; 65 char *dev = NULL; 66 uint64_t txg = 0; 67 nvlist_t *nvtop, **child; 68 char *type; 69 uint_t children, c; 70 71 spa_check_rootconf(devpath, &dev, &conf, &txg); 72 if (txg == 0 || conf == NULL) 73 return (EINVAL); 74 75 VERIFY(nvlist_lookup_nvlist(conf, ZPOOL_CONFIG_VDEV_TREE, 76 &nvtop) == 0); 77 VERIFY(nvlist_lookup_string(nvtop, ZPOOL_CONFIG_TYPE, &type) == 0); 78 79 if (strcmp(type, VDEV_TYPE_DISK) == 0) { 80 if (spa_rootdev_validate(nvtop)) 81 goto out; 82 else 83 return (EINVAL); 84 } 85 86 ASSERT(strcmp(type, VDEV_TYPE_MIRROR) == 0); 87 88 VERIFY(nvlist_lookup_nvlist_array(nvtop, ZPOOL_CONFIG_CHILDREN, 89 &child, &children) == 0); 90 91 /* 92 * Go thru vdevs in the mirror to see if the given device (devpath) 93 * is in a healthy state. Also check if the given device has the most 94 * recent txg. Only the device with the most recent txg has valid 95 * information and can be booted. 96 */ 97 for (c = 0; c < children; c++) { 98 char *physpath; 99 100 if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_PHYS_PATH, 101 &physpath) != 0) 102 return (EINVAL); 103 104 if (strcmp(devpath, physpath) == 0) { 105 if (!spa_rootdev_validate(child[c])) 106 return (EINVAL); 107 } else { 108 /* get dev with the highest txg */ 109 if (spa_rootdev_validate(child[c])) { 110 spa_check_rootconf(physpath, &dev, 111 &conf, &txg); 112 } 113 } 114 } 115 116 /* Does the given device have the most recent txg? */ 117 if (strcmp(devpath, dev) != 0) 118 return (EINVAL); 119 out: 120 *bestdev = dev; 121 *bestconf = conf; 122 return (0); 123 } 124