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