1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21ad135b5dSChristopher Siden 22fa9e4066Sahrens /* 23069f55e2SEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens /* 28ad135b5dSChristopher Siden * Copyright (c) 2012 by Delphix. All rights reserved. 29b289d045SDan Vatca * Copyright (c) 2015 by Syneto S.R.L. All rights reserved. 30*8808ac5dSYuri Pankov * Copyright 2016 Nexenta Systems, Inc. 31ad135b5dSChristopher Siden */ 32ad135b5dSChristopher Siden 33ad135b5dSChristopher Siden /* 34fa9e4066Sahrens * The pool configuration repository is stored in /etc/zfs/zpool.cache as a 35fa9e4066Sahrens * single packed nvlist. While it would be nice to just read in this 36fa9e4066Sahrens * file from userland, this wouldn't work from a local zone. So we have to have 37fa9e4066Sahrens * a zpool ioctl to return the complete configuration for all pools. In the 38fa9e4066Sahrens * global zone, this will be identical to reading the file and unpacking it in 39fa9e4066Sahrens * userland. 40fa9e4066Sahrens */ 41fa9e4066Sahrens 42fa9e4066Sahrens #include <errno.h> 43fa9e4066Sahrens #include <sys/stat.h> 44fa9e4066Sahrens #include <fcntl.h> 45fa9e4066Sahrens #include <stddef.h> 46fa9e4066Sahrens #include <string.h> 47fa9e4066Sahrens #include <unistd.h> 48fa9e4066Sahrens #include <libintl.h> 49fa9e4066Sahrens #include <libuutil.h> 50fa9e4066Sahrens 51fa9e4066Sahrens #include "libzfs_impl.h" 52fa9e4066Sahrens 53fa9e4066Sahrens typedef struct config_node { 54fa9e4066Sahrens char *cn_name; 55fa9e4066Sahrens nvlist_t *cn_config; 56fa9e4066Sahrens uu_avl_node_t cn_avl; 57fa9e4066Sahrens } config_node_t; 58fa9e4066Sahrens 59fa9e4066Sahrens /* ARGSUSED */ 60fa9e4066Sahrens static int 61fa9e4066Sahrens config_node_compare(const void *a, const void *b, void *unused) 62fa9e4066Sahrens { 63fa9e4066Sahrens int ret; 64fa9e4066Sahrens 65fa9e4066Sahrens const config_node_t *ca = (config_node_t *)a; 66fa9e4066Sahrens const config_node_t *cb = (config_node_t *)b; 67fa9e4066Sahrens 68fa9e4066Sahrens ret = strcmp(ca->cn_name, cb->cn_name); 69fa9e4066Sahrens 70fa9e4066Sahrens if (ret < 0) 71fa9e4066Sahrens return (-1); 72fa9e4066Sahrens else if (ret > 0) 73fa9e4066Sahrens return (1); 74fa9e4066Sahrens else 75fa9e4066Sahrens return (0); 76fa9e4066Sahrens } 77fa9e4066Sahrens 7899653d4eSeschrock void 7999653d4eSeschrock namespace_clear(libzfs_handle_t *hdl) 8099653d4eSeschrock { 8199653d4eSeschrock if (hdl->libzfs_ns_avl) { 8299653d4eSeschrock config_node_t *cn; 8368f944b7Seschrock void *cookie = NULL; 8499653d4eSeschrock 8568f944b7Seschrock while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, 8668f944b7Seschrock &cookie)) != NULL) { 8799653d4eSeschrock nvlist_free(cn->cn_config); 8899653d4eSeschrock free(cn->cn_name); 8999653d4eSeschrock free(cn); 9099653d4eSeschrock } 9199653d4eSeschrock 9299653d4eSeschrock uu_avl_destroy(hdl->libzfs_ns_avl); 9399653d4eSeschrock hdl->libzfs_ns_avl = NULL; 9499653d4eSeschrock } 9599653d4eSeschrock 9699653d4eSeschrock if (hdl->libzfs_ns_avlpool) { 9799653d4eSeschrock uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); 9899653d4eSeschrock hdl->libzfs_ns_avlpool = NULL; 9999653d4eSeschrock } 10099653d4eSeschrock } 10199653d4eSeschrock 102fa9e4066Sahrens /* 103fa9e4066Sahrens * Loads the pool namespace, or re-loads it if the cache has changed. 104fa9e4066Sahrens */ 10599653d4eSeschrock static int 10699653d4eSeschrock namespace_reload(libzfs_handle_t *hdl) 107fa9e4066Sahrens { 108fa9e4066Sahrens nvlist_t *config; 109fa9e4066Sahrens config_node_t *cn; 110fa9e4066Sahrens nvpair_t *elem; 111fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 11268f944b7Seschrock void *cookie; 113fa9e4066Sahrens 11499653d4eSeschrock if (hdl->libzfs_ns_gen == 0) { 115fa9e4066Sahrens /* 116fa9e4066Sahrens * This is the first time we've accessed the configuration 117fa9e4066Sahrens * cache. Initialize the AVL tree and then fall through to the 118fa9e4066Sahrens * common code. 119fa9e4066Sahrens */ 12099653d4eSeschrock if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", 121fa9e4066Sahrens sizeof (config_node_t), 122fa9e4066Sahrens offsetof(config_node_t, cn_avl), 123fa9e4066Sahrens config_node_compare, UU_DEFAULT)) == NULL) 12499653d4eSeschrock return (no_memory(hdl)); 125fa9e4066Sahrens 12699653d4eSeschrock if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, 12799653d4eSeschrock NULL, UU_DEFAULT)) == NULL) 12899653d4eSeschrock return (no_memory(hdl)); 129fa9e4066Sahrens } 130fa9e4066Sahrens 131e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 13299653d4eSeschrock return (-1); 133e9dbad6fSeschrock 134fa9e4066Sahrens for (;;) { 13599653d4eSeschrock zc.zc_cookie = hdl->libzfs_ns_gen; 13699653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 137fa9e4066Sahrens switch (errno) { 138fa9e4066Sahrens case EEXIST: 139fa9e4066Sahrens /* 140fa9e4066Sahrens * The namespace hasn't changed. 141fa9e4066Sahrens */ 142e9dbad6fSeschrock zcmd_free_nvlists(&zc); 14399653d4eSeschrock return (0); 144fa9e4066Sahrens 145fa9e4066Sahrens case ENOMEM: 146e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 147e9dbad6fSeschrock zcmd_free_nvlists(&zc); 14899653d4eSeschrock return (-1); 149e9dbad6fSeschrock } 150fa9e4066Sahrens break; 151fa9e4066Sahrens 152fa9e4066Sahrens default: 153e9dbad6fSeschrock zcmd_free_nvlists(&zc); 15499653d4eSeschrock return (zfs_standard_error(hdl, errno, 15599653d4eSeschrock dgettext(TEXT_DOMAIN, "failed to read " 15699653d4eSeschrock "pool configuration"))); 157fa9e4066Sahrens } 158fa9e4066Sahrens } else { 15999653d4eSeschrock hdl->libzfs_ns_gen = zc.zc_cookie; 160fa9e4066Sahrens break; 161fa9e4066Sahrens } 162fa9e4066Sahrens } 163fa9e4066Sahrens 164e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 165e9dbad6fSeschrock zcmd_free_nvlists(&zc); 166e9dbad6fSeschrock return (-1); 16794de1d4cSeschrock } 168fa9e4066Sahrens 169e9dbad6fSeschrock zcmd_free_nvlists(&zc); 170fa9e4066Sahrens 171fa9e4066Sahrens /* 172fa9e4066Sahrens * Clear out any existing configuration information. 173fa9e4066Sahrens */ 17468f944b7Seschrock cookie = NULL; 17568f944b7Seschrock while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) { 176fa9e4066Sahrens nvlist_free(cn->cn_config); 177fa9e4066Sahrens free(cn->cn_name); 178fa9e4066Sahrens free(cn); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens elem = NULL; 182fa9e4066Sahrens while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 183fa9e4066Sahrens nvlist_t *child; 184fa9e4066Sahrens uu_avl_index_t where; 185fa9e4066Sahrens 18699653d4eSeschrock if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 18799653d4eSeschrock nvlist_free(config); 18899653d4eSeschrock return (-1); 18999653d4eSeschrock } 19099653d4eSeschrock 19199653d4eSeschrock if ((cn->cn_name = zfs_strdup(hdl, 19299653d4eSeschrock nvpair_name(elem))) == NULL) { 19399653d4eSeschrock free(cn); 1943bb79becSeschrock nvlist_free(config); 19599653d4eSeschrock return (-1); 19699653d4eSeschrock } 197fa9e4066Sahrens 198fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &child) == 0); 19999653d4eSeschrock if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 2003bb79becSeschrock free(cn->cn_name); 2013bb79becSeschrock free(cn); 20299653d4eSeschrock nvlist_free(config); 20399653d4eSeschrock return (no_memory(hdl)); 20499653d4eSeschrock } 20599653d4eSeschrock verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 20699653d4eSeschrock == NULL); 207fa9e4066Sahrens 20899653d4eSeschrock uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 209fa9e4066Sahrens } 210fa9e4066Sahrens 211fa9e4066Sahrens nvlist_free(config); 21299653d4eSeschrock return (0); 213fa9e4066Sahrens } 214fa9e4066Sahrens 215fa9e4066Sahrens /* 21668f944b7Seschrock * Retrieve the configuration for the given pool. The configuration is a nvlist 217fa9e4066Sahrens * describing the vdevs, as well as the statistics associated with each one. 218fa9e4066Sahrens */ 219fa9e4066Sahrens nvlist_t * 220088e9d47Seschrock zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 221fa9e4066Sahrens { 222088e9d47Seschrock if (oldconfig) 223088e9d47Seschrock *oldconfig = zhp->zpool_old_config; 224fa9e4066Sahrens return (zhp->zpool_config); 225fa9e4066Sahrens } 226fa9e4066Sahrens 227fa9e4066Sahrens /* 228ad135b5dSChristopher Siden * Retrieves a list of enabled features and their refcounts and caches it in 229ad135b5dSChristopher Siden * the pool handle. 230ad135b5dSChristopher Siden */ 231ad135b5dSChristopher Siden nvlist_t * 232ad135b5dSChristopher Siden zpool_get_features(zpool_handle_t *zhp) 233ad135b5dSChristopher Siden { 234ad135b5dSChristopher Siden nvlist_t *config, *features; 235ad135b5dSChristopher Siden 236ad135b5dSChristopher Siden config = zpool_get_config(zhp, NULL); 237ad135b5dSChristopher Siden 238ad135b5dSChristopher Siden if (config == NULL || !nvlist_exists(config, 239ad135b5dSChristopher Siden ZPOOL_CONFIG_FEATURE_STATS)) { 240ad135b5dSChristopher Siden int error; 241ad135b5dSChristopher Siden boolean_t missing = B_FALSE; 242ad135b5dSChristopher Siden 243ad135b5dSChristopher Siden error = zpool_refresh_stats(zhp, &missing); 244ad135b5dSChristopher Siden 245ad135b5dSChristopher Siden if (error != 0 || missing) 246ad135b5dSChristopher Siden return (NULL); 247ad135b5dSChristopher Siden 248ad135b5dSChristopher Siden config = zpool_get_config(zhp, NULL); 249ad135b5dSChristopher Siden } 250ad135b5dSChristopher Siden 251b289d045SDan Vatca if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, 252b289d045SDan Vatca &features) != 0) 253b289d045SDan Vatca return (NULL); 254ad135b5dSChristopher Siden 255ad135b5dSChristopher Siden return (features); 256ad135b5dSChristopher Siden } 257ad135b5dSChristopher Siden 258ad135b5dSChristopher Siden /* 259fa9e4066Sahrens * Refresh the vdev statistics associated with the given pool. This is used in 260fa9e4066Sahrens * iostat to show configuration changes and determine the delta from the last 261fa9e4066Sahrens * time the function was called. This function can fail, in case the pool has 262fa9e4066Sahrens * been destroyed. 263fa9e4066Sahrens */ 264fa9e4066Sahrens int 26594de1d4cSeschrock zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 266fa9e4066Sahrens { 267fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 268fa9e4066Sahrens int error; 269088e9d47Seschrock nvlist_t *config; 270e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 271fa9e4066Sahrens 27294de1d4cSeschrock *missing = B_FALSE; 273fa9e4066Sahrens (void) strcpy(zc.zc_name, zhp->zpool_name); 274fa9e4066Sahrens 275fa9e4066Sahrens if (zhp->zpool_config_size == 0) 276fa9e4066Sahrens zhp->zpool_config_size = 1 << 16; 277fa9e4066Sahrens 278e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0) 27999653d4eSeschrock return (-1); 280fa9e4066Sahrens 281ea8dc4b6Seschrock for (;;) { 28299653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, 28399653d4eSeschrock &zc) == 0) { 284fa9e4066Sahrens /* 285ea8dc4b6Seschrock * The real error is returned in the zc_cookie field. 286fa9e4066Sahrens */ 28794de1d4cSeschrock error = zc.zc_cookie; 288fa9e4066Sahrens break; 289fa9e4066Sahrens } 290fa9e4066Sahrens 291ea8dc4b6Seschrock if (errno == ENOMEM) { 292e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 293e9dbad6fSeschrock zcmd_free_nvlists(&zc); 29499653d4eSeschrock return (-1); 295e9dbad6fSeschrock } 296ea8dc4b6Seschrock } else { 297e9dbad6fSeschrock zcmd_free_nvlists(&zc); 29894de1d4cSeschrock if (errno == ENOENT || errno == EINVAL) 29994de1d4cSeschrock *missing = B_TRUE; 30094de1d4cSeschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 30194de1d4cSeschrock return (0); 302fa9e4066Sahrens } 303fa9e4066Sahrens } 304fa9e4066Sahrens 305e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 306e9dbad6fSeschrock zcmd_free_nvlists(&zc); 307e9dbad6fSeschrock return (-1); 30899653d4eSeschrock } 309fa9e4066Sahrens 310e9dbad6fSeschrock zcmd_free_nvlists(&zc); 311e9dbad6fSeschrock 312e9dbad6fSeschrock zhp->zpool_config_size = zc.zc_nvlist_dst_size; 313fa9e4066Sahrens 314088e9d47Seschrock if (zhp->zpool_config != NULL) { 315088e9d47Seschrock uint64_t oldtxg, newtxg; 316088e9d47Seschrock 317088e9d47Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, 318088e9d47Seschrock ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 319088e9d47Seschrock verify(nvlist_lookup_uint64(config, 320088e9d47Seschrock ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 321088e9d47Seschrock 322088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 323088e9d47Seschrock 324088e9d47Seschrock if (oldtxg != newtxg) { 325fa9e4066Sahrens nvlist_free(zhp->zpool_config); 326088e9d47Seschrock zhp->zpool_old_config = NULL; 327088e9d47Seschrock } else { 328088e9d47Seschrock zhp->zpool_old_config = zhp->zpool_config; 329088e9d47Seschrock } 330088e9d47Seschrock } 331fa9e4066Sahrens 332088e9d47Seschrock zhp->zpool_config = config; 33394de1d4cSeschrock if (error) 33494de1d4cSeschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 33594de1d4cSeschrock else 33694de1d4cSeschrock zhp->zpool_state = POOL_STATE_ACTIVE; 337fa9e4066Sahrens 33894de1d4cSeschrock return (0); 339fa9e4066Sahrens } 340fa9e4066Sahrens 341fa9e4066Sahrens /* 342*8808ac5dSYuri Pankov * The following environment variables are undocumented 343*8808ac5dSYuri Pankov * and should be used for testing purposes only: 34465fec9f6SChristopher Siden * 345*8808ac5dSYuri Pankov * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists 346*8808ac5dSYuri Pankov * __ZFS_POOL_RESTRICT - iterate only over the pools it lists 34765fec9f6SChristopher Siden * 34865fec9f6SChristopher Siden * This function returns B_TRUE if the pool should be skipped 34965fec9f6SChristopher Siden * during iteration. 35065fec9f6SChristopher Siden */ 351*8808ac5dSYuri Pankov boolean_t 352*8808ac5dSYuri Pankov zpool_skip_pool(const char *poolname) 35365fec9f6SChristopher Siden { 35465fec9f6SChristopher Siden static boolean_t initialized = B_FALSE; 355*8808ac5dSYuri Pankov static const char *exclude = NULL; 356*8808ac5dSYuri Pankov static const char *restricted = NULL; 35765fec9f6SChristopher Siden 35865fec9f6SChristopher Siden const char *cur, *end; 359*8808ac5dSYuri Pankov int len; 360*8808ac5dSYuri Pankov int namelen = strlen(poolname); 36165fec9f6SChristopher Siden 36265fec9f6SChristopher Siden if (!initialized) { 36365fec9f6SChristopher Siden initialized = B_TRUE; 364*8808ac5dSYuri Pankov exclude = getenv("__ZFS_POOL_EXCLUDE"); 36565fec9f6SChristopher Siden restricted = getenv("__ZFS_POOL_RESTRICT"); 36665fec9f6SChristopher Siden } 36765fec9f6SChristopher Siden 368*8808ac5dSYuri Pankov if (exclude != NULL) { 369*8808ac5dSYuri Pankov cur = exclude; 370*8808ac5dSYuri Pankov do { 371*8808ac5dSYuri Pankov end = strchr(cur, ' '); 372*8808ac5dSYuri Pankov len = (NULL == end) ? strlen(cur) : (end - cur); 373*8808ac5dSYuri Pankov if (len == namelen && 0 == strncmp(cur, poolname, len)) 374*8808ac5dSYuri Pankov return (B_TRUE); 375*8808ac5dSYuri Pankov cur += (len + 1); 376*8808ac5dSYuri Pankov } while (NULL != end); 377*8808ac5dSYuri Pankov } 378*8808ac5dSYuri Pankov 37965fec9f6SChristopher Siden if (NULL == restricted) 38065fec9f6SChristopher Siden return (B_FALSE); 38165fec9f6SChristopher Siden 38265fec9f6SChristopher Siden cur = restricted; 38365fec9f6SChristopher Siden do { 38465fec9f6SChristopher Siden end = strchr(cur, ' '); 38565fec9f6SChristopher Siden len = (NULL == end) ? strlen(cur) : (end - cur); 38665fec9f6SChristopher Siden 38765fec9f6SChristopher Siden if (len == namelen && 0 == strncmp(cur, poolname, len)) { 38865fec9f6SChristopher Siden return (B_FALSE); 38965fec9f6SChristopher Siden } 39065fec9f6SChristopher Siden 39165fec9f6SChristopher Siden cur += (len + 1); 39265fec9f6SChristopher Siden } while (NULL != end); 39365fec9f6SChristopher Siden 39465fec9f6SChristopher Siden return (B_TRUE); 39565fec9f6SChristopher Siden } 39665fec9f6SChristopher Siden 39765fec9f6SChristopher Siden /* 398fa9e4066Sahrens * Iterate over all pools in the system. 399fa9e4066Sahrens */ 400fa9e4066Sahrens int 40199653d4eSeschrock zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 402fa9e4066Sahrens { 403fa9e4066Sahrens config_node_t *cn; 404fa9e4066Sahrens zpool_handle_t *zhp; 405fa9e4066Sahrens int ret; 406fa9e4066Sahrens 407069f55e2SEric Schrock /* 408069f55e2SEric Schrock * If someone makes a recursive call to zpool_iter(), we want to avoid 409069f55e2SEric Schrock * refreshing the namespace because that will invalidate the parent 410069f55e2SEric Schrock * context. We allow recursive calls, but simply re-use the same 411069f55e2SEric Schrock * namespace AVL tree. 412069f55e2SEric Schrock */ 413069f55e2SEric Schrock if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0) 41499653d4eSeschrock return (-1); 415fa9e4066Sahrens 416069f55e2SEric Schrock hdl->libzfs_pool_iter++; 41799653d4eSeschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 41899653d4eSeschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 419fa9e4066Sahrens 420*8808ac5dSYuri Pankov if (zpool_skip_pool(cn->cn_name)) 42165fec9f6SChristopher Siden continue; 42265fec9f6SChristopher Siden 423069f55e2SEric Schrock if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) { 424069f55e2SEric Schrock hdl->libzfs_pool_iter--; 42594de1d4cSeschrock return (-1); 426069f55e2SEric Schrock } 42794de1d4cSeschrock 42894de1d4cSeschrock if (zhp == NULL) 429fa9e4066Sahrens continue; 430fa9e4066Sahrens 431069f55e2SEric Schrock if ((ret = func(zhp, data)) != 0) { 432069f55e2SEric Schrock hdl->libzfs_pool_iter--; 433fa9e4066Sahrens return (ret); 434fa9e4066Sahrens } 435069f55e2SEric Schrock } 436069f55e2SEric Schrock hdl->libzfs_pool_iter--; 437fa9e4066Sahrens 438fa9e4066Sahrens return (0); 439fa9e4066Sahrens } 440fa9e4066Sahrens 441fa9e4066Sahrens /* 442fa9e4066Sahrens * Iterate over root datasets, calling the given function for each. The zfs 443fa9e4066Sahrens * handle passed each time must be explicitly closed by the callback. 444fa9e4066Sahrens */ 445fa9e4066Sahrens int 44699653d4eSeschrock zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 447fa9e4066Sahrens { 448fa9e4066Sahrens config_node_t *cn; 449fa9e4066Sahrens zfs_handle_t *zhp; 450fa9e4066Sahrens int ret; 451fa9e4066Sahrens 45299653d4eSeschrock if (namespace_reload(hdl) != 0) 45399653d4eSeschrock return (-1); 454fa9e4066Sahrens 45599653d4eSeschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 45699653d4eSeschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 457fa9e4066Sahrens 458*8808ac5dSYuri Pankov if (zpool_skip_pool(cn->cn_name)) 45965fec9f6SChristopher Siden continue; 46065fec9f6SChristopher Siden 46199653d4eSeschrock if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 462fa9e4066Sahrens continue; 463fa9e4066Sahrens 464fa9e4066Sahrens if ((ret = func(zhp, data)) != 0) 465fa9e4066Sahrens return (ret); 466fa9e4066Sahrens } 467fa9e4066Sahrens 468fa9e4066Sahrens return (0); 469fa9e4066Sahrens } 470