xref: /illumos-gate/usr/src/cmd/zpool/zpool_iter.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
1*fa9e4066Sahrens /*
2*fa9e4066Sahrens  * CDDL HEADER START
3*fa9e4066Sahrens  *
4*fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5*fa9e4066Sahrens  * Common Development and Distribution License, Version 1.0 only
6*fa9e4066Sahrens  * (the "License").  You may not use this file except in compliance
7*fa9e4066Sahrens  * with the License.
8*fa9e4066Sahrens  *
9*fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
11*fa9e4066Sahrens  * See the License for the specific language governing permissions
12*fa9e4066Sahrens  * and limitations under the License.
13*fa9e4066Sahrens  *
14*fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15*fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17*fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18*fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19*fa9e4066Sahrens  *
20*fa9e4066Sahrens  * CDDL HEADER END
21*fa9e4066Sahrens  */
22*fa9e4066Sahrens /*
23*fa9e4066Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*fa9e4066Sahrens  * Use is subject to license terms.
25*fa9e4066Sahrens  */
26*fa9e4066Sahrens 
27*fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*fa9e4066Sahrens 
29*fa9e4066Sahrens #include <libintl.h>
30*fa9e4066Sahrens #include <libuutil.h>
31*fa9e4066Sahrens #include <stddef.h>
32*fa9e4066Sahrens #include <stdio.h>
33*fa9e4066Sahrens #include <stdlib.h>
34*fa9e4066Sahrens #include <strings.h>
35*fa9e4066Sahrens 
36*fa9e4066Sahrens #include <libzfs.h>
37*fa9e4066Sahrens 
38*fa9e4066Sahrens #include "zpool_util.h"
39*fa9e4066Sahrens 
40*fa9e4066Sahrens /*
41*fa9e4066Sahrens  * Private interface for iterating over pools specified on the command line.
42*fa9e4066Sahrens  * Most consumers will call for_each_pool, but in order to support iostat, we
43*fa9e4066Sahrens  * allow fined grained control through the zpool_list_t interface.
44*fa9e4066Sahrens  */
45*fa9e4066Sahrens 
46*fa9e4066Sahrens typedef struct zpool_node {
47*fa9e4066Sahrens 	zpool_handle_t	*zn_handle;
48*fa9e4066Sahrens 	uu_avl_node_t	zn_avlnode;
49*fa9e4066Sahrens 	int		zn_mark;
50*fa9e4066Sahrens } zpool_node_t;
51*fa9e4066Sahrens 
52*fa9e4066Sahrens struct zpool_list {
53*fa9e4066Sahrens 	int		zl_findall;
54*fa9e4066Sahrens 	uu_avl_t	*zl_avl;
55*fa9e4066Sahrens 	uu_avl_pool_t	*zl_pool;
56*fa9e4066Sahrens };
57*fa9e4066Sahrens 
58*fa9e4066Sahrens /* ARGSUSED */
59*fa9e4066Sahrens static int
60*fa9e4066Sahrens zpool_compare(const void *larg, const void *rarg, void *unused)
61*fa9e4066Sahrens {
62*fa9e4066Sahrens 	zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
63*fa9e4066Sahrens 	zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
64*fa9e4066Sahrens 	const char *lname = zpool_get_name(l);
65*fa9e4066Sahrens 	const char *rname = zpool_get_name(r);
66*fa9e4066Sahrens 
67*fa9e4066Sahrens 	return (strcmp(lname, rname));
68*fa9e4066Sahrens }
69*fa9e4066Sahrens 
70*fa9e4066Sahrens /*
71*fa9e4066Sahrens  * Callback function for pool_list_get().  Adds the given pool to the AVL tree
72*fa9e4066Sahrens  * of known pools.
73*fa9e4066Sahrens  */
74*fa9e4066Sahrens static int
75*fa9e4066Sahrens add_pool(zpool_handle_t *zhp, void *data)
76*fa9e4066Sahrens {
77*fa9e4066Sahrens 	zpool_list_t *zlp = data;
78*fa9e4066Sahrens 	zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
79*fa9e4066Sahrens 	uu_avl_index_t idx;
80*fa9e4066Sahrens 
81*fa9e4066Sahrens 	node->zn_handle = zhp;
82*fa9e4066Sahrens 	uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
83*fa9e4066Sahrens 	if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
84*fa9e4066Sahrens 		uu_avl_insert(zlp->zl_avl, node, idx);
85*fa9e4066Sahrens 	} else {
86*fa9e4066Sahrens 		zpool_close(zhp);
87*fa9e4066Sahrens 		free(node);
88*fa9e4066Sahrens 	}
89*fa9e4066Sahrens 
90*fa9e4066Sahrens 	return (0);
91*fa9e4066Sahrens }
92*fa9e4066Sahrens 
93*fa9e4066Sahrens /*
94*fa9e4066Sahrens  * Create a list of pools based on the given arguments.  If we're given no
95*fa9e4066Sahrens  * arguments, then iterate over all pools in the system and add them to the AVL
96*fa9e4066Sahrens  * tree.  Otherwise, add only those pool explicitly specified on the command
97*fa9e4066Sahrens  * line.
98*fa9e4066Sahrens  */
99*fa9e4066Sahrens zpool_list_t *
100*fa9e4066Sahrens pool_list_get(int argc, char **argv, int *err)
101*fa9e4066Sahrens {
102*fa9e4066Sahrens 	zpool_list_t *zlp;
103*fa9e4066Sahrens 
104*fa9e4066Sahrens 	zlp = safe_malloc(sizeof (zpool_list_t));
105*fa9e4066Sahrens 
106*fa9e4066Sahrens 	zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
107*fa9e4066Sahrens 	    offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
108*fa9e4066Sahrens 
109*fa9e4066Sahrens 	if (zlp->zl_pool == NULL)
110*fa9e4066Sahrens 		no_memory();
111*fa9e4066Sahrens 
112*fa9e4066Sahrens 	if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
113*fa9e4066Sahrens 	    UU_DEFAULT)) == NULL)
114*fa9e4066Sahrens 		no_memory();
115*fa9e4066Sahrens 
116*fa9e4066Sahrens 	if (argc == 0) {
117*fa9e4066Sahrens 		(void) zpool_iter(add_pool, zlp);
118*fa9e4066Sahrens 		zlp->zl_findall = TRUE;
119*fa9e4066Sahrens 	} else {
120*fa9e4066Sahrens 		int i;
121*fa9e4066Sahrens 
122*fa9e4066Sahrens 		for (i = 0; i < argc; i++) {
123*fa9e4066Sahrens 			zpool_handle_t *zhp;
124*fa9e4066Sahrens 
125*fa9e4066Sahrens 			if ((zhp = zpool_open_canfail(argv[i])) != NULL)
126*fa9e4066Sahrens 				(void) add_pool(zhp, zlp);
127*fa9e4066Sahrens 			else
128*fa9e4066Sahrens 				*err = TRUE;
129*fa9e4066Sahrens 		}
130*fa9e4066Sahrens 	}
131*fa9e4066Sahrens 
132*fa9e4066Sahrens 	return (zlp);
133*fa9e4066Sahrens }
134*fa9e4066Sahrens 
135*fa9e4066Sahrens /*
136*fa9e4066Sahrens  * Search for any new pools, adding them to the list.  We only add pools when no
137*fa9e4066Sahrens  * options were given on the command line.  Otherwise, we keep the list fixed as
138*fa9e4066Sahrens  * those that were explicitly specified.
139*fa9e4066Sahrens  */
140*fa9e4066Sahrens void
141*fa9e4066Sahrens pool_list_update(zpool_list_t *zlp)
142*fa9e4066Sahrens {
143*fa9e4066Sahrens 	if (zlp->zl_findall)
144*fa9e4066Sahrens 		(void) zpool_iter(add_pool, zlp);
145*fa9e4066Sahrens }
146*fa9e4066Sahrens 
147*fa9e4066Sahrens /*
148*fa9e4066Sahrens  * Iterate over all pools in the list, executing the callback for each
149*fa9e4066Sahrens  */
150*fa9e4066Sahrens int
151*fa9e4066Sahrens pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
152*fa9e4066Sahrens     void *data)
153*fa9e4066Sahrens {
154*fa9e4066Sahrens 	zpool_node_t *node, *next_node;
155*fa9e4066Sahrens 	int ret = 0;
156*fa9e4066Sahrens 
157*fa9e4066Sahrens 	for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
158*fa9e4066Sahrens 		next_node = uu_avl_next(zlp->zl_avl, node);
159*fa9e4066Sahrens 		if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
160*fa9e4066Sahrens 		    unavail)
161*fa9e4066Sahrens 			ret |= func(node->zn_handle, data);
162*fa9e4066Sahrens 	}
163*fa9e4066Sahrens 
164*fa9e4066Sahrens 	return (ret);
165*fa9e4066Sahrens }
166*fa9e4066Sahrens 
167*fa9e4066Sahrens /*
168*fa9e4066Sahrens  * Remove the given pool from the list.  When running iostat, we want to remove
169*fa9e4066Sahrens  * those pools that no longer exist.
170*fa9e4066Sahrens  */
171*fa9e4066Sahrens void
172*fa9e4066Sahrens pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
173*fa9e4066Sahrens {
174*fa9e4066Sahrens 	zpool_node_t search, *node;
175*fa9e4066Sahrens 
176*fa9e4066Sahrens 	search.zn_handle = zhp;
177*fa9e4066Sahrens 	if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
178*fa9e4066Sahrens 		uu_avl_remove(zlp->zl_avl, node);
179*fa9e4066Sahrens 		zpool_close(node->zn_handle);
180*fa9e4066Sahrens 		free(node);
181*fa9e4066Sahrens 	}
182*fa9e4066Sahrens }
183*fa9e4066Sahrens 
184*fa9e4066Sahrens /*
185*fa9e4066Sahrens  * Free all the handles associated with this list.
186*fa9e4066Sahrens  */
187*fa9e4066Sahrens void
188*fa9e4066Sahrens pool_list_free(zpool_list_t *zlp)
189*fa9e4066Sahrens {
190*fa9e4066Sahrens 	uu_avl_walk_t *walk;
191*fa9e4066Sahrens 	zpool_node_t *node;
192*fa9e4066Sahrens 
193*fa9e4066Sahrens 	if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
194*fa9e4066Sahrens 		(void) fprintf(stderr,
195*fa9e4066Sahrens 		    gettext("internal error: out of memory"));
196*fa9e4066Sahrens 		exit(1);
197*fa9e4066Sahrens 	}
198*fa9e4066Sahrens 
199*fa9e4066Sahrens 	while ((node = uu_avl_walk_next(walk)) != NULL) {
200*fa9e4066Sahrens 		uu_avl_remove(zlp->zl_avl, node);
201*fa9e4066Sahrens 		zpool_close(node->zn_handle);
202*fa9e4066Sahrens 		free(node);
203*fa9e4066Sahrens 	}
204*fa9e4066Sahrens 
205*fa9e4066Sahrens 	uu_avl_walk_end(walk);
206*fa9e4066Sahrens 	uu_avl_destroy(zlp->zl_avl);
207*fa9e4066Sahrens 	uu_avl_pool_destroy(zlp->zl_pool);
208*fa9e4066Sahrens 
209*fa9e4066Sahrens 	free(zlp);
210*fa9e4066Sahrens }
211*fa9e4066Sahrens 
212*fa9e4066Sahrens /*
213*fa9e4066Sahrens  * Returns the number of elements in the pool list.
214*fa9e4066Sahrens  */
215*fa9e4066Sahrens int
216*fa9e4066Sahrens pool_list_count(zpool_list_t *zlp)
217*fa9e4066Sahrens {
218*fa9e4066Sahrens 	return (uu_avl_numnodes(zlp->zl_avl));
219*fa9e4066Sahrens }
220*fa9e4066Sahrens 
221*fa9e4066Sahrens /*
222*fa9e4066Sahrens  * High level function which iterates over all pools given on the command line,
223*fa9e4066Sahrens  * using the pool_list_* interfaces.
224*fa9e4066Sahrens  */
225*fa9e4066Sahrens int
226*fa9e4066Sahrens for_each_pool(int argc, char **argv, int unavail, zpool_iter_f func,
227*fa9e4066Sahrens     void *data)
228*fa9e4066Sahrens {
229*fa9e4066Sahrens 	zpool_list_t *list;
230*fa9e4066Sahrens 	int ret = 0;
231*fa9e4066Sahrens 
232*fa9e4066Sahrens 	if ((list = pool_list_get(argc, argv, &ret)) == NULL)
233*fa9e4066Sahrens 		return (1);
234*fa9e4066Sahrens 
235*fa9e4066Sahrens 	if (pool_list_iter(list, unavail, func, data) != 0)
236*fa9e4066Sahrens 		ret = 1;
237*fa9e4066Sahrens 
238*fa9e4066Sahrens 	pool_list_free(list);
239*fa9e4066Sahrens 
240*fa9e4066Sahrens 	return (ret);
241*fa9e4066Sahrens }
242