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