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