Path: blob/main/sys/contrib/openzfs/lib/libzfs/libzfs_config.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright 2009 Sun Microsystems, Inc. All rights reserved.24* Use is subject to license terms.25*/2627/*28* Copyright (c) 2012 by Delphix. All rights reserved.29* Copyright (c) 2015 by Syneto S.R.L. All rights reserved.30* Copyright 2016 Nexenta Systems, Inc.31*/3233/*34* The pool configuration repository is stored in /etc/zfs/zpool.cache as a35* single packed nvlist. While it would be nice to just read in this36* file from userland, this wouldn't work from a local zone. So we have to have37* a zpool ioctl to return the complete configuration for all pools. In the38* global zone, this will be identical to reading the file and unpacking it in39* userland.40*/4142#include <errno.h>43#include <sys/stat.h>44#include <fcntl.h>45#include <stddef.h>46#include <string.h>47#include <unistd.h>48#include <libintl.h>49#include <libuutil.h>5051#include "libzfs_impl.h"5253typedef struct config_node {54char *cn_name;55nvlist_t *cn_config;56uu_avl_node_t cn_avl;57} config_node_t;5859static int60config_node_compare(const void *a, const void *b, void *unused)61{62(void) unused;63const config_node_t *ca = (config_node_t *)a;64const config_node_t *cb = (config_node_t *)b;6566int ret = strcmp(ca->cn_name, cb->cn_name);6768if (ret < 0)69return (-1);70else if (ret > 0)71return (1);72else73return (0);74}7576void77namespace_clear(libzfs_handle_t *hdl)78{79if (hdl->libzfs_ns_avl) {80config_node_t *cn;81void *cookie = NULL;8283while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,84&cookie)) != NULL) {85nvlist_free(cn->cn_config);86free(cn->cn_name);87free(cn);88}8990uu_avl_destroy(hdl->libzfs_ns_avl);91hdl->libzfs_ns_avl = NULL;92}9394if (hdl->libzfs_ns_avlpool) {95uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);96hdl->libzfs_ns_avlpool = NULL;97}98}99100/*101* Loads the pool namespace, or re-loads it if the cache has changed.102*/103static int104namespace_reload(libzfs_handle_t *hdl)105{106nvlist_t *config;107config_node_t *cn;108nvpair_t *elem;109zfs_cmd_t zc = {"\0"};110void *cookie;111112if (hdl->libzfs_ns_gen == 0) {113/*114* This is the first time we've accessed the configuration115* cache. Initialize the AVL tree and then fall through to the116* common code.117*/118if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",119sizeof (config_node_t),120offsetof(config_node_t, cn_avl),121config_node_compare, UU_DEFAULT)) == NULL)122return (no_memory(hdl));123124if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,125NULL, UU_DEFAULT)) == NULL)126return (no_memory(hdl));127}128129zcmd_alloc_dst_nvlist(hdl, &zc, 0);130131for (;;) {132zc.zc_cookie = hdl->libzfs_ns_gen;133if (zfs_ioctl(hdl, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {134switch (errno) {135case EEXIST:136/*137* The namespace hasn't changed.138*/139zcmd_free_nvlists(&zc);140return (0);141142case ENOMEM:143zcmd_expand_dst_nvlist(hdl, &zc);144break;145146default:147zcmd_free_nvlists(&zc);148return (zfs_standard_error(hdl, errno,149dgettext(TEXT_DOMAIN, "failed to read "150"pool configuration")));151}152} else {153hdl->libzfs_ns_gen = zc.zc_cookie;154break;155}156}157158if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {159zcmd_free_nvlists(&zc);160return (-1);161}162163zcmd_free_nvlists(&zc);164165/*166* Clear out any existing configuration information.167*/168cookie = NULL;169while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {170nvlist_free(cn->cn_config);171free(cn->cn_name);172free(cn);173}174175elem = NULL;176while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {177nvlist_t *child;178uu_avl_index_t where;179180cn = zfs_alloc(hdl, sizeof (config_node_t));181cn->cn_name = zfs_strdup(hdl, nvpair_name(elem));182child = fnvpair_value_nvlist(elem);183if (nvlist_dup(child, &cn->cn_config, 0) != 0) {184free(cn->cn_name);185free(cn);186nvlist_free(config);187return (no_memory(hdl));188}189verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)190== NULL);191192uu_avl_insert(hdl->libzfs_ns_avl, cn, where);193}194195nvlist_free(config);196return (0);197}198199/*200* Retrieve the configuration for the given pool. The configuration is an nvlist201* describing the vdevs, as well as the statistics associated with each one.202*/203nvlist_t *204zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)205{206if (oldconfig)207*oldconfig = zhp->zpool_old_config;208return (zhp->zpool_config);209}210211/*212* Retrieves a list of enabled features and their refcounts and caches it in213* the pool handle.214*/215nvlist_t *216zpool_get_features(zpool_handle_t *zhp)217{218nvlist_t *config, *features;219220config = zpool_get_config(zhp, NULL);221222if (config == NULL || !nvlist_exists(config,223ZPOOL_CONFIG_FEATURE_STATS)) {224int error;225boolean_t missing = B_FALSE;226227error = zpool_refresh_stats(zhp, &missing);228229if (error != 0 || missing)230return (NULL);231232config = zpool_get_config(zhp, NULL);233}234235if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,236&features) != 0)237return (NULL);238239return (features);240}241242/*243* Refresh the vdev statistics associated with the given pool. This is used in244* iostat to show configuration changes and determine the delta from the last245* time the function was called. This function can fail, in case the pool has246* been destroyed.247*/248int249zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)250{251zfs_cmd_t zc = {"\0"};252int error;253nvlist_t *config;254libzfs_handle_t *hdl = zhp->zpool_hdl;255256*missing = B_FALSE;257(void) strcpy(zc.zc_name, zhp->zpool_name);258259if (zhp->zpool_config_size == 0)260zhp->zpool_config_size = 1 << 16;261262zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size);263264for (;;) {265if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_STATS,266&zc) == 0) {267/*268* The real error is returned in the zc_cookie field.269*/270error = zc.zc_cookie;271break;272}273274if (errno == ENOMEM)275zcmd_expand_dst_nvlist(hdl, &zc);276else {277zcmd_free_nvlists(&zc);278if (errno == ENOENT || errno == EINVAL)279*missing = B_TRUE;280zhp->zpool_state = POOL_STATE_UNAVAIL;281return (0);282}283}284285if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {286zcmd_free_nvlists(&zc);287return (-1);288}289290zcmd_free_nvlists(&zc);291292zhp->zpool_config_size = zc.zc_nvlist_dst_size;293294if (zhp->zpool_config != NULL) {295nvlist_free(zhp->zpool_old_config);296297zhp->zpool_old_config = zhp->zpool_config;298}299300zhp->zpool_config = config;301if (error)302zhp->zpool_state = POOL_STATE_UNAVAIL;303else304zhp->zpool_state = POOL_STATE_ACTIVE;305306return (0);307}308309/*310* Copies the pool config and state from szhp to dzhp. szhp and dzhp must311* represent the same pool. Used by pool_list_refresh() to avoid another312* round-trip into the kernel to get stats already collected earlier in the313* function.314*/315void316zpool_refresh_stats_from_handle(zpool_handle_t *dzhp, zpool_handle_t *szhp)317{318VERIFY0(strcmp(dzhp->zpool_name, szhp->zpool_name));319nvlist_free(dzhp->zpool_old_config);320dzhp->zpool_old_config = dzhp->zpool_config;321dzhp->zpool_config = fnvlist_dup(szhp->zpool_config);322dzhp->zpool_config_size = szhp->zpool_config_size;323dzhp->zpool_state = szhp->zpool_state;324}325326/*327* The following environment variables are undocumented328* and should be used for testing purposes only:329*330* __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists331* __ZFS_POOL_RESTRICT - iterate only over the pools it lists332*333* This function returns B_TRUE if the pool should be skipped334* during iteration.335*/336boolean_t337zpool_skip_pool(const char *poolname)338{339static boolean_t initialized = B_FALSE;340static const char *exclude = NULL;341static const char *restricted = NULL;342343const char *cur, *end;344int len;345int namelen = strlen(poolname);346347if (!initialized) {348initialized = B_TRUE;349exclude = getenv("__ZFS_POOL_EXCLUDE");350restricted = getenv("__ZFS_POOL_RESTRICT");351}352353if (exclude != NULL) {354cur = exclude;355do {356end = strchr(cur, ' ');357len = (NULL == end) ? strlen(cur) : (end - cur);358if (len == namelen && 0 == strncmp(cur, poolname, len))359return (B_TRUE);360cur += (len + 1);361} while (NULL != end);362}363364if (NULL == restricted)365return (B_FALSE);366367cur = restricted;368do {369end = strchr(cur, ' ');370len = (NULL == end) ? strlen(cur) : (end - cur);371372if (len == namelen && 0 == strncmp(cur, poolname, len)) {373return (B_FALSE);374}375376cur += (len + 1);377} while (NULL != end);378379return (B_TRUE);380}381382/*383* Iterate over all pools in the system.384*/385int386zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)387{388config_node_t *cn;389zpool_handle_t *zhp;390int ret;391392/*393* If someone makes a recursive call to zpool_iter(), we want to avoid394* refreshing the namespace because that will invalidate the parent395* context. We allow recursive calls, but simply re-use the same396* namespace AVL tree.397*/398if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)399return (-1);400401hdl->libzfs_pool_iter++;402for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;403cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {404405if (zpool_skip_pool(cn->cn_name))406continue;407408if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {409hdl->libzfs_pool_iter--;410return (-1);411}412413if (zhp == NULL)414continue;415416if ((ret = func(zhp, data)) != 0) {417hdl->libzfs_pool_iter--;418return (ret);419}420}421hdl->libzfs_pool_iter--;422423return (0);424}425426/*427* Iterate over root datasets, calling the given function for each. The zfs428* handle passed each time must be explicitly closed by the callback.429*/430int431zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)432{433config_node_t *cn;434zfs_handle_t *zhp;435int ret;436437if (namespace_reload(hdl) != 0)438return (-1);439440for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;441cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {442443if (zpool_skip_pool(cn->cn_name))444continue;445446if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)447continue;448449if ((ret = func(zhp, data)) != 0)450return (ret);451}452453return (0);454}455456457