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 http://www.opensolaris.org/os/licensing.
  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  */
  30 
  31 /*
  32  * The pool configuration repository is stored in /etc/zfs/zpool.cache as a
  33  * single packed nvlist.  While it would be nice to just read in this
  34  * file from userland, this wouldn't work from a local zone.  So we have to have
  35  * a zpool ioctl to return the complete configuration for all pools.  In the
  36  * global zone, this will be identical to reading the file and unpacking it in
  37  * userland.
  38  */
  39 
  40 #include <errno.h>
  41 #include <sys/stat.h>
  42 #include <fcntl.h>
  43 #include <stddef.h>
  44 #include <string.h>
  45 #include <unistd.h>
  46 #include <libintl.h>
  47 #include <libuutil.h>
  48 
  49 #include "libzfs_impl.h"
  50 
  51 typedef struct config_node {
  52         char            *cn_name;
  53         nvlist_t        *cn_config;
  54         uu_avl_node_t   cn_avl;
  55 } config_node_t;
  56 
  57 /* ARGSUSED */
  58 static int
  59 config_node_compare(const void *a, const void *b, void *unused)
  60 {
  61         int ret;
  62 
  63         const config_node_t *ca = (config_node_t *)a;
  64         const config_node_t *cb = (config_node_t *)b;
  65 
  66         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         if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
 130                 return (-1);
 131 
 132         for (;;) {
 133                 zc.zc_cookie = hdl->libzfs_ns_gen;
 134                 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
 135                         switch (errno) {
 136                         case EEXIST:
 137                                 /*
 138                                  * The namespace hasn't changed.
 139                                  */
 140                                 zcmd_free_nvlists(&zc);
 141                                 return (0);
 142 
 143                         case ENOMEM:
 144                                 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
 145                                         zcmd_free_nvlists(&zc);
 146                                         return (-1);
 147                                 }
 148                                 break;
 149 
 150                         default:
 151                                 zcmd_free_nvlists(&zc);
 152                                 return (zfs_standard_error(hdl, errno,
 153                                     dgettext(TEXT_DOMAIN, "failed to read "
 154                                     "pool configuration")));
 155                         }
 156                 } else {
 157                         hdl->libzfs_ns_gen = zc.zc_cookie;
 158                         break;
 159                 }
 160         }
 161 
 162         if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
 163                 zcmd_free_nvlists(&zc);
 164                 return (-1);
 165         }
 166 
 167         zcmd_free_nvlists(&zc);
 168 
 169         /*
 170          * Clear out any existing configuration information.
 171          */
 172         cookie = NULL;
 173         while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
 174                 nvlist_free(cn->cn_config);
 175                 free(cn->cn_name);
 176                 free(cn);
 177         }
 178 
 179         elem = NULL;
 180         while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
 181                 nvlist_t *child;
 182                 uu_avl_index_t where;
 183 
 184                 if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
 185                         nvlist_free(config);
 186                         return (-1);
 187                 }
 188 
 189                 if ((cn->cn_name = zfs_strdup(hdl,
 190                     nvpair_name(elem))) == NULL) {
 191                         free(cn);
 192                         nvlist_free(config);
 193                         return (-1);
 194                 }
 195 
 196                 verify(nvpair_value_nvlist(elem, &child) == 0);
 197                 if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
 198                         free(cn->cn_name);
 199                         free(cn);
 200                         nvlist_free(config);
 201                         return (no_memory(hdl));
 202                 }
 203                 verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
 204                     == NULL);
 205 
 206                 uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
 207         }
 208 
 209         nvlist_free(config);
 210         return (0);
 211 }
 212 
 213 /*
 214  * Retrieve the configuration for the given pool.  The configuration is a nvlist
 215  * describing the vdevs, as well as the statistics associated with each one.
 216  */
 217 nvlist_t *
 218 zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
 219 {
 220         if (oldconfig)
 221                 *oldconfig = zhp->zpool_old_config;
 222         return (zhp->zpool_config);
 223 }
 224 
 225 /*
 226  * Retrieves a list of enabled features and their refcounts and caches it in
 227  * the pool handle.
 228  */
 229 nvlist_t *
 230 zpool_get_features(zpool_handle_t *zhp)
 231 {
 232         nvlist_t *config, *features;
 233 
 234         config = zpool_get_config(zhp, NULL);
 235 
 236         if (config == NULL || !nvlist_exists(config,
 237             ZPOOL_CONFIG_FEATURE_STATS)) {
 238                 int error;
 239                 boolean_t missing = B_FALSE;
 240 
 241                 error = zpool_refresh_stats(zhp, &missing);
 242 
 243                 if (error != 0 || missing)
 244                         return (NULL);
 245 
 246                 config = zpool_get_config(zhp, NULL);
 247         }
 248 
 249         verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
 250             &features) == 0);
 251 
 252         return (features);
 253 }
 254 
 255 /*
 256  * Refresh the vdev statistics associated with the given pool.  This is used in
 257  * iostat to show configuration changes and determine the delta from the last
 258  * time the function was called.  This function can fail, in case the pool has
 259  * been destroyed.
 260  */
 261 int
 262 zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
 263 {
 264         zfs_cmd_t zc = { 0 };
 265         int error;
 266         nvlist_t *config;
 267         libzfs_handle_t *hdl = zhp->zpool_hdl;
 268 
 269         *missing = B_FALSE;
 270         (void) strcpy(zc.zc_name, zhp->zpool_name);
 271 
 272         if (zhp->zpool_config_size == 0)
 273                 zhp->zpool_config_size = 1 << 16;
 274 
 275         if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
 276                 return (-1);
 277 
 278         for (;;) {
 279                 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
 280                     &zc) == 0) {
 281                         /*
 282                          * The real error is returned in the zc_cookie field.
 283                          */
 284                         error = zc.zc_cookie;
 285                         break;
 286                 }
 287 
 288                 if (errno == ENOMEM) {
 289                         if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
 290                                 zcmd_free_nvlists(&zc);
 291                                 return (-1);
 292                         }
 293                 } else {
 294                         zcmd_free_nvlists(&zc);
 295                         if (errno == ENOENT || errno == EINVAL)
 296                                 *missing = B_TRUE;
 297                         zhp->zpool_state = POOL_STATE_UNAVAIL;
 298                         return (0);
 299                 }
 300         }
 301 
 302         if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
 303                 zcmd_free_nvlists(&zc);
 304                 return (-1);
 305         }
 306 
 307         zcmd_free_nvlists(&zc);
 308 
 309         zhp->zpool_config_size = zc.zc_nvlist_dst_size;
 310 
 311         if (zhp->zpool_config != NULL) {
 312                 uint64_t oldtxg, newtxg;
 313 
 314                 verify(nvlist_lookup_uint64(zhp->zpool_config,
 315                     ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
 316                 verify(nvlist_lookup_uint64(config,
 317                     ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);
 318 
 319                 if (zhp->zpool_old_config != NULL)
 320                         nvlist_free(zhp->zpool_old_config);
 321 
 322                 if (oldtxg != newtxg) {
 323                         nvlist_free(zhp->zpool_config);
 324                         zhp->zpool_old_config = NULL;
 325                 } else {
 326                         zhp->zpool_old_config = zhp->zpool_config;
 327                 }
 328         }
 329 
 330         zhp->zpool_config = config;
 331         if (error)
 332                 zhp->zpool_state = POOL_STATE_UNAVAIL;
 333         else
 334                 zhp->zpool_state = POOL_STATE_ACTIVE;
 335 
 336         return (0);
 337 }
 338 
 339 /*
 340  * If the __ZFS_POOL_RESTRICT environment variable is set we only iterate over
 341  * pools it lists.
 342  *
 343  * This is an undocumented feature for use during testing only.
 344  *
 345  * This function returns B_TRUE if the pool should be skipped
 346  * during iteration.
 347  */
 348 static boolean_t
 349 check_restricted(const char *poolname)
 350 {
 351         static boolean_t initialized = B_FALSE;
 352         static char *restricted = NULL;
 353 
 354         const char *cur, *end;
 355         int len, namelen;
 356 
 357         if (!initialized) {
 358                 initialized = B_TRUE;
 359                 restricted = getenv("__ZFS_POOL_RESTRICT");
 360         }
 361 
 362         if (NULL == restricted)
 363                 return (B_FALSE);
 364 
 365         cur = restricted;
 366         namelen = strlen(poolname);
 367         do {
 368                 end = strchr(cur, ' ');
 369                 len = (NULL == end) ? strlen(cur) : (end - cur);
 370 
 371                 if (len == namelen && 0 == strncmp(cur, poolname, len)) {
 372                         return (B_FALSE);
 373                 }
 374 
 375                 cur += (len + 1);
 376         } while (NULL != end);
 377 
 378         return (B_TRUE);
 379 }
 380 
 381 /*
 382  * Iterate over all pools in the system.
 383  */
 384 int
 385 zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
 386 {
 387         config_node_t *cn;
 388         zpool_handle_t *zhp;
 389         int ret;
 390 
 391         /*
 392          * If someone makes a recursive call to zpool_iter(), we want to avoid
 393          * refreshing the namespace because that will invalidate the parent
 394          * context.  We allow recursive calls, but simply re-use the same
 395          * namespace AVL tree.
 396          */
 397         if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
 398                 return (-1);
 399 
 400         hdl->libzfs_pool_iter++;
 401         for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
 402             cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
 403 
 404                 if (check_restricted(cn->cn_name))
 405                         continue;
 406 
 407                 if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
 408                         hdl->libzfs_pool_iter--;
 409                         return (-1);
 410                 }
 411 
 412                 if (zhp == NULL)
 413                         continue;
 414 
 415                 if ((ret = func(zhp, data)) != 0) {
 416                         hdl->libzfs_pool_iter--;
 417                         return (ret);
 418                 }
 419         }
 420         hdl->libzfs_pool_iter--;
 421 
 422         return (0);
 423 }
 424 
 425 /*
 426  * Iterate over root datasets, calling the given function for each.  The zfs
 427  * handle passed each time must be explicitly closed by the callback.
 428  */
 429 int
 430 zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
 431 {
 432         config_node_t *cn;
 433         zfs_handle_t *zhp;
 434         int ret;
 435 
 436         if (namespace_reload(hdl) != 0)
 437                 return (-1);
 438 
 439         for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
 440             cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
 441 
 442                 if (check_restricted(cn->cn_name))
 443                         continue;
 444 
 445                 if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
 446                         continue;
 447 
 448                 if ((ret = func(zhp, data)) != 0)
 449                         return (ret);
 450         }
 451 
 452         return (0);
 453 }