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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * The pool configuration repository is stored in /etc/zfs/zpool.cache as a 28 * single packed nvlist. While it would be nice to just read in this 29 * file from userland, this wouldn't work from a local zone. So we have to have 30 * a zpool ioctl to return the complete configuration for all pools. In the 31 * global zone, this will be identical to reading the file and unpacking it in 32 * userland. 33 */ 34 35 #include <errno.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <stddef.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <libintl.h> 42 #include <libuutil.h> 43 44 #include "libzfs_impl.h" 45 46 typedef struct config_node { 47 char *cn_name; 48 nvlist_t *cn_config; 49 uu_avl_node_t cn_avl; 50 } config_node_t; 51 52 /* ARGSUSED */ 53 static int 54 config_node_compare(const void *a, const void *b, void *unused) 55 { 56 int ret; 57 58 const config_node_t *ca = (config_node_t *)a; 59 const config_node_t *cb = (config_node_t *)b; 60 61 ret = strcmp(ca->cn_name, cb->cn_name); 62 63 if (ret < 0) 64 return (-1); 65 else if (ret > 0) 66 return (1); 67 else 68 return (0); 69 } 70 71 void 72 namespace_clear(libzfs_handle_t *hdl) 73 { 74 if (hdl->libzfs_ns_avl) { 75 config_node_t *cn; 76 void *cookie = NULL; 77 78 while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, 79 &cookie)) != NULL) { 80 nvlist_free(cn->cn_config); 81 free(cn->cn_name); 82 free(cn); 83 } 84 85 uu_avl_destroy(hdl->libzfs_ns_avl); 86 hdl->libzfs_ns_avl = NULL; 87 } 88 89 if (hdl->libzfs_ns_avlpool) { 90 uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); 91 hdl->libzfs_ns_avlpool = NULL; 92 } 93 } 94 95 /* 96 * Loads the pool namespace, or re-loads it if the cache has changed. 97 */ 98 static int 99 namespace_reload(libzfs_handle_t *hdl) 100 { 101 nvlist_t *config; 102 config_node_t *cn; 103 nvpair_t *elem; 104 zfs_cmd_t zc = { 0 }; 105 void *cookie; 106 107 if (hdl->libzfs_ns_gen == 0) { 108 /* 109 * This is the first time we've accessed the configuration 110 * cache. Initialize the AVL tree and then fall through to the 111 * common code. 112 */ 113 if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", 114 sizeof (config_node_t), 115 offsetof(config_node_t, cn_avl), 116 config_node_compare, UU_DEFAULT)) == NULL) 117 return (no_memory(hdl)); 118 119 if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, 120 NULL, UU_DEFAULT)) == NULL) 121 return (no_memory(hdl)); 122 } 123 124 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 125 return (-1); 126 127 for (;;) { 128 zc.zc_cookie = hdl->libzfs_ns_gen; 129 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { 130 switch (errno) { 131 case EEXIST: 132 /* 133 * The namespace hasn't changed. 134 */ 135 zcmd_free_nvlists(&zc); 136 return (0); 137 138 case ENOMEM: 139 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 140 zcmd_free_nvlists(&zc); 141 return (-1); 142 } 143 break; 144 145 default: 146 zcmd_free_nvlists(&zc); 147 return (zfs_standard_error(hdl, errno, 148 dgettext(TEXT_DOMAIN, "failed to read " 149 "pool configuration"))); 150 } 151 } else { 152 hdl->libzfs_ns_gen = zc.zc_cookie; 153 break; 154 } 155 } 156 157 if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 158 zcmd_free_nvlists(&zc); 159 return (-1); 160 } 161 162 zcmd_free_nvlists(&zc); 163 164 /* 165 * Clear out any existing configuration information. 166 */ 167 cookie = NULL; 168 while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) { 169 nvlist_free(cn->cn_config); 170 free(cn->cn_name); 171 free(cn); 172 } 173 174 elem = NULL; 175 while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { 176 nvlist_t *child; 177 uu_avl_index_t where; 178 179 if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { 180 nvlist_free(config); 181 return (-1); 182 } 183 184 if ((cn->cn_name = zfs_strdup(hdl, 185 nvpair_name(elem))) == NULL) { 186 free(cn); 187 nvlist_free(config); 188 return (-1); 189 } 190 191 verify(nvpair_value_nvlist(elem, &child) == 0); 192 if (nvlist_dup(child, &cn->cn_config, 0) != 0) { 193 free(cn->cn_name); 194 free(cn); 195 nvlist_free(config); 196 return (no_memory(hdl)); 197 } 198 verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) 199 == NULL); 200 201 uu_avl_insert(hdl->libzfs_ns_avl, cn, where); 202 } 203 204 nvlist_free(config); 205 return (0); 206 } 207 208 /* 209 * Retrieve the configuration for the given pool. The configuration is a nvlist 210 * describing the vdevs, as well as the statistics associated with each one. 211 */ 212 nvlist_t * 213 zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) 214 { 215 if (oldconfig) 216 *oldconfig = zhp->zpool_old_config; 217 return (zhp->zpool_config); 218 } 219 220 /* 221 * Refresh the vdev statistics associated with the given pool. This is used in 222 * iostat to show configuration changes and determine the delta from the last 223 * time the function was called. This function can fail, in case the pool has 224 * been destroyed. 225 */ 226 int 227 zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) 228 { 229 zfs_cmd_t zc = { 0 }; 230 int error; 231 nvlist_t *config; 232 libzfs_handle_t *hdl = zhp->zpool_hdl; 233 234 *missing = B_FALSE; 235 (void) strcpy(zc.zc_name, zhp->zpool_name); 236 237 if (zhp->zpool_config_size == 0) 238 zhp->zpool_config_size = 1 << 16; 239 240 if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0) 241 return (-1); 242 243 for (;;) { 244 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, 245 &zc) == 0) { 246 /* 247 * The real error is returned in the zc_cookie field. 248 */ 249 error = zc.zc_cookie; 250 break; 251 } 252 253 if (errno == ENOMEM) { 254 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 255 zcmd_free_nvlists(&zc); 256 return (-1); 257 } 258 } else { 259 zcmd_free_nvlists(&zc); 260 if (errno == ENOENT || errno == EINVAL) 261 *missing = B_TRUE; 262 zhp->zpool_state = POOL_STATE_UNAVAIL; 263 return (0); 264 } 265 } 266 267 if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) { 268 zcmd_free_nvlists(&zc); 269 return (-1); 270 } 271 272 zcmd_free_nvlists(&zc); 273 274 zhp->zpool_config_size = zc.zc_nvlist_dst_size; 275 276 if (zhp->zpool_config != NULL) { 277 uint64_t oldtxg, newtxg; 278 279 verify(nvlist_lookup_uint64(zhp->zpool_config, 280 ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); 281 verify(nvlist_lookup_uint64(config, 282 ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); 283 284 if (zhp->zpool_old_config != NULL) 285 nvlist_free(zhp->zpool_old_config); 286 287 if (oldtxg != newtxg) { 288 nvlist_free(zhp->zpool_config); 289 zhp->zpool_old_config = NULL; 290 } else { 291 zhp->zpool_old_config = zhp->zpool_config; 292 } 293 } 294 295 zhp->zpool_config = config; 296 if (error) 297 zhp->zpool_state = POOL_STATE_UNAVAIL; 298 else 299 zhp->zpool_state = POOL_STATE_ACTIVE; 300 301 return (0); 302 } 303 304 /* 305 * Iterate over all pools in the system. 306 */ 307 int 308 zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) 309 { 310 config_node_t *cn; 311 zpool_handle_t *zhp; 312 int ret; 313 314 /* 315 * If someone makes a recursive call to zpool_iter(), we want to avoid 316 * refreshing the namespace because that will invalidate the parent 317 * context. We allow recursive calls, but simply re-use the same 318 * namespace AVL tree. 319 */ 320 if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0) 321 return (-1); 322 323 hdl->libzfs_pool_iter++; 324 for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 325 cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 326 327 if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) { 328 hdl->libzfs_pool_iter--; 329 return (-1); 330 } 331 332 if (zhp == NULL) 333 continue; 334 335 if ((ret = func(zhp, data)) != 0) { 336 hdl->libzfs_pool_iter--; 337 return (ret); 338 } 339 } 340 hdl->libzfs_pool_iter--; 341 342 return (0); 343 } 344 345 /* 346 * Iterate over root datasets, calling the given function for each. The zfs 347 * handle passed each time must be explicitly closed by the callback. 348 */ 349 int 350 zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) 351 { 352 config_node_t *cn; 353 zfs_handle_t *zhp; 354 int ret; 355 356 if (namespace_reload(hdl) != 0) 357 return (-1); 358 359 for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 360 cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { 361 362 if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) 363 continue; 364 365 if ((ret = func(zhp, data)) != 0) 366 return (ret); 367 } 368 369 return (0); 370 } 371