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