1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221544Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens /* 29789Sahrens * The pool configuration repository is stored in /etc/zfs/zpool.cache as a 30789Sahrens * single packed nvlist. While it would be nice to just read in this 31789Sahrens * file from userland, this wouldn't work from a local zone. So we have to have 32789Sahrens * a zpool ioctl to return the complete configuration for all pools. In the 33789Sahrens * global zone, this will be identical to reading the file and unpacking it in 34789Sahrens * userland. 35789Sahrens */ 36789Sahrens 37789Sahrens #include <errno.h> 38789Sahrens #include <sys/stat.h> 39789Sahrens #include <fcntl.h> 40789Sahrens #include <stddef.h> 41789Sahrens #include <string.h> 42789Sahrens #include <unistd.h> 43789Sahrens #include <libintl.h> 44789Sahrens #include <libuutil.h> 45789Sahrens 46789Sahrens #include "libzfs_impl.h" 47789Sahrens 48789Sahrens typedef struct config_node { 49789Sahrens char *cn_name; 50789Sahrens nvlist_t *cn_config; 51789Sahrens uu_avl_node_t cn_avl; 52789Sahrens } config_node_t; 53789Sahrens 54789Sahrens /* ARGSUSED */ 55789Sahrens static int 56789Sahrens config_node_compare(const void *a, const void *b, void *unused) 57789Sahrens { 58789Sahrens int ret; 59789Sahrens 60789Sahrens const config_node_t *ca = (config_node_t *)a; 61789Sahrens const config_node_t *cb = (config_node_t *)b; 62789Sahrens 63789Sahrens ret = strcmp(ca->cn_name, cb->cn_name); 64789Sahrens 65789Sahrens if (ret < 0) 66789Sahrens return (-1); 67789Sahrens else if (ret > 0) 68789Sahrens return (1); 69789Sahrens else 70789Sahrens return (0); 71789Sahrens } 72789Sahrens 732082Seschrock void 742082Seschrock namespace_clear(libzfs_handle_t *hdl) 752082Seschrock { 762082Seschrock if (hdl->libzfs_ns_avl) { 772082Seschrock uu_avl_walk_t *walk; 782082Seschrock config_node_t *cn; 792082Seschrock 802082Seschrock if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl, 812082Seschrock UU_WALK_ROBUST)) == NULL) 822082Seschrock return; 832082Seschrock 842082Seschrock while ((cn = uu_avl_walk_next(walk)) != NULL) { 852082Seschrock uu_avl_remove(hdl->libzfs_ns_avl, cn); 862082Seschrock nvlist_free(cn->cn_config); 872082Seschrock free(cn->cn_name); 882082Seschrock free(cn); 892082Seschrock } 902082Seschrock 912082Seschrock uu_avl_walk_end(walk); 922082Seschrock 932082Seschrock uu_avl_destroy(hdl->libzfs_ns_avl); 942082Seschrock hdl->libzfs_ns_avl = NULL; 952082Seschrock } 962082Seschrock 972082Seschrock if (hdl->libzfs_ns_avlpool) { 982082Seschrock uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); 992082Seschrock hdl->libzfs_ns_avlpool = NULL; 1002082Seschrock } 1012082Seschrock } 1022082Seschrock 103789Sahrens /* 104789Sahrens * Loads the pool namespace, or re-loads it if the cache has changed. 105789Sahrens */ 1062082Seschrock static int 1072082Seschrock namespace_reload(libzfs_handle_t *hdl) 108789Sahrens { 109789Sahrens nvlist_t *config; 110789Sahrens config_node_t *cn; 111789Sahrens nvpair_t *elem; 112789Sahrens zfs_cmd_t zc = { 0 }; 113789Sahrens uu_avl_walk_t *walk; 114789Sahrens 1152082Seschrock if (hdl->libzfs_ns_gen == 0) { 116789Sahrens /* 117789Sahrens * This is the first time we've accessed the configuration 118789Sahrens * cache. Initialize the AVL tree and then fall through to the 119789Sahrens * common code. 120789Sahrens */ 1212082Seschrock if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", 122789Sahrens sizeof (config_node_t), 123789Sahrens offsetof(config_node_t, cn_avl), 124789Sahrens config_node_compare, UU_DEFAULT)) == NULL) 1252082Seschrock return (no_memory(hdl)); 126789Sahrens 1272082Seschrock if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, 1282082Seschrock NULL, UU_DEFAULT)) == NULL) 1292082Seschrock return (no_memory(hdl)); 130789Sahrens } 131789Sahrens 132789Sahrens /* 133789Sahrens * Issue the ZFS_IOC_POOL_CONFIGS ioctl. 134789Sahrens * This can fail for one of two reasons: 135789Sahrens * 136789Sahrens * EEXIST The generation counts match, nothing to do. 137789Sahrens * ENOMEM The zc_config_dst buffer isn't large enough to 138789Sahrens * hold the config; zc_config_dst_size will have 139789Sahrens * been modified to tell us how much to allocate. 140789Sahrens */ 141789Sahrens zc.zc_config_dst_size = 1024; 1422082Seschrock if ((zc.zc_config_dst = (uint64_t)(uintptr_t) 1432082Seschrock zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL) 1442082Seschrock return (-1); 145789Sahrens for (;;) { 1462082Seschrock zc.zc_cookie = hdl->libzfs_ns_gen; 1472082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 148789Sahrens switch (errno) { 149789Sahrens case EEXIST: 150789Sahrens /* 151789Sahrens * The namespace hasn't changed. 152789Sahrens */ 153789Sahrens free((void *)(uintptr_t)zc.zc_config_dst); 1542082Seschrock return (0); 155789Sahrens 156789Sahrens case ENOMEM: 157789Sahrens free((void *)(uintptr_t)zc.zc_config_dst); 1582082Seschrock if ((zc.zc_config_dst = (uint64_t)(uintptr_t) 1592082Seschrock zfs_alloc(hdl, zc.zc_config_dst_size)) 1602082Seschrock == NULL) 1612082Seschrock return (-1); 162789Sahrens break; 163789Sahrens 164789Sahrens default: 1652082Seschrock return (zfs_standard_error(hdl, errno, 1662082Seschrock dgettext(TEXT_DOMAIN, "failed to read " 1672082Seschrock "pool configuration"))); 168789Sahrens } 169789Sahrens } else { 1702082Seschrock hdl->libzfs_ns_gen = zc.zc_cookie; 171789Sahrens break; 172789Sahrens } 173789Sahrens } 174789Sahrens 1752082Seschrock if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, 176*2142Seschrock zc.zc_config_dst_size, &config, 0) != 0) { 177*2142Seschrock free((void *)(uintptr_t)zc.zc_config_dst); 1782082Seschrock return (no_memory(hdl)); 179*2142Seschrock } 180789Sahrens 181789Sahrens free((void *)(uintptr_t)zc.zc_config_dst); 182789Sahrens 183789Sahrens /* 184789Sahrens * Clear out any existing configuration information. 185789Sahrens */ 1862082Seschrock if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl, 1872082Seschrock UU_WALK_ROBUST)) == NULL) { 1882082Seschrock nvlist_free(config); 1892082Seschrock return (no_memory(hdl)); 1902082Seschrock } 191789Sahrens 192789Sahrens while ((cn = uu_avl_walk_next(walk)) != NULL) { 1932082Seschrock uu_avl_remove(hdl->libzfs_ns_avl, cn); 194789Sahrens nvlist_free(cn->cn_config); 195789Sahrens free(cn->cn_name); 196789Sahrens free(cn); 197789Sahrens } 198789Sahrens 1992082Seschrock uu_avl_walk_end(walk); 2002082Seschrock 201789Sahrens elem = NULL; 202789Sahrens while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 203789Sahrens nvlist_t *child; 204789Sahrens uu_avl_index_t where; 205789Sahrens 2062082Seschrock if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 2072082Seschrock nvlist_free(config); 2082082Seschrock return (-1); 2092082Seschrock } 2102082Seschrock 2112082Seschrock if ((cn->cn_name = zfs_strdup(hdl, 2122082Seschrock nvpair_name(elem))) == NULL) { 2132082Seschrock free(cn); 2142082Seschrock return (-1); 2152082Seschrock } 216789Sahrens 217789Sahrens verify(nvpair_value_nvlist(elem, &child) == 0); 2182082Seschrock if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 2192082Seschrock nvlist_free(config); 2202082Seschrock return (no_memory(hdl)); 2212082Seschrock } 2222082Seschrock verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 2232082Seschrock == NULL); 224789Sahrens 2252082Seschrock uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 226789Sahrens } 227789Sahrens 228789Sahrens nvlist_free(config); 2292082Seschrock return (0); 230789Sahrens } 231789Sahrens 232789Sahrens /* 233789Sahrens * Retrive the configuration for the given pool. The configuration is a nvlist 234789Sahrens * describing the vdevs, as well as the statistics associated with each one. 235789Sahrens */ 236789Sahrens nvlist_t * 237952Seschrock zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 238789Sahrens { 239952Seschrock if (oldconfig) 240952Seschrock *oldconfig = zhp->zpool_old_config; 241789Sahrens return (zhp->zpool_config); 242789Sahrens } 243789Sahrens 244789Sahrens /* 245789Sahrens * Refresh the vdev statistics associated with the given pool. This is used in 246789Sahrens * iostat to show configuration changes and determine the delta from the last 247789Sahrens * time the function was called. This function can fail, in case the pool has 248789Sahrens * been destroyed. 249789Sahrens */ 250789Sahrens int 251*2142Seschrock zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 252789Sahrens { 253789Sahrens zfs_cmd_t zc = { 0 }; 254789Sahrens int error; 255952Seschrock nvlist_t *config; 256789Sahrens 257*2142Seschrock *missing = B_FALSE; 258789Sahrens (void) strcpy(zc.zc_name, zhp->zpool_name); 259789Sahrens 260789Sahrens if (zhp->zpool_config_size == 0) 261789Sahrens zhp->zpool_config_size = 1 << 16; 262789Sahrens 263789Sahrens zc.zc_config_dst_size = zhp->zpool_config_size; 2642082Seschrock if ((zc.zc_config_dst = (uint64_t)(uintptr_t) 2652082Seschrock zfs_alloc(zhp->zpool_hdl, zc.zc_config_dst_size)) == NULL) 2662082Seschrock return (-1); 267789Sahrens 2681544Seschrock for (;;) { 2692082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, 2702082Seschrock &zc) == 0) { 271789Sahrens /* 2721544Seschrock * The real error is returned in the zc_cookie field. 273789Sahrens */ 274*2142Seschrock error = zc.zc_cookie; 275789Sahrens break; 276789Sahrens } 277789Sahrens 2781544Seschrock if (errno == ENOMEM) { 2791544Seschrock free((void *)(uintptr_t)zc.zc_config_dst); 2802082Seschrock if ((zc.zc_config_dst = (uint64_t)(uintptr_t) 2812082Seschrock zfs_alloc(zhp->zpool_hdl, 2822082Seschrock zc.zc_config_dst_size)) == NULL) 2832082Seschrock return (-1); 2841544Seschrock } else { 2851544Seschrock free((void *)(uintptr_t)zc.zc_config_dst); 286*2142Seschrock if (errno == ENOENT || errno == EINVAL) 287*2142Seschrock *missing = B_TRUE; 288*2142Seschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 289*2142Seschrock return (0); 290789Sahrens } 291789Sahrens } 292789Sahrens 2932082Seschrock if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, 2942082Seschrock zc.zc_config_dst_size, &config, 0) != 0) { 2952082Seschrock free((void *)(uintptr_t)zc.zc_config_dst); 2962082Seschrock return (no_memory(zhp->zpool_hdl)); 2972082Seschrock } 298789Sahrens 299789Sahrens zhp->zpool_config_size = zc.zc_config_dst_size; 300789Sahrens free((void *)(uintptr_t)zc.zc_config_dst); 301789Sahrens 302*2142Seschrock if (set_pool_health(config) != 0) { 303*2142Seschrock nvlist_free(config); 3042082Seschrock return (no_memory(zhp->zpool_hdl)); 305*2142Seschrock } 306952Seschrock 307952Seschrock if (zhp->zpool_config != NULL) { 308952Seschrock uint64_t oldtxg, newtxg; 309952Seschrock 310952Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, 311952Seschrock ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 312952Seschrock verify(nvlist_lookup_uint64(config, 313952Seschrock ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 314789Sahrens 315952Seschrock if (zhp->zpool_old_config != NULL) 316952Seschrock nvlist_free(zhp->zpool_old_config); 317789Sahrens 318952Seschrock if (oldtxg != newtxg) { 319952Seschrock nvlist_free(zhp->zpool_config); 320952Seschrock zhp->zpool_old_config = NULL; 321952Seschrock } else { 322952Seschrock zhp->zpool_old_config = zhp->zpool_config; 323952Seschrock } 324952Seschrock } 325952Seschrock 326952Seschrock zhp->zpool_config = config; 327*2142Seschrock if (error) 328*2142Seschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 329*2142Seschrock else 330*2142Seschrock zhp->zpool_state = POOL_STATE_ACTIVE; 331789Sahrens 332*2142Seschrock return (0); 333789Sahrens } 334789Sahrens 335789Sahrens /* 336789Sahrens * Iterate over all pools in the system. 337789Sahrens */ 338789Sahrens int 3392082Seschrock zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 340789Sahrens { 341789Sahrens config_node_t *cn; 342789Sahrens zpool_handle_t *zhp; 343789Sahrens int ret; 344789Sahrens 3452082Seschrock if (namespace_reload(hdl) != 0) 3462082Seschrock return (-1); 347789Sahrens 3482082Seschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 3492082Seschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 350789Sahrens 351*2142Seschrock if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) 352*2142Seschrock return (-1); 353*2142Seschrock 354*2142Seschrock if (zhp == NULL) 355789Sahrens continue; 356789Sahrens 357789Sahrens if ((ret = func(zhp, data)) != 0) 358789Sahrens return (ret); 359789Sahrens } 360789Sahrens 361789Sahrens return (0); 362789Sahrens } 363789Sahrens 364789Sahrens /* 365789Sahrens * Iterate over root datasets, calling the given function for each. The zfs 366789Sahrens * handle passed each time must be explicitly closed by the callback. 367789Sahrens */ 368789Sahrens int 3692082Seschrock zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 370789Sahrens { 371789Sahrens config_node_t *cn; 372789Sahrens zfs_handle_t *zhp; 373789Sahrens int ret; 374789Sahrens 3752082Seschrock if (namespace_reload(hdl) != 0) 3762082Seschrock return (-1); 377789Sahrens 3782082Seschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 3792082Seschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 380789Sahrens 3812082Seschrock if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 382789Sahrens continue; 383789Sahrens 384789Sahrens if ((ret = func(zhp, data)) != 0) 385789Sahrens return (ret); 386789Sahrens } 387789Sahrens 388789Sahrens return (0); 389789Sahrens } 390