zpool_iter.c revision 297119
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 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
27 */
28
29#include <solaris.h>
30#include <libintl.h>
31#include <libuutil.h>
32#include <stddef.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <strings.h>
36
37#include <libzfs.h>
38
39#include "zpool_util.h"
40
41/*
42 * Private interface for iterating over pools specified on the command line.
43 * Most consumers will call for_each_pool, but in order to support iostat, we
44 * allow fined grained control through the zpool_list_t interface.
45 */
46
47typedef struct zpool_node {
48	zpool_handle_t	*zn_handle;
49	uu_avl_node_t	zn_avlnode;
50	int		zn_mark;
51} zpool_node_t;
52
53struct zpool_list {
54	boolean_t	zl_findall;
55	uu_avl_t	*zl_avl;
56	uu_avl_pool_t	*zl_pool;
57	zprop_list_t	**zl_proplist;
58};
59
60/* ARGSUSED */
61static int
62zpool_compare(const void *larg, const void *rarg, void *unused)
63{
64	zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
65	zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
66	const char *lname = zpool_get_name(l);
67	const char *rname = zpool_get_name(r);
68
69	return (strcmp(lname, rname));
70}
71
72/*
73 * Callback function for pool_list_get().  Adds the given pool to the AVL tree
74 * of known pools.
75 */
76static int
77add_pool(zpool_handle_t *zhp, void *data)
78{
79	zpool_list_t *zlp = data;
80	zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
81	uu_avl_index_t idx;
82
83	node->zn_handle = zhp;
84	uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
85	if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
86		if (zlp->zl_proplist &&
87		    zpool_expand_proplist(zhp, zlp->zl_proplist) != 0) {
88			zpool_close(zhp);
89			free(node);
90			return (-1);
91		}
92		uu_avl_insert(zlp->zl_avl, node, idx);
93	} else {
94		zpool_close(zhp);
95		free(node);
96		return (-1);
97	}
98
99	return (0);
100}
101
102/*
103 * Create a list of pools based on the given arguments.  If we're given no
104 * arguments, then iterate over all pools in the system and add them to the AVL
105 * tree.  Otherwise, add only those pool explicitly specified on the command
106 * line.
107 */
108zpool_list_t *
109pool_list_get(int argc, char **argv, zprop_list_t **proplist, int *err)
110{
111	zpool_list_t *zlp;
112
113	zlp = safe_malloc(sizeof (zpool_list_t));
114
115	zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
116	    offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
117
118	if (zlp->zl_pool == NULL)
119		zpool_no_memory();
120
121	if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
122	    UU_DEFAULT)) == NULL)
123		zpool_no_memory();
124
125	zlp->zl_proplist = proplist;
126
127	if (argc == 0) {
128		(void) zpool_iter(g_zfs, add_pool, zlp);
129		zlp->zl_findall = B_TRUE;
130	} else {
131		int i;
132
133		for (i = 0; i < argc; i++) {
134			zpool_handle_t *zhp;
135
136			if ((zhp = zpool_open_canfail(g_zfs, argv[i])) !=
137			    NULL) {
138				if (add_pool(zhp, zlp) != 0)
139					*err = B_TRUE;
140			} else {
141				*err = B_TRUE;
142			}
143		}
144	}
145
146	return (zlp);
147}
148
149/*
150 * Search for any new pools, adding them to the list.  We only add pools when no
151 * options were given on the command line.  Otherwise, we keep the list fixed as
152 * those that were explicitly specified.
153 */
154void
155pool_list_update(zpool_list_t *zlp)
156{
157	if (zlp->zl_findall)
158		(void) zpool_iter(g_zfs, add_pool, zlp);
159}
160
161/*
162 * Iterate over all pools in the list, executing the callback for each
163 */
164int
165pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
166    void *data)
167{
168	zpool_node_t *node, *next_node;
169	int ret = 0;
170
171	for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
172		next_node = uu_avl_next(zlp->zl_avl, node);
173		if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
174		    unavail)
175			ret |= func(node->zn_handle, data);
176	}
177
178	return (ret);
179}
180
181/*
182 * Remove the given pool from the list.  When running iostat, we want to remove
183 * those pools that no longer exist.
184 */
185void
186pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
187{
188	zpool_node_t search, *node;
189
190	search.zn_handle = zhp;
191	if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
192		uu_avl_remove(zlp->zl_avl, node);
193		zpool_close(node->zn_handle);
194		free(node);
195	}
196}
197
198/*
199 * Free all the handles associated with this list.
200 */
201void
202pool_list_free(zpool_list_t *zlp)
203{
204	uu_avl_walk_t *walk;
205	zpool_node_t *node;
206
207	if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
208		(void) fprintf(stderr,
209		    gettext("internal error: out of memory"));
210		exit(1);
211	}
212
213	while ((node = uu_avl_walk_next(walk)) != NULL) {
214		uu_avl_remove(zlp->zl_avl, node);
215		zpool_close(node->zn_handle);
216		free(node);
217	}
218
219	uu_avl_walk_end(walk);
220	uu_avl_destroy(zlp->zl_avl);
221	uu_avl_pool_destroy(zlp->zl_pool);
222
223	free(zlp);
224}
225
226/*
227 * Returns the number of elements in the pool list.
228 */
229int
230pool_list_count(zpool_list_t *zlp)
231{
232	return (uu_avl_numnodes(zlp->zl_avl));
233}
234
235/*
236 * High level function which iterates over all pools given on the command line,
237 * using the pool_list_* interfaces.
238 */
239int
240for_each_pool(int argc, char **argv, boolean_t unavail,
241    zprop_list_t **proplist, zpool_iter_f func, void *data)
242{
243	zpool_list_t *list;
244	int ret = 0;
245
246	if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
247		return (1);
248
249	if (pool_list_iter(list, unavail, func, data) != 0)
250		ret = 1;
251
252	pool_list_free(list);
253
254	return (ret);
255}
256