xref: /illumos-gate/usr/src/uts/sparc/zfs/spa_boot.c (revision e7cbe64f7a72dae5cb44f100db60ca88f3313c65)
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/bootconf.h>
31*e7cbe64fSgw 
32*e7cbe64fSgw char *
33*e7cbe64fSgw spa_get_bootfs()
34*e7cbe64fSgw {
35*e7cbe64fSgw 	int proplen;
36*e7cbe64fSgw 	char *zfs_bp;
37*e7cbe64fSgw 
38*e7cbe64fSgw 	proplen = BOP_GETPROPLEN(bootops, "zfs-bootfs");
39*e7cbe64fSgw 	if (proplen == 0)
40*e7cbe64fSgw 		return (NULL);
41*e7cbe64fSgw 
42*e7cbe64fSgw 	zfs_bp = kmem_zalloc(proplen, KM_SLEEP);
43*e7cbe64fSgw 	if (BOP_GETPROP(bootops, "zfs-bootfs", zfs_bp) == -1) {
44*e7cbe64fSgw 		kmem_free(zfs_bp, proplen);
45*e7cbe64fSgw 		return (NULL);
46*e7cbe64fSgw 	}
47*e7cbe64fSgw 
48*e7cbe64fSgw 	return (zfs_bp);
49*e7cbe64fSgw }
50*e7cbe64fSgw 
51*e7cbe64fSgw void
52*e7cbe64fSgw spa_free_bootfs(char *bootfs)
53*e7cbe64fSgw {
54*e7cbe64fSgw 	kmem_free(bootfs, strlen(bootfs) + 1);
55*e7cbe64fSgw }
56*e7cbe64fSgw 
57*e7cbe64fSgw /*
58*e7cbe64fSgw  * Given the boot device physpath, check if the device is in a valid state.
59*e7cbe64fSgw  * If so, return the configuration from the vdev label.
60*e7cbe64fSgw  */
61*e7cbe64fSgw int
62*e7cbe64fSgw spa_get_rootconf(char *devpath, char **bestdev, nvlist_t **bestconf)
63*e7cbe64fSgw {
64*e7cbe64fSgw 	nvlist_t *conf = NULL;
65*e7cbe64fSgw 	char *dev = NULL;
66*e7cbe64fSgw 	uint64_t txg = 0;
67*e7cbe64fSgw 	nvlist_t *nvtop, **child;
68*e7cbe64fSgw 	char *type;
69*e7cbe64fSgw 	uint_t children, c;
70*e7cbe64fSgw 
71*e7cbe64fSgw 	spa_check_rootconf(devpath, &dev, &conf, &txg);
72*e7cbe64fSgw 	if (txg == 0 || conf == NULL)
73*e7cbe64fSgw 		return (EINVAL);
74*e7cbe64fSgw 
75*e7cbe64fSgw 	VERIFY(nvlist_lookup_nvlist(conf, ZPOOL_CONFIG_VDEV_TREE,
76*e7cbe64fSgw 	    &nvtop) == 0);
77*e7cbe64fSgw 	VERIFY(nvlist_lookup_string(nvtop, ZPOOL_CONFIG_TYPE, &type) == 0);
78*e7cbe64fSgw 
79*e7cbe64fSgw 	if (strcmp(type, VDEV_TYPE_DISK) == 0) {
80*e7cbe64fSgw 		if (spa_rootdev_validate(nvtop))
81*e7cbe64fSgw 			goto out;
82*e7cbe64fSgw 		else
83*e7cbe64fSgw 			return (EINVAL);
84*e7cbe64fSgw 	}
85*e7cbe64fSgw 
86*e7cbe64fSgw 	ASSERT(strcmp(type, VDEV_TYPE_MIRROR) == 0);
87*e7cbe64fSgw 
88*e7cbe64fSgw 	VERIFY(nvlist_lookup_nvlist_array(nvtop, ZPOOL_CONFIG_CHILDREN,
89*e7cbe64fSgw 	    &child, &children) == 0);
90*e7cbe64fSgw 
91*e7cbe64fSgw 	/*
92*e7cbe64fSgw 	 * Go thru vdevs in the mirror to see if the given device (devpath)
93*e7cbe64fSgw 	 * is in a healthy state. Also check if the given device has the most
94*e7cbe64fSgw 	 * recent txg. Only the device with the most recent txg has valid
95*e7cbe64fSgw 	 * information and can be booted.
96*e7cbe64fSgw 	 */
97*e7cbe64fSgw 	for (c = 0; c < children; c++) {
98*e7cbe64fSgw 		char *physpath;
99*e7cbe64fSgw 
100*e7cbe64fSgw 		if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_PHYS_PATH,
101*e7cbe64fSgw 		    &physpath) != 0)
102*e7cbe64fSgw 			return (EINVAL);
103*e7cbe64fSgw 
104*e7cbe64fSgw 		if (strcmp(devpath, physpath) == 0) {
105*e7cbe64fSgw 			if (!spa_rootdev_validate(child[c]))
106*e7cbe64fSgw 				return (EINVAL);
107*e7cbe64fSgw 		} else {
108*e7cbe64fSgw 			/* get dev with the highest txg */
109*e7cbe64fSgw 			if (spa_rootdev_validate(child[c])) {
110*e7cbe64fSgw 				spa_check_rootconf(physpath, &dev,
111*e7cbe64fSgw 				    &conf, &txg);
112*e7cbe64fSgw 			}
113*e7cbe64fSgw 		}
114*e7cbe64fSgw 	}
115*e7cbe64fSgw 
116*e7cbe64fSgw 	/* Does the given device have the most recent txg? */
117*e7cbe64fSgw 	if (strcmp(devpath, dev) != 0)
118*e7cbe64fSgw 		return (EINVAL);
119*e7cbe64fSgw out:
120*e7cbe64fSgw 	*bestdev = dev;
121*e7cbe64fSgw 	*bestconf = conf;
122*e7cbe64fSgw 	return (0);
123*e7cbe64fSgw }
124