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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
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.
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
51 #include "libzfs_impl.h"
53 typedef struct config_node
{
60 config_node_compare(const void *a
, const void *b
, void *unused
)
63 const config_node_t
*ca
= (config_node_t
*)a
;
64 const config_node_t
*cb
= (config_node_t
*)b
;
66 int ret
= strcmp(ca
->cn_name
, cb
->cn_name
);
77 namespace_clear(libzfs_handle_t
*hdl
)
79 if (hdl
->libzfs_ns_avl
) {
83 while ((cn
= uu_avl_teardown(hdl
->libzfs_ns_avl
,
85 nvlist_free(cn
->cn_config
);
90 uu_avl_destroy(hdl
->libzfs_ns_avl
);
91 hdl
->libzfs_ns_avl
= NULL
;
94 if (hdl
->libzfs_ns_avlpool
) {
95 uu_avl_pool_destroy(hdl
->libzfs_ns_avlpool
);
96 hdl
->libzfs_ns_avlpool
= NULL
;
101 * Loads the pool namespace, or re-loads it if the cache has changed.
104 namespace_reload(libzfs_handle_t
*hdl
)
109 zfs_cmd_t zc
= {"\0"};
112 if (hdl
->libzfs_ns_gen
== 0) {
114 * This is the first time we've accessed the configuration
115 * cache. Initialize the AVL tree and then fall through to the
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
));
124 if ((hdl
->libzfs_ns_avl
= uu_avl_create(hdl
->libzfs_ns_avlpool
,
125 NULL
, UU_DEFAULT
)) == NULL
)
126 return (no_memory(hdl
));
129 zcmd_alloc_dst_nvlist(hdl
, &zc
, 0);
132 zc
.zc_cookie
= hdl
->libzfs_ns_gen
;
133 if (zfs_ioctl(hdl
, ZFS_IOC_POOL_CONFIGS
, &zc
) != 0) {
137 * The namespace hasn't changed.
139 zcmd_free_nvlists(&zc
);
143 zcmd_expand_dst_nvlist(hdl
, &zc
);
147 zcmd_free_nvlists(&zc
);
148 return (zfs_standard_error(hdl
, errno
,
149 dgettext(TEXT_DOMAIN
, "failed to read "
150 "pool configuration")));
153 hdl
->libzfs_ns_gen
= zc
.zc_cookie
;
158 if (zcmd_read_dst_nvlist(hdl
, &zc
, &config
) != 0) {
159 zcmd_free_nvlists(&zc
);
163 zcmd_free_nvlists(&zc
);
166 * Clear out any existing configuration information.
169 while ((cn
= uu_avl_teardown(hdl
->libzfs_ns_avl
, &cookie
)) != NULL
) {
170 nvlist_free(cn
->cn_config
);
176 while ((elem
= nvlist_next_nvpair(config
, elem
)) != NULL
) {
178 uu_avl_index_t where
;
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) {
187 return (no_memory(hdl
));
189 verify(uu_avl_find(hdl
->libzfs_ns_avl
, cn
, NULL
, &where
)
192 uu_avl_insert(hdl
->libzfs_ns_avl
, cn
, where
);
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.
204 zpool_get_config(zpool_handle_t
*zhp
, nvlist_t
**oldconfig
)
207 *oldconfig
= zhp
->zpool_old_config
;
208 return (zhp
->zpool_config
);
212 * Retrieves a list of enabled features and their refcounts and caches it in
216 zpool_get_features(zpool_handle_t
*zhp
)
218 nvlist_t
*config
, *features
;
220 config
= zpool_get_config(zhp
, NULL
);
222 if (config
== NULL
|| !nvlist_exists(config
,
223 ZPOOL_CONFIG_FEATURE_STATS
)) {
225 boolean_t missing
= B_FALSE
;
227 error
= zpool_refresh_stats(zhp
, &missing
);
229 if (error
!= 0 || missing
)
232 config
= zpool_get_config(zhp
, NULL
);
235 if (nvlist_lookup_nvlist(config
, ZPOOL_CONFIG_FEATURE_STATS
,
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
249 zpool_refresh_stats(zpool_handle_t
*zhp
, boolean_t
*missing
)
251 zfs_cmd_t zc
= {"\0"};
254 libzfs_handle_t
*hdl
= zhp
->zpool_hdl
;
257 (void) strcpy(zc
.zc_name
, zhp
->zpool_name
);
259 if (zhp
->zpool_config_size
== 0)
260 zhp
->zpool_config_size
= 1 << 16;
262 zcmd_alloc_dst_nvlist(hdl
, &zc
, zhp
->zpool_config_size
);
265 if (zfs_ioctl(zhp
->zpool_hdl
, ZFS_IOC_POOL_STATS
,
268 * The real error is returned in the zc_cookie field.
270 error
= zc
.zc_cookie
;
275 zcmd_expand_dst_nvlist(hdl
, &zc
);
277 zcmd_free_nvlists(&zc
);
278 if (errno
== ENOENT
|| errno
== EINVAL
)
280 zhp
->zpool_state
= POOL_STATE_UNAVAIL
;
285 if (zcmd_read_dst_nvlist(hdl
, &zc
, &config
) != 0) {
286 zcmd_free_nvlists(&zc
);
290 zcmd_free_nvlists(&zc
);
292 zhp
->zpool_config_size
= zc
.zc_nvlist_dst_size
;
294 if (zhp
->zpool_config
!= NULL
) {
295 nvlist_free(zhp
->zpool_old_config
);
297 zhp
->zpool_old_config
= zhp
->zpool_config
;
300 zhp
->zpool_config
= config
;
302 zhp
->zpool_state
= POOL_STATE_UNAVAIL
;
304 zhp
->zpool_state
= POOL_STATE_ACTIVE
;
310 * The following environment variables are undocumented
311 * and should be used for testing purposes only:
313 * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists
314 * __ZFS_POOL_RESTRICT - iterate only over the pools it lists
316 * This function returns B_TRUE if the pool should be skipped
320 zpool_skip_pool(const char *poolname
)
322 static boolean_t initialized
= B_FALSE
;
323 static const char *exclude
= NULL
;
324 static const char *restricted
= NULL
;
326 const char *cur
, *end
;
328 int namelen
= strlen(poolname
);
331 initialized
= B_TRUE
;
332 exclude
= getenv("__ZFS_POOL_EXCLUDE");
333 restricted
= getenv("__ZFS_POOL_RESTRICT");
336 if (exclude
!= NULL
) {
339 end
= strchr(cur
, ' ');
340 len
= (NULL
== end
) ? strlen(cur
) : (end
- cur
);
341 if (len
== namelen
&& 0 == strncmp(cur
, poolname
, len
))
344 } while (NULL
!= end
);
347 if (NULL
== restricted
)
352 end
= strchr(cur
, ' ');
353 len
= (NULL
== end
) ? strlen(cur
) : (end
- cur
);
355 if (len
== namelen
&& 0 == strncmp(cur
, poolname
, len
)) {
360 } while (NULL
!= end
);
366 * Iterate over all pools in the system.
369 zpool_iter(libzfs_handle_t
*hdl
, zpool_iter_f func
, void *data
)
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.
381 if (!hdl
->libzfs_pool_iter
&& namespace_reload(hdl
) != 0)
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
)) {
388 if (zpool_skip_pool(cn
->cn_name
))
391 if (zpool_open_silent(hdl
, cn
->cn_name
, &zhp
) != 0) {
392 hdl
->libzfs_pool_iter
--;
399 if ((ret
= func(zhp
, data
)) != 0) {
400 hdl
->libzfs_pool_iter
--;
404 hdl
->libzfs_pool_iter
--;
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.
414 zfs_iter_root(libzfs_handle_t
*hdl
, zfs_iter_f func
, void *data
)
420 if (namespace_reload(hdl
) != 0)
423 for (cn
= uu_avl_first(hdl
->libzfs_ns_avl
); cn
!= NULL
;
424 cn
= uu_avl_next(hdl
->libzfs_ns_avl
, cn
)) {
426 if (zpool_skip_pool(cn
->cn_name
))
429 if ((zhp
= make_dataset_handle(hdl
, cn
->cn_name
)) == NULL
)
432 if ((ret
= func(zhp
, data
)) != 0)