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 /* 223741Smmusante * 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 config_node_t *cn; 78*4074Seschrock void *cookie = NULL; 792082Seschrock 80*4074Seschrock while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, 81*4074Seschrock &cookie)) != NULL) { 822082Seschrock nvlist_free(cn->cn_config); 832082Seschrock free(cn->cn_name); 842082Seschrock free(cn); 852082Seschrock } 862082Seschrock 872082Seschrock uu_avl_destroy(hdl->libzfs_ns_avl); 882082Seschrock hdl->libzfs_ns_avl = NULL; 892082Seschrock } 902082Seschrock 912082Seschrock if (hdl->libzfs_ns_avlpool) { 922082Seschrock uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); 932082Seschrock hdl->libzfs_ns_avlpool = NULL; 942082Seschrock } 952082Seschrock } 962082Seschrock 97789Sahrens /* 98789Sahrens * Loads the pool namespace, or re-loads it if the cache has changed. 99789Sahrens */ 1002082Seschrock static int 1012082Seschrock namespace_reload(libzfs_handle_t *hdl) 102789Sahrens { 103789Sahrens nvlist_t *config; 104789Sahrens config_node_t *cn; 105789Sahrens nvpair_t *elem; 106789Sahrens zfs_cmd_t zc = { 0 }; 107*4074Seschrock void *cookie; 108789Sahrens 1092082Seschrock if (hdl->libzfs_ns_gen == 0) { 110789Sahrens /* 111789Sahrens * This is the first time we've accessed the configuration 112789Sahrens * cache. Initialize the AVL tree and then fall through to the 113789Sahrens * common code. 114789Sahrens */ 1152082Seschrock if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", 116789Sahrens sizeof (config_node_t), 117789Sahrens offsetof(config_node_t, cn_avl), 118789Sahrens config_node_compare, UU_DEFAULT)) == NULL) 1192082Seschrock return (no_memory(hdl)); 120789Sahrens 1212082Seschrock if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, 1222082Seschrock NULL, UU_DEFAULT)) == NULL) 1232082Seschrock return (no_memory(hdl)); 124789Sahrens } 125789Sahrens 1262676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 1272082Seschrock return (-1); 1282676Seschrock 129789Sahrens for (;;) { 1302082Seschrock zc.zc_cookie = hdl->libzfs_ns_gen; 1312082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 132789Sahrens switch (errno) { 133789Sahrens case EEXIST: 134789Sahrens /* 135789Sahrens * The namespace hasn't changed. 136789Sahrens */ 1372676Seschrock zcmd_free_nvlists(&zc); 1382082Seschrock return (0); 139789Sahrens 140789Sahrens case ENOMEM: 1412676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 1422676Seschrock zcmd_free_nvlists(&zc); 1432082Seschrock return (-1); 1442676Seschrock } 145789Sahrens break; 146789Sahrens 147789Sahrens default: 1482676Seschrock zcmd_free_nvlists(&zc); 1492082Seschrock return (zfs_standard_error(hdl, errno, 1502082Seschrock dgettext(TEXT_DOMAIN, "failed to read " 1512082Seschrock "pool configuration"))); 152789Sahrens } 153789Sahrens } else { 1542082Seschrock hdl->libzfs_ns_gen = zc.zc_cookie; 155789Sahrens break; 156789Sahrens } 157789Sahrens } 158789Sahrens 1592676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 1602676Seschrock zcmd_free_nvlists(&zc); 1612676Seschrock return (-1); 1622142Seschrock } 163789Sahrens 1642676Seschrock zcmd_free_nvlists(&zc); 165789Sahrens 166789Sahrens /* 167789Sahrens * Clear out any existing configuration information. 168789Sahrens */ 169*4074Seschrock cookie = NULL; 170*4074Seschrock while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) { 171789Sahrens nvlist_free(cn->cn_config); 172789Sahrens free(cn->cn_name); 173789Sahrens free(cn); 174789Sahrens } 175789Sahrens 176789Sahrens elem = NULL; 177789Sahrens while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 178789Sahrens nvlist_t *child; 179789Sahrens uu_avl_index_t where; 180789Sahrens 1812082Seschrock if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 1822082Seschrock nvlist_free(config); 1832082Seschrock return (-1); 1842082Seschrock } 1852082Seschrock 1862082Seschrock if ((cn->cn_name = zfs_strdup(hdl, 1872082Seschrock nvpair_name(elem))) == NULL) { 1882082Seschrock free(cn); 1892474Seschrock nvlist_free(config); 1902082Seschrock return (-1); 1912082Seschrock } 192789Sahrens 193789Sahrens verify(nvpair_value_nvlist(elem, &child) == 0); 1942082Seschrock if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 1952474Seschrock free(cn->cn_name); 1962474Seschrock free(cn); 1972082Seschrock nvlist_free(config); 1982082Seschrock return (no_memory(hdl)); 1992082Seschrock } 2002082Seschrock verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 2012082Seschrock == NULL); 202789Sahrens 2032082Seschrock uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 204789Sahrens } 205789Sahrens 206789Sahrens nvlist_free(config); 2072082Seschrock return (0); 208789Sahrens } 209789Sahrens 210789Sahrens /* 211*4074Seschrock * Retrieve the configuration for the given pool. The configuration is a nvlist 212789Sahrens * describing the vdevs, as well as the statistics associated with each one. 213789Sahrens */ 214789Sahrens nvlist_t * 215952Seschrock zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 216789Sahrens { 217952Seschrock if (oldconfig) 218952Seschrock *oldconfig = zhp->zpool_old_config; 219789Sahrens return (zhp->zpool_config); 220789Sahrens } 221789Sahrens 222789Sahrens /* 223789Sahrens * Refresh the vdev statistics associated with the given pool. This is used in 224789Sahrens * iostat to show configuration changes and determine the delta from the last 225789Sahrens * time the function was called. This function can fail, in case the pool has 226789Sahrens * been destroyed. 227789Sahrens */ 228789Sahrens int 2292142Seschrock zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 230789Sahrens { 231789Sahrens zfs_cmd_t zc = { 0 }; 232789Sahrens int error; 233952Seschrock nvlist_t *config; 2342676Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 235789Sahrens 2362142Seschrock *missing = B_FALSE; 237789Sahrens (void) strcpy(zc.zc_name, zhp->zpool_name); 238789Sahrens 239789Sahrens if (zhp->zpool_config_size == 0) 240789Sahrens zhp->zpool_config_size = 1 << 16; 241789Sahrens 2422676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0) 2432082Seschrock return (-1); 244789Sahrens 2451544Seschrock for (;;) { 2462082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, 2472082Seschrock &zc) == 0) { 248789Sahrens /* 2491544Seschrock * The real error is returned in the zc_cookie field. 250789Sahrens */ 2512142Seschrock error = zc.zc_cookie; 252789Sahrens break; 253789Sahrens } 254789Sahrens 2551544Seschrock if (errno == ENOMEM) { 2562676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 2572676Seschrock zcmd_free_nvlists(&zc); 2582082Seschrock return (-1); 2592676Seschrock } 2601544Seschrock } else { 2612676Seschrock zcmd_free_nvlists(&zc); 2622142Seschrock if (errno == ENOENT || errno == EINVAL) 2632142Seschrock *missing = B_TRUE; 2642142Seschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 2652142Seschrock return (0); 266789Sahrens } 267789Sahrens } 268789Sahrens 2692676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 2702676Seschrock zcmd_free_nvlists(&zc); 2712676Seschrock return (-1); 2722082Seschrock } 273789Sahrens 2742676Seschrock zcmd_free_nvlists(&zc); 2752676Seschrock 2762676Seschrock zhp->zpool_config_size = zc.zc_nvlist_dst_size; 277789Sahrens 278952Seschrock if (zhp->zpool_config != NULL) { 279952Seschrock uint64_t oldtxg, newtxg; 280952Seschrock 281952Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, 282952Seschrock ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 283952Seschrock verify(nvlist_lookup_uint64(config, 284952Seschrock ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 285789Sahrens 286952Seschrock if (zhp->zpool_old_config != NULL) 287952Seschrock nvlist_free(zhp->zpool_old_config); 288789Sahrens 289952Seschrock if (oldtxg != newtxg) { 290952Seschrock nvlist_free(zhp->zpool_config); 291952Seschrock zhp->zpool_old_config = NULL; 292952Seschrock } else { 293952Seschrock zhp->zpool_old_config = zhp->zpool_config; 294952Seschrock } 295952Seschrock } 296952Seschrock 297952Seschrock zhp->zpool_config = config; 2982142Seschrock if (error) 2992142Seschrock zhp->zpool_state = POOL_STATE_UNAVAIL; 3002142Seschrock else 3012142Seschrock zhp->zpool_state = POOL_STATE_ACTIVE; 302789Sahrens 3032142Seschrock return (0); 304789Sahrens } 305789Sahrens 306789Sahrens /* 307789Sahrens * Iterate over all pools in the system. 308789Sahrens */ 309789Sahrens int 3102082Seschrock zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 311789Sahrens { 312789Sahrens config_node_t *cn; 313789Sahrens zpool_handle_t *zhp; 314789Sahrens int ret; 315789Sahrens 3162082Seschrock if (namespace_reload(hdl) != 0) 3172082Seschrock return (-1); 318789Sahrens 3192082Seschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 3202082Seschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 321789Sahrens 3222142Seschrock if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) 3232142Seschrock return (-1); 3242142Seschrock 3252142Seschrock if (zhp == NULL) 326789Sahrens continue; 327789Sahrens 328789Sahrens if ((ret = func(zhp, data)) != 0) 329789Sahrens return (ret); 330789Sahrens } 331789Sahrens 332789Sahrens return (0); 333789Sahrens } 334789Sahrens 335789Sahrens /* 336789Sahrens * Iterate over root datasets, calling the given function for each. The zfs 337789Sahrens * handle passed each time must be explicitly closed by the callback. 338789Sahrens */ 339789Sahrens int 3402082Seschrock zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 341789Sahrens { 342789Sahrens config_node_t *cn; 343789Sahrens zfs_handle_t *zhp; 344789Sahrens int ret; 345789Sahrens 3462082Seschrock if (namespace_reload(hdl) != 0) 3472082Seschrock return (-1); 348789Sahrens 3492082Seschrock for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 3502082Seschrock cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 351789Sahrens 3522082Seschrock if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 353789Sahrens continue; 354789Sahrens 355789Sahrens if ((ret = func(zhp, data)) != 0) 356789Sahrens return (ret); 357789Sahrens } 358789Sahrens 359789Sahrens return (0); 360789Sahrens } 361