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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The pool configuration repository is stored in /etc/zfs/zpool.cache as a 31 * single packed nvlist. While it would be nice to just read in this 32 * file from userland, this wouldn't work from a local zone. So we have to have 33 * a zpool ioctl to return the complete configuration for all pools. In the 34 * global zone, this will be identical to reading the file and unpacking it in 35 * userland. 36 */ 37 38 #include <errno.h> 39 #include <sys/stat.h> 40 #include <fcntl.h> 41 #include <stddef.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <libintl.h> 45 #include <libuutil.h> 46 47 #include "libzfs_impl.h" 48 49 static uu_avl_t *namespace_avl; 50 static uint64_t namespace_generation; 51 52 typedef struct config_node { 53 char *cn_name; 54 nvlist_t *cn_config; 55 uu_avl_node_t cn_avl; 56 } config_node_t; 57 58 /* ARGSUSED */ 59 static int 60 config_node_compare(const void *a, const void *b, void *unused) 61 { 62 int ret; 63 64 const config_node_t *ca = (config_node_t *)a; 65 const config_node_t *cb = (config_node_t *)b; 66 67 ret = strcmp(ca->cn_name, cb->cn_name); 68 69 if (ret < 0) 70 return (-1); 71 else if (ret > 0) 72 return (1); 73 else 74 return (0); 75 } 76 77 /* 78 * Loads the pool namespace, or re-loads it if the cache has changed. 79 */ 80 static void 81 namespace_reload() 82 { 83 nvlist_t *config; 84 config_node_t *cn; 85 nvpair_t *elem; 86 zfs_cmd_t zc = { 0 }; 87 uu_avl_walk_t *walk; 88 89 if (namespace_generation == 0) { 90 /* 91 * This is the first time we've accessed the configuration 92 * cache. Initialize the AVL tree and then fall through to the 93 * common code. 94 */ 95 uu_avl_pool_t *pool; 96 97 if ((pool = uu_avl_pool_create("config_pool", 98 sizeof (config_node_t), 99 offsetof(config_node_t, cn_avl), 100 config_node_compare, UU_DEFAULT)) == NULL) 101 no_memory(); 102 103 if ((namespace_avl = uu_avl_create(pool, NULL, 104 UU_DEFAULT)) == NULL) 105 no_memory(); 106 } 107 108 /* 109 * Issue the ZFS_IOC_POOL_CONFIGS ioctl. 110 * This can fail for one of two reasons: 111 * 112 * EEXIST The generation counts match, nothing to do. 113 * ENOMEM The zc_config_dst buffer isn't large enough to 114 * hold the config; zc_config_dst_size will have 115 * been modified to tell us how much to allocate. 116 */ 117 zc.zc_config_dst_size = 1024; 118 zc.zc_config_dst = (uint64_t)(uintptr_t) 119 zfs_malloc(zc.zc_config_dst_size); 120 for (;;) { 121 zc.zc_cookie = namespace_generation; 122 if (ioctl(zfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 123 switch (errno) { 124 case EEXIST: 125 /* 126 * The namespace hasn't changed. 127 */ 128 free((void *)(uintptr_t)zc.zc_config_dst); 129 return; 130 131 case ENOMEM: 132 free((void *)(uintptr_t)zc.zc_config_dst); 133 zc.zc_config_dst = (uint64_t)(uintptr_t) 134 zfs_malloc(zc.zc_config_dst_size); 135 break; 136 137 default: 138 zfs_baderror(errno); 139 } 140 } else { 141 namespace_generation = zc.zc_cookie; 142 break; 143 } 144 } 145 146 verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, 147 zc.zc_config_dst_size, &config, 0) == 0); 148 149 free((void *)(uintptr_t)zc.zc_config_dst); 150 151 /* 152 * Clear out any existing configuration information. 153 */ 154 if ((walk = uu_avl_walk_start(namespace_avl, UU_WALK_ROBUST)) == NULL) 155 no_memory(); 156 157 while ((cn = uu_avl_walk_next(walk)) != NULL) { 158 uu_avl_remove(namespace_avl, cn); 159 nvlist_free(cn->cn_config); 160 free(cn->cn_name); 161 free(cn); 162 } 163 164 elem = NULL; 165 while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 166 nvlist_t *child; 167 uu_avl_index_t where; 168 169 cn = zfs_malloc(sizeof (config_node_t)); 170 cn->cn_name = zfs_strdup(nvpair_name(elem)); 171 172 verify(nvpair_value_nvlist(elem, &child) == 0); 173 verify(nvlist_dup(child, &cn->cn_config, 0) == 0); 174 verify(uu_avl_find(namespace_avl, cn, NULL, &where) == NULL); 175 176 uu_avl_insert(namespace_avl, cn, where); 177 } 178 179 nvlist_free(config); 180 } 181 182 /* 183 * Retrive the configuration for the given pool. The configuration is a nvlist 184 * describing the vdevs, as well as the statistics associated with each one. 185 */ 186 nvlist_t * 187 zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 188 { 189 if (oldconfig) 190 *oldconfig = zhp->zpool_old_config; 191 return (zhp->zpool_config); 192 } 193 194 /* 195 * Refresh the vdev statistics associated with the given pool. This is used in 196 * iostat to show configuration changes and determine the delta from the last 197 * time the function was called. This function can fail, in case the pool has 198 * been destroyed. 199 */ 200 int 201 zpool_refresh_stats(zpool_handle_t *zhp) 202 { 203 zfs_cmd_t zc = { 0 }; 204 int error; 205 nvlist_t *config; 206 207 (void) strcpy(zc.zc_name, zhp->zpool_name); 208 209 if (zhp->zpool_config_size == 0) 210 zhp->zpool_config_size = 1 << 16; 211 212 zc.zc_config_dst_size = zhp->zpool_config_size; 213 zc.zc_config_dst = (uint64_t)(uintptr_t) 214 zfs_malloc(zc.zc_config_dst_size); 215 216 while ((error = ioctl(zfs_fd, ZFS_IOC_POOL_STATS, &zc)) != 0) { 217 error = errno; 218 219 if (error == ENXIO) { 220 /* 221 * We can't open one or more top-level vdevs, 222 * but we have the config. 223 */ 224 break; 225 } 226 227 free((void *)(uintptr_t)zc.zc_config_dst); 228 229 if (error == ENOENT || error == EINVAL) { 230 /* 231 * There's no such pool (ENOENT) 232 * or the config is bogus (EINVAL). 233 */ 234 return (error); 235 } 236 237 if (error != ENOMEM) 238 zfs_baderror(error); 239 240 zc.zc_config_dst = 241 (uint64_t)(uintptr_t)zfs_malloc(zc.zc_config_dst_size); 242 } 243 244 verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, 245 zc.zc_config_dst_size, &config, 0) == 0); 246 247 zhp->zpool_config_size = zc.zc_config_dst_size; 248 free((void *)(uintptr_t)zc.zc_config_dst); 249 250 set_pool_health(config); 251 252 if (zhp->zpool_config != NULL) { 253 uint64_t oldtxg, newtxg; 254 255 verify(nvlist_lookup_uint64(zhp->zpool_config, 256 ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 257 verify(nvlist_lookup_uint64(config, 258 ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 259 260 if (zhp->zpool_old_config != NULL) 261 nvlist_free(zhp->zpool_old_config); 262 263 if (oldtxg != newtxg) { 264 nvlist_free(zhp->zpool_config); 265 zhp->zpool_old_config = NULL; 266 } else { 267 zhp->zpool_old_config = zhp->zpool_config; 268 } 269 } 270 271 zhp->zpool_config = config; 272 273 return (error); 274 } 275 276 /* 277 * Iterate over all pools in the system. 278 */ 279 int 280 zpool_iter(zpool_iter_f func, void *data) 281 { 282 config_node_t *cn; 283 zpool_handle_t *zhp; 284 int ret; 285 286 namespace_reload(); 287 288 for (cn = uu_avl_first(namespace_avl); cn != NULL; 289 cn = uu_avl_next(namespace_avl, cn)) { 290 291 if ((zhp = zpool_open_silent(cn->cn_name)) == NULL) 292 continue; 293 294 if ((ret = func(zhp, data)) != 0) 295 return (ret); 296 } 297 298 return (0); 299 } 300 301 /* 302 * Iterate over root datasets, calling the given function for each. The zfs 303 * handle passed each time must be explicitly closed by the callback. 304 */ 305 int 306 zfs_iter_root(zfs_iter_f func, void *data) 307 { 308 config_node_t *cn; 309 zfs_handle_t *zhp; 310 int ret; 311 312 namespace_reload(); 313 314 for (cn = uu_avl_first(namespace_avl); cn != NULL; 315 cn = uu_avl_next(namespace_avl, cn)) { 316 317 if ((zhp = make_dataset_handle(cn->cn_name)) == NULL) 318 continue; 319 320 if ((ret = func(zhp, data)) != 0) 321 return (ret); 322 } 323 324 return (0); 325 } 326