1*e7cbe64fSgw /* 2*e7cbe64fSgw * CDDL HEADER START 3*e7cbe64fSgw * 4*e7cbe64fSgw * The contents of this file are subject to the terms of the 5*e7cbe64fSgw * Common Development and Distribution License (the "License"). 6*e7cbe64fSgw * You may not use this file except in compliance with the License. 7*e7cbe64fSgw * 8*e7cbe64fSgw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*e7cbe64fSgw * or http://www.opensolaris.org/os/licensing. 10*e7cbe64fSgw * See the License for the specific language governing permissions 11*e7cbe64fSgw * and limitations under the License. 12*e7cbe64fSgw * 13*e7cbe64fSgw * When distributing Covered Code, include this CDDL HEADER in each 14*e7cbe64fSgw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*e7cbe64fSgw * If applicable, add the following below this CDDL HEADER, with the 16*e7cbe64fSgw * fields enclosed by brackets "[]" replaced with your own identifying 17*e7cbe64fSgw * information: Portions Copyright [yyyy] [name of copyright owner] 18*e7cbe64fSgw * 19*e7cbe64fSgw * CDDL HEADER END 20*e7cbe64fSgw */ 21*e7cbe64fSgw 22*e7cbe64fSgw /* 23*e7cbe64fSgw * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*e7cbe64fSgw * Use is subject to license terms. 25*e7cbe64fSgw */ 26*e7cbe64fSgw 27*e7cbe64fSgw #pragma ident "%Z%%M% %I% %E% SMI" 28*e7cbe64fSgw 29*e7cbe64fSgw #include <sys/spa.h> 30*e7cbe64fSgw #include <sys/sunddi.h> 31*e7cbe64fSgw 32*e7cbe64fSgw char * 33*e7cbe64fSgw spa_get_bootfs() 34*e7cbe64fSgw { 35*e7cbe64fSgw char *zfs_bp; 36*e7cbe64fSgw 37*e7cbe64fSgw if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 38*e7cbe64fSgw DDI_PROP_DONTPASS, "zfs-bootfs", &zfs_bp) != 39*e7cbe64fSgw DDI_SUCCESS) 40*e7cbe64fSgw return (NULL); 41*e7cbe64fSgw return (zfs_bp); 42*e7cbe64fSgw } 43*e7cbe64fSgw 44*e7cbe64fSgw void 45*e7cbe64fSgw spa_free_bootfs(char *bootfs) 46*e7cbe64fSgw { 47*e7cbe64fSgw ddi_prop_free(bootfs); 48*e7cbe64fSgw } 49*e7cbe64fSgw 50*e7cbe64fSgw /* 51*e7cbe64fSgw * Calculate how many device pathnames are in devpath_list. 52*e7cbe64fSgw * The devpath_list could look like this: 53*e7cbe64fSgw * 54*e7cbe64fSgw * "/pci@1f,0/ide@d/disk@0,0:a /pci@1f,o/ide@d/disk@2,0:a" 55*e7cbe64fSgw */ 56*e7cbe64fSgw static int 57*e7cbe64fSgw spa_count_devpath(char *devpath_list) 58*e7cbe64fSgw { 59*e7cbe64fSgw int numpath; 60*e7cbe64fSgw char *tmp_path, *blank; 61*e7cbe64fSgw 62*e7cbe64fSgw numpath = 0; 63*e7cbe64fSgw tmp_path = devpath_list; 64*e7cbe64fSgw 65*e7cbe64fSgw /* skip leading blanks */ 66*e7cbe64fSgw while (*tmp_path == ' ') 67*e7cbe64fSgw tmp_path++; 68*e7cbe64fSgw 69*e7cbe64fSgw while ((blank = strchr(tmp_path, ' ')) != NULL) { 70*e7cbe64fSgw 71*e7cbe64fSgw numpath++; 72*e7cbe64fSgw /* skip contiguous blanks */ 73*e7cbe64fSgw while (*blank == ' ') 74*e7cbe64fSgw blank++; 75*e7cbe64fSgw tmp_path = blank; 76*e7cbe64fSgw } 77*e7cbe64fSgw 78*e7cbe64fSgw if (strlen(tmp_path) > 0) 79*e7cbe64fSgw numpath++; 80*e7cbe64fSgw 81*e7cbe64fSgw return (numpath); 82*e7cbe64fSgw } 83*e7cbe64fSgw 84*e7cbe64fSgw /* 85*e7cbe64fSgw * Only allow booting the device if it has the same vdev information as 86*e7cbe64fSgw * the most recently updated vdev (highest txg) and is in a valid state. 87*e7cbe64fSgw * 88*e7cbe64fSgw * GRUB passes online/active device path names, e.g. 89*e7cbe64fSgw * "/pci@1f,0/ide@d/disk@0,0:a /pci@1f,o/ide@d/disk@2,0:a" 90*e7cbe64fSgw * to the kernel. The best vdev should have the same matching online/active 91*e7cbe64fSgw * list as what GRUB passes in. 92*e7cbe64fSgw */ 93*e7cbe64fSgw static int 94*e7cbe64fSgw spa_check_devstate(char *devpath_list, char *dev, nvlist_t *conf) 95*e7cbe64fSgw { 96*e7cbe64fSgw nvlist_t *nvtop, **child; 97*e7cbe64fSgw uint_t label_path, grub_path, c, children; 98*e7cbe64fSgw char *type; 99*e7cbe64fSgw 100*e7cbe64fSgw VERIFY(nvlist_lookup_nvlist(conf, ZPOOL_CONFIG_VDEV_TREE, 101*e7cbe64fSgw &nvtop) == 0); 102*e7cbe64fSgw VERIFY(nvlist_lookup_string(nvtop, ZPOOL_CONFIG_TYPE, &type) == 0); 103*e7cbe64fSgw 104*e7cbe64fSgw if (strcmp(type, VDEV_TYPE_DISK) == 0) 105*e7cbe64fSgw return (spa_rootdev_validate(nvtop)? 0 : EINVAL); 106*e7cbe64fSgw 107*e7cbe64fSgw ASSERT(strcmp(type, VDEV_TYPE_MIRROR) == 0); 108*e7cbe64fSgw 109*e7cbe64fSgw VERIFY(nvlist_lookup_nvlist_array(nvtop, ZPOOL_CONFIG_CHILDREN, 110*e7cbe64fSgw &child, &children) == 0); 111*e7cbe64fSgw 112*e7cbe64fSgw /* 113*e7cbe64fSgw * Check if the devpath_list is the same as the path list in conf. 114*e7cbe64fSgw * If these two lists are different, then the booting device is not an 115*e7cbe64fSgw * up-to-date device that can be booted. 116*e7cbe64fSgw */ 117*e7cbe64fSgw label_path = 0; 118*e7cbe64fSgw for (c = 0; c < children; c++) { 119*e7cbe64fSgw char *physpath; 120*e7cbe64fSgw 121*e7cbe64fSgw if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_PHYS_PATH, 122*e7cbe64fSgw &physpath) != 0) 123*e7cbe64fSgw return (EINVAL); 124*e7cbe64fSgw 125*e7cbe64fSgw if (spa_rootdev_validate(child[c])) { 126*e7cbe64fSgw if (strstr(devpath_list, physpath) == NULL) 127*e7cbe64fSgw return (EINVAL); 128*e7cbe64fSgw label_path++; 129*e7cbe64fSgw } else { 130*e7cbe64fSgw char *blank; 131*e7cbe64fSgw 132*e7cbe64fSgw if (blank = strchr(dev, ' ')) 133*e7cbe64fSgw *blank = '\0'; 134*e7cbe64fSgw if (strcmp(physpath, dev) == 0) 135*e7cbe64fSgw return (EINVAL); 136*e7cbe64fSgw if (blank) 137*e7cbe64fSgw *blank = ' '; 138*e7cbe64fSgw } 139*e7cbe64fSgw } 140*e7cbe64fSgw 141*e7cbe64fSgw grub_path = spa_count_devpath(devpath_list); 142*e7cbe64fSgw 143*e7cbe64fSgw if (label_path != grub_path) 144*e7cbe64fSgw return (EINVAL); 145*e7cbe64fSgw 146*e7cbe64fSgw return (0); 147*e7cbe64fSgw } 148*e7cbe64fSgw 149*e7cbe64fSgw /* 150*e7cbe64fSgw * Given a list of vdev physpath names, pick the vdev with the most recent txg, 151*e7cbe64fSgw * and return the point of the device's physpath in the list and the device's 152*e7cbe64fSgw * label configuration. The content of the label would be the most recent 153*e7cbe64fSgw * updated information. 154*e7cbe64fSgw */ 155*e7cbe64fSgw int 156*e7cbe64fSgw spa_get_rootconf(char *devpath_list, char **bestdev, nvlist_t **bestconf) 157*e7cbe64fSgw { 158*e7cbe64fSgw nvlist_t *conf = NULL; 159*e7cbe64fSgw char *dev = NULL; 160*e7cbe64fSgw uint64_t txg = 0; 161*e7cbe64fSgw char *devpath, *blank; 162*e7cbe64fSgw 163*e7cbe64fSgw devpath = devpath_list; 164*e7cbe64fSgw dev = devpath; 165*e7cbe64fSgw 166*e7cbe64fSgw while (devpath[0] == ' ') 167*e7cbe64fSgw devpath++; 168*e7cbe64fSgw 169*e7cbe64fSgw while ((blank = strchr(devpath, ' ')) != NULL) { 170*e7cbe64fSgw *blank = '\0'; 171*e7cbe64fSgw spa_check_rootconf(devpath, &dev, &conf, &txg); 172*e7cbe64fSgw *blank = ' '; 173*e7cbe64fSgw 174*e7cbe64fSgw while (*blank == ' ') 175*e7cbe64fSgw blank++; 176*e7cbe64fSgw devpath = blank; 177*e7cbe64fSgw } 178*e7cbe64fSgw 179*e7cbe64fSgw /* for the only or the last devpath in the devpath_list */ 180*e7cbe64fSgw if (strlen(devpath) > 0) 181*e7cbe64fSgw spa_check_rootconf(devpath, &dev, &conf, &txg); 182*e7cbe64fSgw 183*e7cbe64fSgw if (conf == NULL) 184*e7cbe64fSgw return (EINVAL); 185*e7cbe64fSgw 186*e7cbe64fSgw /* 187*e7cbe64fSgw * dev/conf is the vdev with the most recent txg. 188*e7cbe64fSgw * Check if the device is in a bootable state. 189*e7cbe64fSgw * dev may have a trailing blank since it points to a string 190*e7cbe64fSgw * in the devpath_list. 191*e7cbe64fSgw */ 192*e7cbe64fSgw if (spa_check_devstate(devpath_list, dev, conf) != 0) 193*e7cbe64fSgw return (EINVAL); 194*e7cbe64fSgw 195*e7cbe64fSgw *bestdev = dev; 196*e7cbe64fSgw *bestconf = conf; 197*e7cbe64fSgw return (0); 198*e7cbe64fSgw } 199