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 /* 22*3741Smmusante * Copyright 2007 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 1322676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 1332082Seschrock return (-1); 1342676Seschrock 135789Sahrens for (;;) { 1362082Seschrock zc.zc_cookie = hdl->libzfs_ns_gen; 1372082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 138789Sahrens switch (errno) { 139789Sahrens case EEXIST: 140789Sahrens /* 141789Sahrens * The namespace hasn't changed. 142789Sahrens */ 1432676Seschrock zcmd_free_nvlists(&zc); 1442082Seschrock return (0); 145789Sahrens 146789Sahrens case ENOMEM: 1472676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 1482676Seschrock zcmd_free_nvlists(&zc); 1492082Seschrock return (-1); 1502676Seschrock } 151789Sahrens break; 152789Sahrens 153789Sahrens default: 1542676Seschrock zcmd_free_nvlists(&zc); 1552082Seschrock return (zfs_standard_error(hdl, errno, 1562082Seschrock dgettext(TEXT_DOMAIN, "failed to read " 1572082Seschrock "pool configuration"))); 158789Sahrens } 159789Sahrens } else { 1602082Seschrock hdl->libzfs_ns_gen = zc.zc_cookie; 161789Sahrens break; 162789Sahrens } 163789Sahrens } 164789Sahrens 1652676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 1662676Seschrock zcmd_free_nvlists(&zc); 1672676Seschrock return (-1); 1682142Seschrock } 169789Sahrens 1702676Seschrock zcmd_free_nvlists(&zc); 171789Sahrens 172789Sahrens /* 173789Sahrens * Clear out any existing configuration information. 174789Sahrens */ 1752082Seschrock if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl, 1762082Seschrock UU_WALK_ROBUST)) == NULL) { 1772082Seschrock nvlist_free(config); 1782082Seschrock return (no_memory(hdl)); 1792082Seschrock } 180789Sahrens 181789Sahrens while ((cn = uu_avl_walk_next(walk)) != NULL) { 1822082Seschrock uu_avl_remove(hdl->libzfs_ns_avl, cn); 183789Sahrens nvlist_free(cn->cn_config); 184789Sahrens free(cn->cn_name); 185789Sahrens free(cn); 186789Sahrens } 187789Sahrens 1882082Seschrock uu_avl_walk_end(walk); 1892082Seschrock 190789Sahrens elem = NULL; 191789Sahrens while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 192789Sahrens nvlist_t *child; 193789Sahrens uu_avl_index_t where; 194789Sahrens 1952082Seschrock if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 1962082Seschrock nvlist_free(config); 1972082Seschrock return (-1); 1982082Seschrock } 1992082Seschrock 2002082Seschrock if ((cn->cn_name = zfs_strdup(hdl, 2012082Seschrock nvpair_name(elem))) == NULL) { 2022082Seschrock free(cn); 2032474Seschrock nvlist_free(config); 2042082Seschrock return (-1); 2052082Seschrock } 206789Sahrens 207789Sahrens verify(nvpair_value_nvlist(elem, &child) == 0); 2082082Seschrock if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 2092474Seschrock free(cn->cn_name); 2102474Seschrock free(cn); 2112082Seschrock nvlist_free(config); 2122082Seschrock return (no_memory(hdl)); 2132082Seschrock } 2142082Seschrock verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 2152082Seschrock == NULL); 216789Sahrens 2172082Seschrock uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 218789Sahrens } 219789Sahrens 220789Sahrens nvlist_free(config); 2212082Seschrock return (0); 222789Sahrens } 223789Sahrens 224789Sahrens /* 225789Sahrens * Retrive the configuration for the given pool. The configuration is a nvlist 226789Sahrens * describing the vdevs, as well as the statistics associated with each one. 227789Sahrens */ 228789Sahrens nvlist_t * 229952Seschrock zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 230789Sahrens { 231952Seschrock if (oldconfig) 232952Seschrock *oldconfig = zhp->zpool_old_config; 233789Sahrens return (zhp->zpool_config); 234789Sahrens } 235789Sahrens 236789Sahrens /* 237789Sahrens * Refresh the vdev statistics associated with the given pool. This is used in 238789Sahrens * iostat to show configuration changes and determine the delta from the last 239789Sahrens * time the function was called. This function can fail, in case the pool has 240789Sahrens * been destroyed. 241789Sahrens */ 242789Sahrens int 2432142Seschrock zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 244789Sahrens { 245789Sahrens zfs_cmd_t zc = { 0 }; 246789Sahrens int error; 247952Seschrock nvlist_t *config; 2482676Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 249789Sahrens 2502142Seschrock *missing = B_FALSE; 251789Sahrens (void) strcpy(zc.zc_name, zhp->zpool_name); 252789Sahrens 253789Sahrens if (zhp->zpool_config_size == 0) 254789Sahrens zhp->zpool_config_size = 1 << 16; 255789Sahrens 2562676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0) 2572082Seschrock return (-1); 258789Sahrens 2591544Seschrock for (;;) { 2602082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, 2612082Seschrock &zc) == 0) { 262789Sahrens /* 2631544Seschrock * The real error is returned in the zc_cookie field. 264789Sahrens */ 2652142Seschrock error = zc.zc_cookie; 266789Sahrens break; 267789Sahrens } 268789Sahrens 2691544Seschrock if (errno == ENOMEM) { 2702676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 2712676Seschrock zcmd_free_nvlists(&zc); 2722082Seschrock return (-1); 2732676Seschrock } 2741544Seschrock } else { 2752676Seschrock zcmd_free_nvlists(&zc); 2762142Seschrock if (errno == ENOENT || errno == EINVAL) 2772142Seschrock *missing = B_TRUE; 2782142Seschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 2792142Seschrock return (0); 280789Sahrens } 281789Sahrens } 282789Sahrens 2832676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 2842676Seschrock zcmd_free_nvlists(&zc); 2852676Seschrock return (-1); 2862082Seschrock } 287789Sahrens 2882676Seschrock zcmd_free_nvlists(&zc); 2892676Seschrock 2902676Seschrock zhp->zpool_config_size = zc.zc_nvlist_dst_size; 291789Sahrens 292952Seschrock if (zhp->zpool_config != NULL) { 293952Seschrock uint64_t oldtxg, newtxg; 294952Seschrock 295952Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, 296952Seschrock ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 297952Seschrock verify(nvlist_lookup_uint64(config, 298952Seschrock ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 299789Sahrens 300952Seschrock if (zhp->zpool_old_config != NULL) 301952Seschrock nvlist_free(zhp->zpool_old_config); 302789Sahrens 303952Seschrock if (oldtxg != newtxg) { 304952Seschrock nvlist_free(zhp->zpool_config); 305952Seschrock zhp->zpool_old_config = NULL; 306952Seschrock } else { 307952Seschrock zhp->zpool_old_config = zhp->zpool_config; 308952Seschrock } 309952Seschrock } 310952Seschrock 311952Seschrock zhp->zpool_config = config; 3122142Seschrock if (error) 3132142Seschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 3142142Seschrock else 3152142Seschrock zhp->zpool_state = POOL_STATE_ACTIVE; 316789Sahrens 3172142Seschrock return (0); 318789Sahrens } 319789Sahrens 320789Sahrens /* 321789Sahrens * Iterate over all pools in the system. 322789Sahrens */ 323789Sahrens int 3242082Seschrock zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 325789Sahrens { 326789Sahrens config_node_t *cn; 327789Sahrens zpool_handle_t *zhp; 328789Sahrens int ret; 329789Sahrens 3302082Seschrock if (namespace_reload(hdl) != 0) 3312082Seschrock return (-1); 332789Sahrens 3332082Seschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 3342082Seschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 335789Sahrens 3362142Seschrock if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) 3372142Seschrock return (-1); 3382142Seschrock 3392142Seschrock if (zhp == NULL) 340789Sahrens continue; 341789Sahrens 342789Sahrens if ((ret = func(zhp, data)) != 0) 343789Sahrens return (ret); 344789Sahrens } 345789Sahrens 346789Sahrens return (0); 347789Sahrens } 348789Sahrens 349789Sahrens /* 350789Sahrens * Iterate over root datasets, calling the given function for each. The zfs 351789Sahrens * handle passed each time must be explicitly closed by the callback. 352789Sahrens */ 353789Sahrens int 3542082Seschrock zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 355789Sahrens { 356789Sahrens config_node_t *cn; 357789Sahrens zfs_handle_t *zhp; 358789Sahrens int ret; 359789Sahrens 3602082Seschrock if (namespace_reload(hdl) != 0) 3612082Seschrock return (-1); 362789Sahrens 3632082Seschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 3642082Seschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 365789Sahrens 3662082Seschrock if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 367789Sahrens continue; 368789Sahrens 369789Sahrens if ((ret = func(zhp, data)) != 0) 370789Sahrens return (ret); 371789Sahrens } 372789Sahrens 373789Sahrens return (0); 374789Sahrens } 375