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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2012 by Delphix. All rights reserved. 29 * Copyright (c) 2015 by Syneto S.R.L. All rights reserved. 30 * Copyright 2016 Nexenta Systems, Inc. 31 */ 32 33 /* 34 * The pool configuration repository is stored in /etc/zfs/zpool.cache as a 35 * single packed nvlist. While it would be nice to just read in this 36 * file from userland, this wouldn't work from a local zone. So we have to have 37 * a zpool ioctl to return the complete configuration for all pools. In the 38 * global zone, this will be identical to reading the file and unpacking it in 39 * userland. 40 */ 41 42 #include <errno.h> 43 #include <sys/stat.h> 44 #include <fcntl.h> 45 #include <stddef.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <libintl.h> 49 #include <libuutil.h> 50 51 #include "libzfs_impl.h" 52 53 typedef struct config_node { 54 char *cn_name; 55 nvlist_t *cn_config; 56 uu_avl_node_t cn_avl; 57 } config_node_t; 58 59 /* ARGSUSED */ 60 static int 61 config_node_compare(const void *a, const void *b, void *unused) 62 { 63 int ret; 64 65 const config_node_t *ca = (config_node_t *)a; 66 const config_node_t *cb = (config_node_t *)b; 67 68 ret = strcmp(ca->cn_name, cb->cn_name); 69 70 if (ret < 0) 71 return (-1); 72 else if (ret > 0) 73 return (1); 74 else 75 return (0); 76 } 77 78 void 79 namespace_clear(libzfs_handle_t *hdl) 80 { 81 if (hdl->libzfs_ns_avl) { 82 config_node_t *cn; 83 void *cookie = NULL; 84 85 while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, 86 &cookie)) != NULL) { 87 nvlist_free(cn->cn_config); 88 free(cn->cn_name); 89 free(cn); 90 } 91 92 uu_avl_destroy(hdl->libzfs_ns_avl); 93 hdl->libzfs_ns_avl = NULL; 94 } 95 96 if (hdl->libzfs_ns_avlpool) { 97 uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); 98 hdl->libzfs_ns_avlpool = NULL; 99 } 100 } 101 102 /* 103 * Loads the pool namespace, or re-loads it if the cache has changed. 104 */ 105 static int 106 namespace_reload(libzfs_handle_t *hdl) 107 { 108 nvlist_t *config; 109 config_node_t *cn; 110 nvpair_t *elem; 111 zfs_cmd_t zc = {"\0"}; 112 void *cookie; 113 114 if (hdl->libzfs_ns_gen == 0) { 115 /* 116 * This is the first time we've accessed the configuration 117 * cache. Initialize the AVL tree and then fall through to the 118 * common code. 119 */ 120 if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", 121 sizeof (config_node_t), 122 offsetof(config_node_t, cn_avl), 123 config_node_compare, UU_DEFAULT)) == NULL) 124 return (no_memory(hdl)); 125 126 if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, 127 NULL, UU_DEFAULT)) == NULL) 128 return (no_memory(hdl)); 129 } 130 131 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 132 return (-1); 133 134 for (;;) { 135 zc.zc_cookie = hdl->libzfs_ns_gen; 136 if (zfs_ioctl(hdl, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 137 switch (errno) { 138 case EEXIST: 139 /* 140 * The namespace hasn't changed. 141 */ 142 zcmd_free_nvlists(&zc); 143 return (0); 144 145 case ENOMEM: 146 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 147 zcmd_free_nvlists(&zc); 148 return (-1); 149 } 150 break; 151 152 default: 153 zcmd_free_nvlists(&zc); 154 return (zfs_standard_error(hdl, errno, 155 dgettext(TEXT_DOMAIN, "failed to read " 156 "pool configuration"))); 157 } 158 } else { 159 hdl->libzfs_ns_gen = zc.zc_cookie; 160 break; 161 } 162 } 163 164 if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 165 zcmd_free_nvlists(&zc); 166 return (-1); 167 } 168 169 zcmd_free_nvlists(&zc); 170 171 /* 172 * Clear out any existing configuration information. 173 */ 174 cookie = NULL; 175 while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) { 176 nvlist_free(cn->cn_config); 177 free(cn->cn_name); 178 free(cn); 179 } 180 181 elem = NULL; 182 while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 183 nvlist_t *child; 184 uu_avl_index_t where; 185 186 if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 187 nvlist_free(config); 188 return (-1); 189 } 190 191 if ((cn->cn_name = zfs_strdup(hdl, 192 nvpair_name(elem))) == NULL) { 193 free(cn); 194 nvlist_free(config); 195 return (-1); 196 } 197 198 verify(nvpair_value_nvlist(elem, &child) == 0); 199 if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 200 free(cn->cn_name); 201 free(cn); 202 nvlist_free(config); 203 return (no_memory(hdl)); 204 } 205 verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 206 == NULL); 207 208 uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 209 } 210 211 nvlist_free(config); 212 return (0); 213 } 214 215 /* 216 * Retrieve the configuration for the given pool. The configuration is an nvlist 217 * describing the vdevs, as well as the statistics associated with each one. 218 */ 219 nvlist_t * 220 zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 221 { 222 if (oldconfig) 223 *oldconfig = zhp->zpool_old_config; 224 return (zhp->zpool_config); 225 } 226 227 /* 228 * Retrieves a list of enabled features and their refcounts and caches it in 229 * the pool handle. 230 */ 231 nvlist_t * 232 zpool_get_features(zpool_handle_t *zhp) 233 { 234 nvlist_t *config, *features; 235 236 config = zpool_get_config(zhp, NULL); 237 238 if (config == NULL || !nvlist_exists(config, 239 ZPOOL_CONFIG_FEATURE_STATS)) { 240 int error; 241 boolean_t missing = B_FALSE; 242 243 error = zpool_refresh_stats(zhp, &missing); 244 245 if (error != 0 || missing) 246 return (NULL); 247 248 config = zpool_get_config(zhp, NULL); 249 } 250 251 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, 252 &features) != 0) 253 return (NULL); 254 255 return (features); 256 } 257 258 /* 259 * Refresh the vdev statistics associated with the given pool. This is used in 260 * iostat to show configuration changes and determine the delta from the last 261 * time the function was called. This function can fail, in case the pool has 262 * been destroyed. 263 */ 264 int 265 zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 266 { 267 zfs_cmd_t zc = {"\0"}; 268 int error; 269 nvlist_t *config; 270 libzfs_handle_t *hdl = zhp->zpool_hdl; 271 272 *missing = B_FALSE; 273 (void) strcpy(zc.zc_name, zhp->zpool_name); 274 275 if (zhp->zpool_config_size == 0) 276 zhp->zpool_config_size = 1 << 16; 277 278 if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0) 279 return (-1); 280 281 for (;;) { 282 if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_STATS, 283 &zc) == 0) { 284 /* 285 * The real error is returned in the zc_cookie field. 286 */ 287 error = zc.zc_cookie; 288 break; 289 } 290 291 if (errno == ENOMEM) { 292 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 293 zcmd_free_nvlists(&zc); 294 return (-1); 295 } 296 } else { 297 zcmd_free_nvlists(&zc); 298 if (errno == ENOENT || errno == EINVAL) 299 *missing = B_TRUE; 300 zhp->zpool_state = POOL_STATE_UNAVAIL; 301 return (0); 302 } 303 } 304 305 if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 306 zcmd_free_nvlists(&zc); 307 return (-1); 308 } 309 310 zcmd_free_nvlists(&zc); 311 312 zhp->zpool_config_size = zc.zc_nvlist_dst_size; 313 314 if (zhp->zpool_config != NULL) { 315 nvlist_free(zhp->zpool_old_config); 316 317 zhp->zpool_old_config = zhp->zpool_config; 318 } 319 320 zhp->zpool_config = config; 321 if (error) 322 zhp->zpool_state = POOL_STATE_UNAVAIL; 323 else 324 zhp->zpool_state = POOL_STATE_ACTIVE; 325 326 return (0); 327 } 328 329 /* 330 * The following environment variables are undocumented 331 * and should be used for testing purposes only: 332 * 333 * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists 334 * __ZFS_POOL_RESTRICT - iterate only over the pools it lists 335 * 336 * This function returns B_TRUE if the pool should be skipped 337 * during iteration. 338 */ 339 boolean_t 340 zpool_skip_pool(const char *poolname) 341 { 342 static boolean_t initialized = B_FALSE; 343 static const char *exclude = NULL; 344 static const char *restricted = NULL; 345 346 const char *cur, *end; 347 int len; 348 int namelen = strlen(poolname); 349 350 if (!initialized) { 351 initialized = B_TRUE; 352 exclude = getenv("__ZFS_POOL_EXCLUDE"); 353 restricted = getenv("__ZFS_POOL_RESTRICT"); 354 } 355 356 if (exclude != NULL) { 357 cur = exclude; 358 do { 359 end = strchr(cur, ' '); 360 len = (NULL == end) ? strlen(cur) : (end - cur); 361 if (len == namelen && 0 == strncmp(cur, poolname, len)) 362 return (B_TRUE); 363 cur += (len + 1); 364 } while (NULL != end); 365 } 366 367 if (NULL == restricted) 368 return (B_FALSE); 369 370 cur = restricted; 371 do { 372 end = strchr(cur, ' '); 373 len = (NULL == end) ? strlen(cur) : (end - cur); 374 375 if (len == namelen && 0 == strncmp(cur, poolname, len)) { 376 return (B_FALSE); 377 } 378 379 cur += (len + 1); 380 } while (NULL != end); 381 382 return (B_TRUE); 383 } 384 385 /* 386 * Iterate over all pools in the system. 387 */ 388 int 389 zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 390 { 391 config_node_t *cn; 392 zpool_handle_t *zhp; 393 int ret; 394 395 /* 396 * If someone makes a recursive call to zpool_iter(), we want to avoid 397 * refreshing the namespace because that will invalidate the parent 398 * context. We allow recursive calls, but simply re-use the same 399 * namespace AVL tree. 400 */ 401 if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0) 402 return (-1); 403 404 hdl->libzfs_pool_iter++; 405 for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 406 cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 407 408 if (zpool_skip_pool(cn->cn_name)) 409 continue; 410 411 if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) { 412 hdl->libzfs_pool_iter--; 413 return (-1); 414 } 415 416 if (zhp == NULL) 417 continue; 418 419 if ((ret = func(zhp, data)) != 0) { 420 hdl->libzfs_pool_iter--; 421 return (ret); 422 } 423 } 424 hdl->libzfs_pool_iter--; 425 426 return (0); 427 } 428 429 /* 430 * Iterate over root datasets, calling the given function for each. The zfs 431 * handle passed each time must be explicitly closed by the callback. 432 */ 433 int 434 zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 435 { 436 config_node_t *cn; 437 zfs_handle_t *zhp; 438 int ret; 439 440 if (namespace_reload(hdl) != 0) 441 return (-1); 442 443 for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 444 cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 445 446 if (zpool_skip_pool(cn->cn_name)) 447 continue; 448 449 if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 450 continue; 451 452 if ((ret = func(zhp, data)) != 0) 453 return (ret); 454 } 455 456 return (0); 457 } 458