3246 ZFS I/O deadman thread
[zfs.git] / lib / libzfs / libzfs_config.c
index 94640d1..ee94fe1 100644 (file)
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident  "%Z%%M% %I%     %E% SMI"
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
 
 /*
  * The pool configuration repository is stored in /etc/zfs/zpool.cache as a
@@ -103,7 +106,7 @@ namespace_reload(libzfs_handle_t *hdl)
        nvlist_t *config;
        config_node_t *cn;
        nvpair_t *elem;
-       zfs_cmd_t zc = { 0 };
+       zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
        void *cookie;
 
        if (hdl->libzfs_ns_gen == 0) {
@@ -220,6 +223,36 @@ zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
 }
 
 /*
+ * Retrieves a list of enabled features and their refcounts and caches it in
+ * the pool handle.
+ */
+nvlist_t *
+zpool_get_features(zpool_handle_t *zhp)
+{
+       nvlist_t *config, *features;
+
+       config = zpool_get_config(zhp, NULL);
+
+       if (config == NULL || !nvlist_exists(config,
+           ZPOOL_CONFIG_FEATURE_STATS)) {
+               int error;
+               boolean_t missing = B_FALSE;
+
+               error = zpool_refresh_stats(zhp, &missing);
+
+               if (error != 0 || missing)
+                       return (NULL);
+
+               config = zpool_get_config(zhp, NULL);
+       }
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
+           &features) == 0);
+
+       return (features);
+}
+
+/*
  * Refresh the vdev statistics associated with the given pool.  This is used in
  * iostat to show configuration changes and determine the delta from the last
  * time the function was called.  This function can fail, in case the pool has
@@ -228,7 +261,7 @@ zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
 int
 zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
 {
-       zfs_cmd_t zc = { 0 };
+       zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
        int error;
        nvlist_t *config;
        libzfs_handle_t *hdl = zhp->zpool_hdl;
@@ -304,6 +337,48 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
 }
 
 /*
+ * If the __ZFS_POOL_RESTRICT environment variable is set we only iterate over
+ * pools it lists.
+ *
+ * This is an undocumented feature for use during testing only.
+ *
+ * This function returns B_TRUE if the pool should be skipped
+ * during iteration.
+ */
+static boolean_t
+check_restricted(const char *poolname)
+{
+       static boolean_t initialized = B_FALSE;
+       static char *restricted = NULL;
+
+       const char *cur, *end;
+       int len, namelen;
+
+       if (!initialized) {
+               initialized = B_TRUE;
+               restricted = getenv("__ZFS_POOL_RESTRICT");
+       }
+
+       if (NULL == restricted)
+               return (B_FALSE);
+
+       cur = restricted;
+       namelen = strlen(poolname);
+       do {
+               end = strchr(cur, ' ');
+               len = (NULL == end) ? strlen(cur) : (end - cur);
+
+               if (len == namelen && 0 == strncmp(cur, poolname, len)) {
+                       return (B_FALSE);
+               }
+
+               cur += (len + 1);
+       } while (NULL != end);
+
+       return (B_TRUE);
+}
+
+/*
  * Iterate over all pools in the system.
  */
 int
@@ -313,21 +388,36 @@ zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
        zpool_handle_t *zhp;
        int ret;
 
-       if (namespace_reload(hdl) != 0)
+       /*
+        * If someone makes a recursive call to zpool_iter(), we want to avoid
+        * refreshing the namespace because that will invalidate the parent
+        * context.  We allow recursive calls, but simply re-use the same
+        * namespace AVL tree.
+        */
+       if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
                return (-1);
 
+       hdl->libzfs_pool_iter++;
        for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
            cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
 
-               if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0)
+               if (check_restricted(cn->cn_name))
+                       continue;
+
+               if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
+                       hdl->libzfs_pool_iter--;
                        return (-1);
+               }
 
                if (zhp == NULL)
                        continue;
 
-               if ((ret = func(zhp, data)) != 0)
+               if ((ret = func(zhp, data)) != 0) {
+                       hdl->libzfs_pool_iter--;
                        return (ret);
+               }
        }
+       hdl->libzfs_pool_iter--;
 
        return (0);
 }
@@ -349,6 +439,9 @@ zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
        for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
            cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
 
+               if (check_restricted(cn->cn_name))
+                       continue;
+
                if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
                        continue;