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