usr/src/lib/libzfs/common/libzfs_config.c
changeset 2082 76b439ec3ac1
parent 1544 938876158511
child 2142 f6e0487aa9a3
equal deleted inserted replaced
2081:34f1e4f08632 2082:76b439ec3ac1
    43 #include <libintl.h>
    43 #include <libintl.h>
    44 #include <libuutil.h>
    44 #include <libuutil.h>
    45 
    45 
    46 #include "libzfs_impl.h"
    46 #include "libzfs_impl.h"
    47 
    47 
    48 static uu_avl_t *namespace_avl;
       
    49 static uint64_t namespace_generation;
       
    50 
       
    51 typedef struct config_node {
    48 typedef struct config_node {
    52 	char		*cn_name;
    49 	char		*cn_name;
    53 	nvlist_t	*cn_config;
    50 	nvlist_t	*cn_config;
    54 	uu_avl_node_t	cn_avl;
    51 	uu_avl_node_t	cn_avl;
    55 } config_node_t;
    52 } config_node_t;
    71 		return (1);
    68 		return (1);
    72 	else
    69 	else
    73 		return (0);
    70 		return (0);
    74 }
    71 }
    75 
    72 
       
    73 void
       
    74 namespace_clear(libzfs_handle_t *hdl)
       
    75 {
       
    76 	if (hdl->libzfs_ns_avl) {
       
    77 		uu_avl_walk_t *walk;
       
    78 		config_node_t *cn;
       
    79 
       
    80 		if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl,
       
    81 		    UU_WALK_ROBUST)) == NULL)
       
    82 			return;
       
    83 
       
    84 		while ((cn = uu_avl_walk_next(walk)) != NULL) {
       
    85 			uu_avl_remove(hdl->libzfs_ns_avl, cn);
       
    86 			nvlist_free(cn->cn_config);
       
    87 			free(cn->cn_name);
       
    88 			free(cn);
       
    89 		}
       
    90 
       
    91 		uu_avl_walk_end(walk);
       
    92 
       
    93 		uu_avl_destroy(hdl->libzfs_ns_avl);
       
    94 		hdl->libzfs_ns_avl = NULL;
       
    95 	}
       
    96 
       
    97 	if (hdl->libzfs_ns_avlpool) {
       
    98 		uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
       
    99 		hdl->libzfs_ns_avlpool = NULL;
       
   100 	}
       
   101 }
       
   102 
    76 /*
   103 /*
    77  * Loads the pool namespace, or re-loads it if the cache has changed.
   104  * Loads the pool namespace, or re-loads it if the cache has changed.
    78  */
   105  */
    79 static void
   106 static int
    80 namespace_reload()
   107 namespace_reload(libzfs_handle_t *hdl)
    81 {
   108 {
    82 	nvlist_t *config;
   109 	nvlist_t *config;
    83 	config_node_t *cn;
   110 	config_node_t *cn;
    84 	nvpair_t *elem;
   111 	nvpair_t *elem;
    85 	zfs_cmd_t zc = { 0 };
   112 	zfs_cmd_t zc = { 0 };
    86 	uu_avl_walk_t *walk;
   113 	uu_avl_walk_t *walk;
    87 
   114 
    88 	if (namespace_generation == 0) {
   115 	if (hdl->libzfs_ns_gen == 0) {
    89 		/*
   116 		/*
    90 		 * This is the first time we've accessed the configuration
   117 		 * This is the first time we've accessed the configuration
    91 		 * cache.  Initialize the AVL tree and then fall through to the
   118 		 * cache.  Initialize the AVL tree and then fall through to the
    92 		 * common code.
   119 		 * common code.
    93 		 */
   120 		 */
    94 		uu_avl_pool_t *pool;
   121 		if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
    95 
       
    96 		if ((pool = uu_avl_pool_create("config_pool",
       
    97 		    sizeof (config_node_t),
   122 		    sizeof (config_node_t),
    98 		    offsetof(config_node_t, cn_avl),
   123 		    offsetof(config_node_t, cn_avl),
    99 		    config_node_compare, UU_DEFAULT)) == NULL)
   124 		    config_node_compare, UU_DEFAULT)) == NULL)
   100 			no_memory();
   125 			return (no_memory(hdl));
   101 
   126 
   102 		if ((namespace_avl = uu_avl_create(pool, NULL,
   127 		if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
   103 		    UU_DEFAULT)) == NULL)
   128 		    NULL, UU_DEFAULT)) == NULL)
   104 			no_memory();
   129 			return (no_memory(hdl));
   105 	}
   130 	}
   106 
   131 
   107 	/*
   132 	/*
   108 	 * Issue the ZFS_IOC_POOL_CONFIGS ioctl.
   133 	 * Issue the ZFS_IOC_POOL_CONFIGS ioctl.
   109 	 * This can fail for one of two reasons:
   134 	 * This can fail for one of two reasons:
   112 	 * 	ENOMEM		The zc_config_dst buffer isn't large enough to
   137 	 * 	ENOMEM		The zc_config_dst buffer isn't large enough to
   113 	 * 			hold the config; zc_config_dst_size will have
   138 	 * 			hold the config; zc_config_dst_size will have
   114 	 *			been modified to tell us how much to allocate.
   139 	 *			been modified to tell us how much to allocate.
   115 	 */
   140 	 */
   116 	zc.zc_config_dst_size = 1024;
   141 	zc.zc_config_dst_size = 1024;
   117 	zc.zc_config_dst = (uint64_t)(uintptr_t)
   142 	if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
   118 	    zfs_malloc(zc.zc_config_dst_size);
   143 	    zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
       
   144 		return (-1);
   119 	for (;;) {
   145 	for (;;) {
   120 		zc.zc_cookie = namespace_generation;
   146 		zc.zc_cookie = hdl->libzfs_ns_gen;
   121 		if (zfs_ioctl(ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
   147 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
   122 			switch (errno) {
   148 			switch (errno) {
   123 			case EEXIST:
   149 			case EEXIST:
   124 				/*
   150 				/*
   125 				 * The namespace hasn't changed.
   151 				 * The namespace hasn't changed.
   126 				 */
   152 				 */
   127 				free((void *)(uintptr_t)zc.zc_config_dst);
   153 				free((void *)(uintptr_t)zc.zc_config_dst);
   128 				return;
   154 				return (0);
   129 
   155 
   130 			case ENOMEM:
   156 			case ENOMEM:
   131 				free((void *)(uintptr_t)zc.zc_config_dst);
   157 				free((void *)(uintptr_t)zc.zc_config_dst);
   132 				zc.zc_config_dst = (uint64_t)(uintptr_t)
   158 				if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
   133 				    zfs_malloc(zc.zc_config_dst_size);
   159 				    zfs_alloc(hdl, zc.zc_config_dst_size))
       
   160 				    == NULL)
       
   161 					return (-1);
   134 				break;
   162 				break;
   135 
   163 
   136 			default:
   164 			default:
   137 				zfs_baderror(errno);
   165 				return (zfs_standard_error(hdl, errno,
       
   166 				    dgettext(TEXT_DOMAIN, "failed to read "
       
   167 				    "pool configuration")));
   138 			}
   168 			}
   139 		} else {
   169 		} else {
   140 			namespace_generation = zc.zc_cookie;
   170 			hdl->libzfs_ns_gen = zc.zc_cookie;
   141 			break;
   171 			break;
   142 		}
   172 		}
   143 	}
   173 	}
   144 
   174 
   145 	verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
   175 	if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
   146 	    zc.zc_config_dst_size, &config, 0) == 0);
   176 	    zc.zc_config_dst_size, &config, 0) != 0)
       
   177 		return (no_memory(hdl));
   147 
   178 
   148 	free((void *)(uintptr_t)zc.zc_config_dst);
   179 	free((void *)(uintptr_t)zc.zc_config_dst);
   149 
   180 
   150 	/*
   181 	/*
   151 	 * Clear out any existing configuration information.
   182 	 * Clear out any existing configuration information.
   152 	 */
   183 	 */
   153 	if ((walk = uu_avl_walk_start(namespace_avl, UU_WALK_ROBUST)) == NULL)
   184 	if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl,
   154 		no_memory();
   185 	    UU_WALK_ROBUST)) == NULL) {
       
   186 		nvlist_free(config);
       
   187 		return (no_memory(hdl));
       
   188 	}
   155 
   189 
   156 	while ((cn = uu_avl_walk_next(walk)) != NULL) {
   190 	while ((cn = uu_avl_walk_next(walk)) != NULL) {
   157 		uu_avl_remove(namespace_avl, cn);
   191 		uu_avl_remove(hdl->libzfs_ns_avl, cn);
   158 		nvlist_free(cn->cn_config);
   192 		nvlist_free(cn->cn_config);
   159 		free(cn->cn_name);
   193 		free(cn->cn_name);
   160 		free(cn);
   194 		free(cn);
   161 	}
   195 	}
       
   196 
       
   197 	uu_avl_walk_end(walk);
   162 
   198 
   163 	elem = NULL;
   199 	elem = NULL;
   164 	while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
   200 	while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
   165 		nvlist_t *child;
   201 		nvlist_t *child;
   166 		uu_avl_index_t where;
   202 		uu_avl_index_t where;
   167 
   203 
   168 		cn = zfs_malloc(sizeof (config_node_t));
   204 		if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
   169 		cn->cn_name = zfs_strdup(nvpair_name(elem));
   205 			nvlist_free(config);
       
   206 			return (-1);
       
   207 		}
       
   208 
       
   209 		if ((cn->cn_name = zfs_strdup(hdl,
       
   210 		    nvpair_name(elem))) == NULL) {
       
   211 			free(cn);
       
   212 			return (-1);
       
   213 		}
   170 
   214 
   171 		verify(nvpair_value_nvlist(elem, &child) == 0);
   215 		verify(nvpair_value_nvlist(elem, &child) == 0);
   172 		verify(nvlist_dup(child, &cn->cn_config, 0) == 0);
   216 		if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
   173 		verify(uu_avl_find(namespace_avl, cn, NULL, &where) == NULL);
   217 			nvlist_free(config);
   174 
   218 			return (no_memory(hdl));
   175 		uu_avl_insert(namespace_avl, cn, where);
   219 		}
       
   220 		verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
       
   221 		    == NULL);
       
   222 
       
   223 		uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
   176 	}
   224 	}
   177 
   225 
   178 	nvlist_free(config);
   226 	nvlist_free(config);
       
   227 	return (0);
   179 }
   228 }
   180 
   229 
   181 /*
   230 /*
   182  * Retrive the configuration for the given pool.  The configuration is a nvlist
   231  * Retrive the configuration for the given pool.  The configuration is a nvlist
   183  * describing the vdevs, as well as the statistics associated with each one.
   232  * describing the vdevs, as well as the statistics associated with each one.
   207 
   256 
   208 	if (zhp->zpool_config_size == 0)
   257 	if (zhp->zpool_config_size == 0)
   209 		zhp->zpool_config_size = 1 << 16;
   258 		zhp->zpool_config_size = 1 << 16;
   210 
   259 
   211 	zc.zc_config_dst_size = zhp->zpool_config_size;
   260 	zc.zc_config_dst_size = zhp->zpool_config_size;
   212 	zc.zc_config_dst = (uint64_t)(uintptr_t)
   261 	if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
   213 	    zfs_malloc(zc.zc_config_dst_size);
   262 	    zfs_alloc(zhp->zpool_hdl, zc.zc_config_dst_size)) == NULL)
       
   263 		return (-1);
   214 
   264 
   215 	for (;;) {
   265 	for (;;) {
   216 		if (zfs_ioctl(ZFS_IOC_POOL_STATS, &zc) == 0) {
   266 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
       
   267 		    &zc) == 0) {
   217 			/*
   268 			/*
   218 			 * The real error is returned in the zc_cookie field.
   269 			 * The real error is returned in the zc_cookie field.
   219 			 */
   270 			 */
   220 			error = zc.zc_cookie;
   271 			error = errno = zc.zc_cookie;
   221 			break;
   272 			break;
   222 		}
   273 		}
   223 
   274 
   224 		if (errno == ENOMEM) {
   275 		if (errno == ENOMEM) {
   225 			free((void *)(uintptr_t)zc.zc_config_dst);
   276 			free((void *)(uintptr_t)zc.zc_config_dst);
   226 			zc.zc_config_dst = (uint64_t)(uintptr_t)
   277 			if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
   227 			    zfs_malloc(zc.zc_config_dst_size);
   278 			    zfs_alloc(zhp->zpool_hdl,
       
   279 			    zc.zc_config_dst_size)) == NULL)
       
   280 				return (-1);
   228 		} else {
   281 		} else {
   229 			free((void *)(uintptr_t)zc.zc_config_dst);
   282 			free((void *)(uintptr_t)zc.zc_config_dst);
   230 			return (errno);
   283 			return (-1);
   231 		}
   284 		}
   232 	}
   285 	}
   233 
   286 
   234 	verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
   287 	if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
   235 	    zc.zc_config_dst_size, &config, 0) == 0);
   288 	    zc.zc_config_dst_size, &config, 0) != 0) {
       
   289 		free((void *)(uintptr_t)zc.zc_config_dst);
       
   290 		return (no_memory(zhp->zpool_hdl));
       
   291 	}
   236 
   292 
   237 	zhp->zpool_config_size = zc.zc_config_dst_size;
   293 	zhp->zpool_config_size = zc.zc_config_dst_size;
   238 	free((void *)(uintptr_t)zc.zc_config_dst);
   294 	free((void *)(uintptr_t)zc.zc_config_dst);
   239 
   295 
   240 	set_pool_health(config);
   296 	if (set_pool_health(config) != 0)
       
   297 		return (no_memory(zhp->zpool_hdl));
   241 
   298 
   242 	if (zhp->zpool_config != NULL) {
   299 	if (zhp->zpool_config != NULL) {
   243 		uint64_t oldtxg, newtxg;
   300 		uint64_t oldtxg, newtxg;
   244 
   301 
   245 		verify(nvlist_lookup_uint64(zhp->zpool_config,
   302 		verify(nvlist_lookup_uint64(zhp->zpool_config,
   258 		}
   315 		}
   259 	}
   316 	}
   260 
   317 
   261 	zhp->zpool_config = config;
   318 	zhp->zpool_config = config;
   262 
   319 
   263 	return (error);
   320 	return (error ? -1 : 0);
   264 }
   321 }
   265 
   322 
   266 /*
   323 /*
   267  * Iterate over all pools in the system.
   324  * Iterate over all pools in the system.
   268  */
   325  */
   269 int
   326 int
   270 zpool_iter(zpool_iter_f func, void *data)
   327 zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
   271 {
   328 {
   272 	config_node_t *cn;
   329 	config_node_t *cn;
   273 	zpool_handle_t *zhp;
   330 	zpool_handle_t *zhp;
   274 	int ret;
   331 	int ret;
   275 
   332 
   276 	namespace_reload();
   333 	if (namespace_reload(hdl) != 0)
   277 
   334 		return (-1);
   278 	for (cn = uu_avl_first(namespace_avl); cn != NULL;
   335 
   279 	    cn = uu_avl_next(namespace_avl, cn)) {
   336 	for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
   280 
   337 	    cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
   281 		if ((zhp = zpool_open_silent(cn->cn_name)) == NULL)
   338 
       
   339 		if ((zhp = zpool_open_silent(hdl, cn->cn_name)) == NULL)
   282 			continue;
   340 			continue;
   283 
   341 
   284 		if ((ret = func(zhp, data)) != 0)
   342 		if ((ret = func(zhp, data)) != 0)
   285 			return (ret);
   343 			return (ret);
   286 	}
   344 	}
   291 /*
   349 /*
   292  * Iterate over root datasets, calling the given function for each.  The zfs
   350  * Iterate over root datasets, calling the given function for each.  The zfs
   293  * handle passed each time must be explicitly closed by the callback.
   351  * handle passed each time must be explicitly closed by the callback.
   294  */
   352  */
   295 int
   353 int
   296 zfs_iter_root(zfs_iter_f func, void *data)
   354 zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
   297 {
   355 {
   298 	config_node_t *cn;
   356 	config_node_t *cn;
   299 	zfs_handle_t *zhp;
   357 	zfs_handle_t *zhp;
   300 	int ret;
   358 	int ret;
   301 
   359 
   302 	namespace_reload();
   360 	if (namespace_reload(hdl) != 0)
   303 
   361 		return (-1);
   304 	for (cn = uu_avl_first(namespace_avl); cn != NULL;
   362 
   305 	    cn = uu_avl_next(namespace_avl, cn)) {
   363 	for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
   306 
   364 	    cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
   307 		if ((zhp = make_dataset_handle(cn->cn_name)) == NULL)
   365 
       
   366 		if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
   308 			continue;
   367 			continue;
   309 
   368 
   310 		if ((ret = func(zhp, data)) != 0)
   369 		if ((ret = func(zhp, data)) != 0)
   311 			return (ret);
   370 			return (ret);
   312 	}
   371 	}