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 https://opensource.org/licenses/CDDL-1.0.
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011 by Delphix. All rights reserved.
25  * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
26  */
27 
28 
29 #include <sys/zfs_context.h>
30 #include <sys/fm/fs/zfs.h>
31 #include <sys/spa_impl.h>
32 #include <sys/zio.h>
33 #include <sys/zio_checksum.h>
34 #include <sys/dmu.h>
35 #include <sys/dmu_tx.h>
36 #include <sys/zap.h>
37 #include <sys/zil.h>
38 #include <sys/ddt.h>
39 #include <sys/vdev_impl.h>
40 #include <sys/vdev_os.h>
41 #include <sys/vdev_removal.h>
42 #include <sys/vdev_indirect_mapping.h>
43 #include <sys/vdev_indirect_births.h>
44 #include <sys/metaslab.h>
45 #include <sys/metaslab_impl.h>
46 #include <sys/uberblock_impl.h>
47 #include <sys/txg.h>
48 #include <sys/avl.h>
49 #include <sys/bpobj.h>
50 #include <sys/dmu_traverse.h>
51 #include <sys/dmu_objset.h>
52 #include <sys/unique.h>
53 #include <sys/dsl_pool.h>
54 #include <sys/dsl_dataset.h>
55 #include <sys/dsl_dir.h>
56 #include <sys/dsl_prop.h>
57 #include <sys/dsl_synctask.h>
58 #include <sys/fs/zfs.h>
59 #include <sys/arc.h>
60 #include <sys/callb.h>
61 #include <sys/zfs_ioctl.h>
62 #include <sys/dsl_scan.h>
63 #include <sys/dmu_send.h>
64 #include <sys/dsl_destroy.h>
65 #include <sys/dsl_userhold.h>
66 #include <sys/zfeature.h>
67 #include <sys/zvol.h>
68 #include <sys/abd.h>
69 #include <sys/callb.h>
70 #include <sys/zone.h>
71 
72 #include "zfs_prop.h"
73 #include "zfs_comutil.h"
74 
75 static nvlist_t *
76 spa_generate_rootconf(const char *name)
77 {
78 	nvlist_t **configs, **tops;
79 	nvlist_t *config;
80 	nvlist_t *best_cfg, *nvtop, *nvroot;
81 	uint64_t *holes;
82 	uint64_t best_txg;
83 	uint64_t nchildren;
84 	uint64_t pgid;
85 	uint64_t count;
86 	uint64_t i;
87 	uint_t   nholes;
88 
89 	if (vdev_geom_read_pool_label(name, &configs, &count) != 0)
90 		return (NULL);
91 
92 	ASSERT3U(count, !=, 0);
93 	best_txg = 0;
94 	for (i = 0; i < count; i++) {
95 		uint64_t txg;
96 
97 		txg = fnvlist_lookup_uint64(configs[i], ZPOOL_CONFIG_POOL_TXG);
98 		if (txg > best_txg) {
99 			best_txg = txg;
100 			best_cfg = configs[i];
101 		}
102 	}
103 
104 	nchildren = 1;
105 	nvlist_lookup_uint64(best_cfg, ZPOOL_CONFIG_VDEV_CHILDREN, &nchildren);
106 	holes = NULL;
107 	nvlist_lookup_uint64_array(best_cfg, ZPOOL_CONFIG_HOLE_ARRAY,
108 	    &holes, &nholes);
109 
110 	tops = kmem_zalloc(nchildren * sizeof (void *), KM_SLEEP);
111 	for (i = 0; i < nchildren; i++) {
112 		if (i >= count)
113 			break;
114 		if (configs[i] == NULL)
115 			continue;
116 		nvtop = fnvlist_lookup_nvlist(configs[i],
117 		    ZPOOL_CONFIG_VDEV_TREE);
118 		tops[i] = fnvlist_dup(nvtop);
119 	}
120 	for (i = 0; holes != NULL && i < nholes; i++) {
121 		if (i >= nchildren)
122 			continue;
123 		if (tops[holes[i]] != NULL)
124 			continue;
125 		tops[holes[i]] = fnvlist_alloc();
126 		fnvlist_add_string(tops[holes[i]], ZPOOL_CONFIG_TYPE,
127 		    VDEV_TYPE_HOLE);
128 		fnvlist_add_uint64(tops[holes[i]], ZPOOL_CONFIG_ID, holes[i]);
129 		fnvlist_add_uint64(tops[holes[i]], ZPOOL_CONFIG_GUID, 0);
130 	}
131 	for (i = 0; i < nchildren; i++) {
132 		if (tops[i] != NULL)
133 			continue;
134 		tops[i] = fnvlist_alloc();
135 		fnvlist_add_string(tops[i], ZPOOL_CONFIG_TYPE,
136 		    VDEV_TYPE_MISSING);
137 		fnvlist_add_uint64(tops[i], ZPOOL_CONFIG_ID, i);
138 		fnvlist_add_uint64(tops[i], ZPOOL_CONFIG_GUID, 0);
139 	}
140 
141 	/*
142 	 * Create pool config based on the best vdev config.
143 	 */
144 	config = fnvlist_dup(best_cfg);
145 
146 	/*
147 	 * Put this pool's top-level vdevs into a root vdev.
148 	 */
149 	pgid = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID);
150 	nvroot = fnvlist_alloc();
151 	fnvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT);
152 	fnvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL);
153 	fnvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, pgid);
154 	fnvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
155 	    (const nvlist_t * const *)tops, nchildren);
156 
157 	/*
158 	 * Replace the existing vdev_tree with the new root vdev in
159 	 * this pool's configuration (remove the old, add the new).
160 	 */
161 	fnvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot);
162 
163 	/*
164 	 * Drop vdev config elements that should not be present at pool level.
165 	 */
166 	fnvlist_remove(config, ZPOOL_CONFIG_GUID);
167 	fnvlist_remove(config, ZPOOL_CONFIG_TOP_GUID);
168 
169 	for (i = 0; i < count; i++)
170 		fnvlist_free(configs[i]);
171 	kmem_free(configs, count * sizeof (void *));
172 	for (i = 0; i < nchildren; i++)
173 		fnvlist_free(tops[i]);
174 	kmem_free(tops, nchildren * sizeof (void *));
175 	fnvlist_free(nvroot);
176 	return (config);
177 }
178 
179 int
180 spa_import_rootpool(const char *name, bool checkpointrewind)
181 {
182 	spa_t *spa;
183 	vdev_t *rvd;
184 	nvlist_t *config, *nvtop;
185 	char *pname;
186 	int error;
187 
188 	/*
189 	 * Read the label from the boot device and generate a configuration.
190 	 */
191 	config = spa_generate_rootconf(name);
192 
193 	mutex_enter(&spa_namespace_lock);
194 	if (config != NULL) {
195 		pname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
196 		VERIFY0(strcmp(name, pname));
197 
198 		if ((spa = spa_lookup(pname)) != NULL) {
199 			/*
200 			 * The pool could already be imported,
201 			 * e.g., after reboot -r.
202 			 */
203 			if (spa->spa_state == POOL_STATE_ACTIVE) {
204 				mutex_exit(&spa_namespace_lock);
205 				fnvlist_free(config);
206 				return (0);
207 			}
208 
209 			/*
210 			 * Remove the existing root pool from the namespace so
211 			 * that we can replace it with the correct config
212 			 * we just read in.
213 			 */
214 			spa_remove(spa);
215 		}
216 		spa = spa_add(pname, config, NULL);
217 
218 		/*
219 		 * Set spa_ubsync.ub_version as it can be used in vdev_alloc()
220 		 * via spa_version().
221 		 */
222 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
223 		    &spa->spa_ubsync.ub_version) != 0)
224 			spa->spa_ubsync.ub_version = SPA_VERSION_INITIAL;
225 	} else if ((spa = spa_lookup(name)) == NULL) {
226 		mutex_exit(&spa_namespace_lock);
227 		fnvlist_free(config);
228 		cmn_err(CE_NOTE, "Cannot find the pool label for '%s'",
229 		    name);
230 		return (EIO);
231 	} else {
232 		config = fnvlist_dup(spa->spa_config);
233 	}
234 	spa->spa_is_root = B_TRUE;
235 	spa->spa_import_flags = ZFS_IMPORT_VERBATIM;
236 	if (checkpointrewind) {
237 		spa->spa_import_flags |= ZFS_IMPORT_CHECKPOINT;
238 	}
239 
240 	/*
241 	 * Build up a vdev tree based on the boot device's label config.
242 	 */
243 	nvtop = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
244 	spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
245 	error = spa_config_parse(spa, &rvd, nvtop, NULL, 0,
246 	    VDEV_ALLOC_ROOTPOOL);
247 	spa_config_exit(spa, SCL_ALL, FTAG);
248 	if (error) {
249 		mutex_exit(&spa_namespace_lock);
250 		fnvlist_free(config);
251 		cmn_err(CE_NOTE, "Can not parse the config for pool '%s'",
252 		    name);
253 		return (error);
254 	}
255 
256 	spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
257 	vdev_free(rvd);
258 	spa_config_exit(spa, SCL_ALL, FTAG);
259 	mutex_exit(&spa_namespace_lock);
260 
261 	fnvlist_free(config);
262 	return (0);
263 }
264 
265 const char *
266 spa_history_zone(void)
267 {
268 	return ("freebsd");
269 }
270 
271 void
272 spa_import_os(spa_t *spa)
273 {
274 	(void) spa;
275 }
276 
277 void
278 spa_export_os(spa_t *spa)
279 {
280 	(void) spa;
281 }
282 
283 void
284 spa_activate_os(spa_t *spa)
285 {
286 	(void) spa;
287 }
288 
289 void
290 spa_deactivate_os(spa_t *spa)
291 {
292 	(void) spa;
293 }
294