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