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. 29ad135b5dSChristopher Siden */ 30ad135b5dSChristopher Siden 31ad135b5dSChristopher Siden /* 32fa9e4066Sahrens * The pool configuration repository is stored in /etc/zfs/zpool.cache as a 33fa9e4066Sahrens * single packed nvlist. While it would be nice to just read in this 34fa9e4066Sahrens * file from userland, this wouldn't work from a local zone. So we have to have 35fa9e4066Sahrens * a zpool ioctl to return the complete configuration for all pools. In the 36fa9e4066Sahrens * global zone, this will be identical to reading the file and unpacking it in 37fa9e4066Sahrens * userland. 38fa9e4066Sahrens */ 39fa9e4066Sahrens 40fa9e4066Sahrens #include <errno.h> 41fa9e4066Sahrens #include <sys/stat.h> 42fa9e4066Sahrens #include <fcntl.h> 43fa9e4066Sahrens #include <stddef.h> 44fa9e4066Sahrens #include <string.h> 45fa9e4066Sahrens #include <unistd.h> 46fa9e4066Sahrens #include <libintl.h> 47fa9e4066Sahrens #include <libuutil.h> 48fa9e4066Sahrens 49fa9e4066Sahrens #include "libzfs_impl.h" 50fa9e4066Sahrens 51fa9e4066Sahrens typedef struct config_node { 52fa9e4066Sahrens char *cn_name; 53fa9e4066Sahrens nvlist_t *cn_config; 54fa9e4066Sahrens uu_avl_node_t cn_avl; 55fa9e4066Sahrens } config_node_t; 56fa9e4066Sahrens 57fa9e4066Sahrens /* ARGSUSED */ 58fa9e4066Sahrens static int 59fa9e4066Sahrens config_node_compare(const void *a, const void *b, void *unused) 60fa9e4066Sahrens { 61fa9e4066Sahrens int ret; 62fa9e4066Sahrens 63fa9e4066Sahrens const config_node_t *ca = (config_node_t *)a; 64fa9e4066Sahrens const config_node_t *cb = (config_node_t *)b; 65fa9e4066Sahrens 66fa9e4066Sahrens ret = strcmp(ca->cn_name, cb->cn_name); 67fa9e4066Sahrens 68fa9e4066Sahrens if (ret < 0) 69fa9e4066Sahrens return (-1); 70fa9e4066Sahrens else if (ret > 0) 71fa9e4066Sahrens return (1); 72fa9e4066Sahrens else 73fa9e4066Sahrens return (0); 74fa9e4066Sahrens } 75fa9e4066Sahrens 7699653d4eSeschrock void 7799653d4eSeschrock namespace_clear(libzfs_handle_t *hdl) 7899653d4eSeschrock { 7999653d4eSeschrock if (hdl->libzfs_ns_avl) { 8099653d4eSeschrock config_node_t *cn; 8168f944b7Seschrock void *cookie = NULL; 8299653d4eSeschrock 8368f944b7Seschrock while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, 8468f944b7Seschrock &cookie)) != NULL) { 8599653d4eSeschrock nvlist_free(cn->cn_config); 8699653d4eSeschrock free(cn->cn_name); 8799653d4eSeschrock free(cn); 8899653d4eSeschrock } 8999653d4eSeschrock 9099653d4eSeschrock uu_avl_destroy(hdl->libzfs_ns_avl); 9199653d4eSeschrock hdl->libzfs_ns_avl = NULL; 9299653d4eSeschrock } 9399653d4eSeschrock 9499653d4eSeschrock if (hdl->libzfs_ns_avlpool) { 9599653d4eSeschrock uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); 9699653d4eSeschrock hdl->libzfs_ns_avlpool = NULL; 9799653d4eSeschrock } 9899653d4eSeschrock } 9999653d4eSeschrock 100fa9e4066Sahrens /* 101fa9e4066Sahrens * Loads the pool namespace, or re-loads it if the cache has changed. 102fa9e4066Sahrens */ 10399653d4eSeschrock static int 10499653d4eSeschrock namespace_reload(libzfs_handle_t *hdl) 105fa9e4066Sahrens { 106fa9e4066Sahrens nvlist_t *config; 107fa9e4066Sahrens config_node_t *cn; 108fa9e4066Sahrens nvpair_t *elem; 109fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 11068f944b7Seschrock void *cookie; 111fa9e4066Sahrens 11299653d4eSeschrock if (hdl->libzfs_ns_gen == 0) { 113fa9e4066Sahrens /* 114fa9e4066Sahrens * This is the first time we've accessed the configuration 115fa9e4066Sahrens * cache. Initialize the AVL tree and then fall through to the 116fa9e4066Sahrens * common code. 117fa9e4066Sahrens */ 11899653d4eSeschrock if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", 119fa9e4066Sahrens sizeof (config_node_t), 120fa9e4066Sahrens offsetof(config_node_t, cn_avl), 121fa9e4066Sahrens config_node_compare, UU_DEFAULT)) == NULL) 12299653d4eSeschrock return (no_memory(hdl)); 123fa9e4066Sahrens 12499653d4eSeschrock if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, 12599653d4eSeschrock NULL, UU_DEFAULT)) == NULL) 12699653d4eSeschrock return (no_memory(hdl)); 127fa9e4066Sahrens } 128fa9e4066Sahrens 129e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 13099653d4eSeschrock return (-1); 131e9dbad6fSeschrock 132fa9e4066Sahrens for (;;) { 13399653d4eSeschrock zc.zc_cookie = hdl->libzfs_ns_gen; 13499653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 135fa9e4066Sahrens switch (errno) { 136fa9e4066Sahrens case EEXIST: 137fa9e4066Sahrens /* 138fa9e4066Sahrens * The namespace hasn't changed. 139fa9e4066Sahrens */ 140e9dbad6fSeschrock zcmd_free_nvlists(&zc); 14199653d4eSeschrock return (0); 142fa9e4066Sahrens 143fa9e4066Sahrens case ENOMEM: 144e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 145e9dbad6fSeschrock zcmd_free_nvlists(&zc); 14699653d4eSeschrock return (-1); 147e9dbad6fSeschrock } 148fa9e4066Sahrens break; 149fa9e4066Sahrens 150fa9e4066Sahrens default: 151e9dbad6fSeschrock zcmd_free_nvlists(&zc); 15299653d4eSeschrock return (zfs_standard_error(hdl, errno, 15399653d4eSeschrock dgettext(TEXT_DOMAIN, "failed to read " 15499653d4eSeschrock "pool configuration"))); 155fa9e4066Sahrens } 156fa9e4066Sahrens } else { 15799653d4eSeschrock hdl->libzfs_ns_gen = zc.zc_cookie; 158fa9e4066Sahrens break; 159fa9e4066Sahrens } 160fa9e4066Sahrens } 161fa9e4066Sahrens 162e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 163e9dbad6fSeschrock zcmd_free_nvlists(&zc); 164e9dbad6fSeschrock return (-1); 16594de1d4cSeschrock } 166fa9e4066Sahrens 167e9dbad6fSeschrock zcmd_free_nvlists(&zc); 168fa9e4066Sahrens 169fa9e4066Sahrens /* 170fa9e4066Sahrens * Clear out any existing configuration information. 171fa9e4066Sahrens */ 17268f944b7Seschrock cookie = NULL; 17368f944b7Seschrock while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) { 174fa9e4066Sahrens nvlist_free(cn->cn_config); 175fa9e4066Sahrens free(cn->cn_name); 176fa9e4066Sahrens free(cn); 177fa9e4066Sahrens } 178fa9e4066Sahrens 179fa9e4066Sahrens elem = NULL; 180fa9e4066Sahrens while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 181fa9e4066Sahrens nvlist_t *child; 182fa9e4066Sahrens uu_avl_index_t where; 183fa9e4066Sahrens 18499653d4eSeschrock if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 18599653d4eSeschrock nvlist_free(config); 18699653d4eSeschrock return (-1); 18799653d4eSeschrock } 18899653d4eSeschrock 18999653d4eSeschrock if ((cn->cn_name = zfs_strdup(hdl, 19099653d4eSeschrock nvpair_name(elem))) == NULL) { 19199653d4eSeschrock free(cn); 1923bb79becSeschrock nvlist_free(config); 19399653d4eSeschrock return (-1); 19499653d4eSeschrock } 195fa9e4066Sahrens 196fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &child) == 0); 19799653d4eSeschrock if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 1983bb79becSeschrock free(cn->cn_name); 1993bb79becSeschrock free(cn); 20099653d4eSeschrock nvlist_free(config); 20199653d4eSeschrock return (no_memory(hdl)); 20299653d4eSeschrock } 20399653d4eSeschrock verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 20499653d4eSeschrock == NULL); 205fa9e4066Sahrens 20699653d4eSeschrock uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 207fa9e4066Sahrens } 208fa9e4066Sahrens 209fa9e4066Sahrens nvlist_free(config); 21099653d4eSeschrock return (0); 211fa9e4066Sahrens } 212fa9e4066Sahrens 213fa9e4066Sahrens /* 21468f944b7Seschrock * Retrieve the configuration for the given pool. The configuration is a nvlist 215fa9e4066Sahrens * describing the vdevs, as well as the statistics associated with each one. 216fa9e4066Sahrens */ 217fa9e4066Sahrens nvlist_t * 218088e9d47Seschrock zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 219fa9e4066Sahrens { 220088e9d47Seschrock if (oldconfig) 221088e9d47Seschrock *oldconfig = zhp->zpool_old_config; 222fa9e4066Sahrens return (zhp->zpool_config); 223fa9e4066Sahrens } 224fa9e4066Sahrens 225fa9e4066Sahrens /* 226ad135b5dSChristopher Siden * Retrieves a list of enabled features and their refcounts and caches it in 227ad135b5dSChristopher Siden * the pool handle. 228ad135b5dSChristopher Siden */ 229ad135b5dSChristopher Siden nvlist_t * 230ad135b5dSChristopher Siden zpool_get_features(zpool_handle_t *zhp) 231ad135b5dSChristopher Siden { 232ad135b5dSChristopher Siden nvlist_t *config, *features; 233ad135b5dSChristopher Siden 234ad135b5dSChristopher Siden config = zpool_get_config(zhp, NULL); 235ad135b5dSChristopher Siden 236ad135b5dSChristopher Siden if (config == NULL || !nvlist_exists(config, 237ad135b5dSChristopher Siden ZPOOL_CONFIG_FEATURE_STATS)) { 238ad135b5dSChristopher Siden int error; 239ad135b5dSChristopher Siden boolean_t missing = B_FALSE; 240ad135b5dSChristopher Siden 241ad135b5dSChristopher Siden error = zpool_refresh_stats(zhp, &missing); 242ad135b5dSChristopher Siden 243ad135b5dSChristopher Siden if (error != 0 || missing) 244ad135b5dSChristopher Siden return (NULL); 245ad135b5dSChristopher Siden 246ad135b5dSChristopher Siden config = zpool_get_config(zhp, NULL); 247ad135b5dSChristopher Siden } 248ad135b5dSChristopher Siden 249ad135b5dSChristopher Siden verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, 250ad135b5dSChristopher Siden &features) == 0); 251ad135b5dSChristopher Siden 252ad135b5dSChristopher Siden return (features); 253ad135b5dSChristopher Siden } 254ad135b5dSChristopher Siden 255ad135b5dSChristopher Siden /* 256fa9e4066Sahrens * Refresh the vdev statistics associated with the given pool. This is used in 257fa9e4066Sahrens * iostat to show configuration changes and determine the delta from the last 258fa9e4066Sahrens * time the function was called. This function can fail, in case the pool has 259fa9e4066Sahrens * been destroyed. 260fa9e4066Sahrens */ 261fa9e4066Sahrens int 26294de1d4cSeschrock zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 263fa9e4066Sahrens { 264fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 265fa9e4066Sahrens int error; 266088e9d47Seschrock nvlist_t *config; 267e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 268fa9e4066Sahrens 26994de1d4cSeschrock *missing = B_FALSE; 270fa9e4066Sahrens (void) strcpy(zc.zc_name, zhp->zpool_name); 271fa9e4066Sahrens 272fa9e4066Sahrens if (zhp->zpool_config_size == 0) 273fa9e4066Sahrens zhp->zpool_config_size = 1 << 16; 274fa9e4066Sahrens 275e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0) 27699653d4eSeschrock return (-1); 277fa9e4066Sahrens 278ea8dc4b6Seschrock for (;;) { 27999653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, 28099653d4eSeschrock &zc) == 0) { 281fa9e4066Sahrens /* 282ea8dc4b6Seschrock * The real error is returned in the zc_cookie field. 283fa9e4066Sahrens */ 28494de1d4cSeschrock error = zc.zc_cookie; 285fa9e4066Sahrens break; 286fa9e4066Sahrens } 287fa9e4066Sahrens 288ea8dc4b6Seschrock if (errno == ENOMEM) { 289e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 290e9dbad6fSeschrock zcmd_free_nvlists(&zc); 29199653d4eSeschrock return (-1); 292e9dbad6fSeschrock } 293ea8dc4b6Seschrock } else { 294e9dbad6fSeschrock zcmd_free_nvlists(&zc); 29594de1d4cSeschrock if (errno == ENOENT || errno == EINVAL) 29694de1d4cSeschrock *missing = B_TRUE; 29794de1d4cSeschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 29894de1d4cSeschrock return (0); 299fa9e4066Sahrens } 300fa9e4066Sahrens } 301fa9e4066Sahrens 302e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 303e9dbad6fSeschrock zcmd_free_nvlists(&zc); 304e9dbad6fSeschrock return (-1); 30599653d4eSeschrock } 306fa9e4066Sahrens 307e9dbad6fSeschrock zcmd_free_nvlists(&zc); 308e9dbad6fSeschrock 309e9dbad6fSeschrock zhp->zpool_config_size = zc.zc_nvlist_dst_size; 310fa9e4066Sahrens 311088e9d47Seschrock if (zhp->zpool_config != NULL) { 312088e9d47Seschrock uint64_t oldtxg, newtxg; 313088e9d47Seschrock 314088e9d47Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, 315088e9d47Seschrock ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 316088e9d47Seschrock verify(nvlist_lookup_uint64(config, 317088e9d47Seschrock ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 318088e9d47Seschrock 319088e9d47Seschrock if (zhp->zpool_old_config != NULL) 320088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 321088e9d47Seschrock 322088e9d47Seschrock if (oldtxg != newtxg) { 323fa9e4066Sahrens nvlist_free(zhp->zpool_config); 324088e9d47Seschrock zhp->zpool_old_config = NULL; 325088e9d47Seschrock } else { 326088e9d47Seschrock zhp->zpool_old_config = zhp->zpool_config; 327088e9d47Seschrock } 328088e9d47Seschrock } 329fa9e4066Sahrens 330088e9d47Seschrock zhp->zpool_config = config; 33194de1d4cSeschrock if (error) 33294de1d4cSeschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 33394de1d4cSeschrock else 33494de1d4cSeschrock zhp->zpool_state = POOL_STATE_ACTIVE; 335fa9e4066Sahrens 33694de1d4cSeschrock return (0); 337fa9e4066Sahrens } 338fa9e4066Sahrens 339fa9e4066Sahrens /* 340*65fec9f6SChristopher Siden * If the __ZFS_POOL_RESTRICT environment variable is set we only iterate over 341*65fec9f6SChristopher Siden * pools it lists. 342*65fec9f6SChristopher Siden * 343*65fec9f6SChristopher Siden * This is an undocumented feature for use during testing only. 344*65fec9f6SChristopher Siden * 345*65fec9f6SChristopher Siden * This function returns B_TRUE if the pool should be skipped 346*65fec9f6SChristopher Siden * during iteration. 347*65fec9f6SChristopher Siden */ 348*65fec9f6SChristopher Siden static boolean_t 349*65fec9f6SChristopher Siden check_restricted(const char *poolname) 350*65fec9f6SChristopher Siden { 351*65fec9f6SChristopher Siden static boolean_t initialized = B_FALSE; 352*65fec9f6SChristopher Siden static char *restricted = NULL; 353*65fec9f6SChristopher Siden 354*65fec9f6SChristopher Siden const char *cur, *end; 355*65fec9f6SChristopher Siden int len, namelen; 356*65fec9f6SChristopher Siden 357*65fec9f6SChristopher Siden if (!initialized) { 358*65fec9f6SChristopher Siden initialized = B_TRUE; 359*65fec9f6SChristopher Siden restricted = getenv("__ZFS_POOL_RESTRICT"); 360*65fec9f6SChristopher Siden } 361*65fec9f6SChristopher Siden 362*65fec9f6SChristopher Siden if (NULL == restricted) 363*65fec9f6SChristopher Siden return (B_FALSE); 364*65fec9f6SChristopher Siden 365*65fec9f6SChristopher Siden cur = restricted; 366*65fec9f6SChristopher Siden namelen = strlen(poolname); 367*65fec9f6SChristopher Siden do { 368*65fec9f6SChristopher Siden end = strchr(cur, ' '); 369*65fec9f6SChristopher Siden len = (NULL == end) ? strlen(cur) : (end - cur); 370*65fec9f6SChristopher Siden 371*65fec9f6SChristopher Siden if (len == namelen && 0 == strncmp(cur, poolname, len)) { 372*65fec9f6SChristopher Siden return (B_FALSE); 373*65fec9f6SChristopher Siden } 374*65fec9f6SChristopher Siden 375*65fec9f6SChristopher Siden cur += (len + 1); 376*65fec9f6SChristopher Siden } while (NULL != end); 377*65fec9f6SChristopher Siden 378*65fec9f6SChristopher Siden return (B_TRUE); 379*65fec9f6SChristopher Siden } 380*65fec9f6SChristopher Siden 381*65fec9f6SChristopher Siden /* 382fa9e4066Sahrens * Iterate over all pools in the system. 383fa9e4066Sahrens */ 384fa9e4066Sahrens int 38599653d4eSeschrock zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 386fa9e4066Sahrens { 387fa9e4066Sahrens config_node_t *cn; 388fa9e4066Sahrens zpool_handle_t *zhp; 389fa9e4066Sahrens int ret; 390fa9e4066Sahrens 391069f55e2SEric Schrock /* 392069f55e2SEric Schrock * If someone makes a recursive call to zpool_iter(), we want to avoid 393069f55e2SEric Schrock * refreshing the namespace because that will invalidate the parent 394069f55e2SEric Schrock * context. We allow recursive calls, but simply re-use the same 395069f55e2SEric Schrock * namespace AVL tree. 396069f55e2SEric Schrock */ 397069f55e2SEric Schrock if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0) 39899653d4eSeschrock return (-1); 399fa9e4066Sahrens 400069f55e2SEric Schrock hdl->libzfs_pool_iter++; 40199653d4eSeschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 40299653d4eSeschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 403fa9e4066Sahrens 404*65fec9f6SChristopher Siden if (check_restricted(cn->cn_name)) 405*65fec9f6SChristopher Siden continue; 406*65fec9f6SChristopher Siden 407069f55e2SEric Schrock if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) { 408069f55e2SEric Schrock hdl->libzfs_pool_iter--; 40994de1d4cSeschrock return (-1); 410069f55e2SEric Schrock } 41194de1d4cSeschrock 41294de1d4cSeschrock if (zhp == NULL) 413fa9e4066Sahrens continue; 414fa9e4066Sahrens 415069f55e2SEric Schrock if ((ret = func(zhp, data)) != 0) { 416069f55e2SEric Schrock hdl->libzfs_pool_iter--; 417fa9e4066Sahrens return (ret); 418fa9e4066Sahrens } 419069f55e2SEric Schrock } 420069f55e2SEric Schrock hdl->libzfs_pool_iter--; 421fa9e4066Sahrens 422fa9e4066Sahrens return (0); 423fa9e4066Sahrens } 424fa9e4066Sahrens 425fa9e4066Sahrens /* 426fa9e4066Sahrens * Iterate over root datasets, calling the given function for each. The zfs 427fa9e4066Sahrens * handle passed each time must be explicitly closed by the callback. 428fa9e4066Sahrens */ 429fa9e4066Sahrens int 43099653d4eSeschrock zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 431fa9e4066Sahrens { 432fa9e4066Sahrens config_node_t *cn; 433fa9e4066Sahrens zfs_handle_t *zhp; 434fa9e4066Sahrens int ret; 435fa9e4066Sahrens 43699653d4eSeschrock if (namespace_reload(hdl) != 0) 43799653d4eSeschrock return (-1); 438fa9e4066Sahrens 43999653d4eSeschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 44099653d4eSeschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 441fa9e4066Sahrens 442*65fec9f6SChristopher Siden if (check_restricted(cn->cn_name)) 443*65fec9f6SChristopher Siden continue; 444*65fec9f6SChristopher Siden 44599653d4eSeschrock if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 446fa9e4066Sahrens continue; 447fa9e4066Sahrens 448fa9e4066Sahrens if ((ret = func(zhp, data)) != 0) 449fa9e4066Sahrens return (ret); 450fa9e4066Sahrens } 451fa9e4066Sahrens 452fa9e4066Sahrens return (0); 453fa9e4066Sahrens } 454