xref: /illumos-gate/usr/src/uts/sparc/zfs/spa_boot.c (revision e7cbe64f7a72dae5cb44f100db60ca88f3313c65)
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