The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/lib/libzfs/libzfs_config.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * 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.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 
   22 /*
   23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   24  * Use is subject to license terms.
   25  */
   26 
   27 /*
   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  */
   32 
   33 /*
   34  * The pool configuration repository is stored in /etc/zfs/zpool.cache as a
   35  * single packed nvlist.  While it would be nice to just read in this
   36  * file from userland, this wouldn't work from a local zone.  So we have to have
   37  * a zpool ioctl to return the complete configuration for all pools.  In the
   38  * global zone, this will be identical to reading the file and unpacking it in
   39  * userland.
   40  */
   41 
   42 #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>
   50 
   51 #include "libzfs_impl.h"
   52 
   53 typedef struct config_node {
   54         char            *cn_name;
   55         nvlist_t        *cn_config;
   56         uu_avl_node_t   cn_avl;
   57 } config_node_t;
   58 
   59 static int
   60 config_node_compare(const void *a, const void *b, void *unused)
   61 {
   62         (void) unused;
   63         const config_node_t *ca = (config_node_t *)a;
   64         const config_node_t *cb = (config_node_t *)b;
   65 
   66         int ret = strcmp(ca->cn_name, cb->cn_name);
   67 
   68         if (ret < 0)
   69                 return (-1);
   70         else if (ret > 0)
   71                 return (1);
   72         else
   73                 return (0);
   74 }
   75 
   76 void
   77 namespace_clear(libzfs_handle_t *hdl)
   78 {
   79         if (hdl->libzfs_ns_avl) {
   80                 config_node_t *cn;
   81                 void *cookie = NULL;
   82 
   83                 while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,
   84                     &cookie)) != NULL) {
   85                         nvlist_free(cn->cn_config);
   86                         free(cn->cn_name);
   87                         free(cn);
   88                 }
   89 
   90                 uu_avl_destroy(hdl->libzfs_ns_avl);
   91                 hdl->libzfs_ns_avl = NULL;
   92         }
   93 
   94         if (hdl->libzfs_ns_avlpool) {
   95                 uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
   96                 hdl->libzfs_ns_avlpool = NULL;
   97         }
   98 }
   99 
  100 /*
  101  * Loads the pool namespace, or re-loads it if the cache has changed.
  102  */
  103 static int
  104 namespace_reload(libzfs_handle_t *hdl)
  105 {
  106         nvlist_t *config;
  107         config_node_t *cn;
  108         nvpair_t *elem;
  109         zfs_cmd_t zc = {"\0"};
  110         void *cookie;
  111 
  112         if (hdl->libzfs_ns_gen == 0) {
  113                 /*
  114                  * This is the first time we've accessed the configuration
  115                  * cache.  Initialize the AVL tree and then fall through to the
  116                  * common code.
  117                  */
  118                 if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
  119                     sizeof (config_node_t),
  120                     offsetof(config_node_t, cn_avl),
  121                     config_node_compare, UU_DEFAULT)) == NULL)
  122                         return (no_memory(hdl));
  123 
  124                 if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
  125                     NULL, UU_DEFAULT)) == NULL)
  126                         return (no_memory(hdl));
  127         }
  128 
  129         zcmd_alloc_dst_nvlist(hdl, &zc, 0);
  130 
  131         for (;;) {
  132                 zc.zc_cookie = hdl->libzfs_ns_gen;
  133                 if (zfs_ioctl(hdl, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
  134                         switch (errno) {
  135                         case EEXIST:
  136                                 /*
  137                                  * The namespace hasn't changed.
  138                                  */
  139                                 zcmd_free_nvlists(&zc);
  140                                 return (0);
  141 
  142                         case ENOMEM:
  143                                 zcmd_expand_dst_nvlist(hdl, &zc);
  144                                 break;
  145 
  146                         default:
  147                                 zcmd_free_nvlists(&zc);
  148                                 return (zfs_standard_error(hdl, errno,
  149                                     dgettext(TEXT_DOMAIN, "failed to read "
  150                                     "pool configuration")));
  151                         }
  152                 } else {
  153                         hdl->libzfs_ns_gen = zc.zc_cookie;
  154                         break;
  155                 }
  156         }
  157 
  158         if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
  159                 zcmd_free_nvlists(&zc);
  160                 return (-1);
  161         }
  162 
  163         zcmd_free_nvlists(&zc);
  164 
  165         /*
  166          * Clear out any existing configuration information.
  167          */
  168         cookie = NULL;
  169         while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
  170                 nvlist_free(cn->cn_config);
  171                 free(cn->cn_name);
  172                 free(cn);
  173         }
  174 
  175         elem = NULL;
  176         while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
  177                 nvlist_t *child;
  178                 uu_avl_index_t where;
  179 
  180                 cn = zfs_alloc(hdl, sizeof (config_node_t));
  181                 cn->cn_name = zfs_strdup(hdl, nvpair_name(elem));
  182                 child = fnvpair_value_nvlist(elem);
  183                 if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
  184                         free(cn->cn_name);
  185                         free(cn);
  186                         nvlist_free(config);
  187                         return (no_memory(hdl));
  188                 }
  189                 verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
  190                     == NULL);
  191 
  192                 uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
  193         }
  194 
  195         nvlist_free(config);
  196         return (0);
  197 }
  198 
  199 /*
  200  * Retrieve the configuration for the given pool. The configuration is an nvlist
  201  * describing the vdevs, as well as the statistics associated with each one.
  202  */
  203 nvlist_t *
  204 zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
  205 {
  206         if (oldconfig)
  207                 *oldconfig = zhp->zpool_old_config;
  208         return (zhp->zpool_config);
  209 }
  210 
  211 /*
  212  * Retrieves a list of enabled features and their refcounts and caches it in
  213  * the pool handle.
  214  */
  215 nvlist_t *
  216 zpool_get_features(zpool_handle_t *zhp)
  217 {
  218         nvlist_t *config, *features;
  219 
  220         config = zpool_get_config(zhp, NULL);
  221 
  222         if (config == NULL || !nvlist_exists(config,
  223             ZPOOL_CONFIG_FEATURE_STATS)) {
  224                 int error;
  225                 boolean_t missing = B_FALSE;
  226 
  227                 error = zpool_refresh_stats(zhp, &missing);
  228 
  229                 if (error != 0 || missing)
  230                         return (NULL);
  231 
  232                 config = zpool_get_config(zhp, NULL);
  233         }
  234 
  235         if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
  236             &features) != 0)
  237                 return (NULL);
  238 
  239         return (features);
  240 }
  241 
  242 /*
  243  * Refresh the vdev statistics associated with the given pool.  This is used in
  244  * iostat to show configuration changes and determine the delta from the last
  245  * time the function was called.  This function can fail, in case the pool has
  246  * been destroyed.
  247  */
  248 int
  249 zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
  250 {
  251         zfs_cmd_t zc = {"\0"};
  252         int error;
  253         nvlist_t *config;
  254         libzfs_handle_t *hdl = zhp->zpool_hdl;
  255 
  256         *missing = B_FALSE;
  257         (void) strcpy(zc.zc_name, zhp->zpool_name);
  258 
  259         if (zhp->zpool_config_size == 0)
  260                 zhp->zpool_config_size = 1 << 16;
  261 
  262         zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size);
  263 
  264         for (;;) {
  265                 if (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                          */
  270                         error = zc.zc_cookie;
  271                         break;
  272                 }
  273 
  274                 if (errno == ENOMEM)
  275                         zcmd_expand_dst_nvlist(hdl, &zc);
  276                 else {
  277                         zcmd_free_nvlists(&zc);
  278                         if (errno == ENOENT || errno == EINVAL)
  279                                 *missing = B_TRUE;
  280                         zhp->zpool_state = POOL_STATE_UNAVAIL;
  281                         return (0);
  282                 }
  283         }
  284 
  285         if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
  286                 zcmd_free_nvlists(&zc);
  287                 return (-1);
  288         }
  289 
  290         zcmd_free_nvlists(&zc);
  291 
  292         zhp->zpool_config_size = zc.zc_nvlist_dst_size;
  293 
  294         if (zhp->zpool_config != NULL) {
  295                 nvlist_free(zhp->zpool_old_config);
  296 
  297                 zhp->zpool_old_config = zhp->zpool_config;
  298         }
  299 
  300         zhp->zpool_config = config;
  301         if (error)
  302                 zhp->zpool_state = POOL_STATE_UNAVAIL;
  303         else
  304                 zhp->zpool_state = POOL_STATE_ACTIVE;
  305 
  306         return (0);
  307 }
  308 
  309 /*
  310  * The following environment variables are undocumented
  311  * and should be used for testing purposes only:
  312  *
  313  * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists
  314  * __ZFS_POOL_RESTRICT - iterate only over the pools it lists
  315  *
  316  * This function returns B_TRUE if the pool should be skipped
  317  * during iteration.
  318  */
  319 boolean_t
  320 zpool_skip_pool(const char *poolname)
  321 {
  322         static boolean_t initialized = B_FALSE;
  323         static const char *exclude = NULL;
  324         static const char *restricted = NULL;
  325 
  326         const char *cur, *end;
  327         int len;
  328         int namelen = strlen(poolname);
  329 
  330         if (!initialized) {
  331                 initialized = B_TRUE;
  332                 exclude = getenv("__ZFS_POOL_EXCLUDE");
  333                 restricted = getenv("__ZFS_POOL_RESTRICT");
  334         }
  335 
  336         if (exclude != NULL) {
  337                 cur = exclude;
  338                 do {
  339                         end = strchr(cur, ' ');
  340                         len = (NULL == end) ? strlen(cur) : (end - cur);
  341                         if (len == namelen && 0 == strncmp(cur, poolname, len))
  342                                 return (B_TRUE);
  343                         cur += (len + 1);
  344                 } while (NULL != end);
  345         }
  346 
  347         if (NULL == restricted)
  348                 return (B_FALSE);
  349 
  350         cur = restricted;
  351         do {
  352                 end = strchr(cur, ' ');
  353                 len = (NULL == end) ? strlen(cur) : (end - cur);
  354 
  355                 if (len == namelen && 0 == strncmp(cur, poolname, len)) {
  356                         return (B_FALSE);
  357                 }
  358 
  359                 cur += (len + 1);
  360         } while (NULL != end);
  361 
  362         return (B_TRUE);
  363 }
  364 
  365 /*
  366  * Iterate over all pools in the system.
  367  */
  368 int
  369 zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
  370 {
  371         config_node_t *cn;
  372         zpool_handle_t *zhp;
  373         int ret;
  374 
  375         /*
  376          * If someone makes a recursive call to zpool_iter(), we want to avoid
  377          * refreshing the namespace because that will invalidate the parent
  378          * context.  We allow recursive calls, but simply re-use the same
  379          * namespace AVL tree.
  380          */
  381         if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
  382                 return (-1);
  383 
  384         hdl->libzfs_pool_iter++;
  385         for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
  386             cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
  387 
  388                 if (zpool_skip_pool(cn->cn_name))
  389                         continue;
  390 
  391                 if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
  392                         hdl->libzfs_pool_iter--;
  393                         return (-1);
  394                 }
  395 
  396                 if (zhp == NULL)
  397                         continue;
  398 
  399                 if ((ret = func(zhp, data)) != 0) {
  400                         hdl->libzfs_pool_iter--;
  401                         return (ret);
  402                 }
  403         }
  404         hdl->libzfs_pool_iter--;
  405 
  406         return (0);
  407 }
  408 
  409 /*
  410  * Iterate over root datasets, calling the given function for each.  The zfs
  411  * handle passed each time must be explicitly closed by the callback.
  412  */
  413 int
  414 zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
  415 {
  416         config_node_t *cn;
  417         zfs_handle_t *zhp;
  418         int ret;
  419 
  420         if (namespace_reload(hdl) != 0)
  421                 return (-1);
  422 
  423         for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
  424             cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
  425 
  426                 if (zpool_skip_pool(cn->cn_name))
  427                         continue;
  428 
  429                 if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
  430                         continue;
  431 
  432                 if ((ret = func(zhp, data)) != 0)
  433                         return (ret);
  434         }
  435 
  436         return (0);
  437 }

Cache object: 594c755c7176416a51887a4d8d988424


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.