Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/module/zcommon/zprop_common.c
48383 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
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24
* Use is subject to license terms.
25
*/
26
/*
27
* Copyright (c) 2012 by Delphix. All rights reserved.
28
*/
29
30
/*
31
* Common routines used by zfs and zpool property management.
32
*/
33
34
#include <sys/zio.h>
35
#include <sys/spa.h>
36
#include <sys/zfs_acl.h>
37
#include <sys/zfs_ioctl.h>
38
#include <sys/zfs_sysfs.h>
39
#include <sys/zfs_znode.h>
40
#include <sys/fs/zfs.h>
41
42
#include "zfs_prop.h"
43
#include "zfs_deleg.h"
44
45
#if !defined(_KERNEL)
46
#include <stdlib.h>
47
#include <string.h>
48
#include <ctype.h>
49
#include <sys/stat.h>
50
#endif
51
52
static zprop_desc_t *
53
zprop_get_proptable(zfs_type_t type)
54
{
55
if (type == ZFS_TYPE_POOL)
56
return (zpool_prop_get_table());
57
else if (type == ZFS_TYPE_VDEV)
58
return (vdev_prop_get_table());
59
else
60
return (zfs_prop_get_table());
61
}
62
63
static int
64
zprop_get_numprops(zfs_type_t type)
65
{
66
if (type == ZFS_TYPE_POOL)
67
return (ZPOOL_NUM_PROPS);
68
else if (type == ZFS_TYPE_VDEV)
69
return (VDEV_NUM_PROPS);
70
else
71
return (ZFS_NUM_PROPS);
72
}
73
74
static boolean_t
75
zfs_mod_supported_prop(const char *name, zfs_type_t type,
76
const struct zfs_mod_supported_features *sfeatures)
77
{
78
/*
79
* The zfs module spa_feature_table[], whether in-kernel or in libzpool,
80
* always supports all the properties. libzfs needs to query the running
81
* module, via sysfs, to determine which properties are supported.
82
*
83
* The equivalent _can_ be done on FreeBSD by way of the sysctl
84
* tree, but this has not been done yet.
85
*/
86
#if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD) || defined(__FreeBSD__)
87
(void) name, (void) type, (void) sfeatures;
88
return (B_TRUE);
89
#else
90
return (zfs_mod_supported(type == ZFS_TYPE_POOL ?
91
ZFS_SYSFS_POOL_PROPERTIES : (type == ZFS_TYPE_VDEV ?
92
ZFS_SYSFS_VDEV_PROPERTIES : ZFS_SYSFS_DATASET_PROPERTIES),
93
name, sfeatures));
94
#endif
95
}
96
97
void
98
zprop_register_impl(int prop, const char *name, zprop_type_t type,
99
uint64_t numdefault, const char *strdefault, zprop_attr_t attr,
100
int objset_types, const char *values, const char *colname,
101
boolean_t rightalign, boolean_t visible, boolean_t flex,
102
const zprop_index_t *idx_tbl,
103
const struct zfs_mod_supported_features *sfeatures)
104
{
105
zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types);
106
zprop_desc_t *pd;
107
108
pd = &prop_tbl[prop];
109
110
ASSERT(pd->pd_name == NULL || pd->pd_name == name);
111
ASSERT(name != NULL);
112
ASSERT(colname != NULL);
113
114
pd->pd_name = name;
115
pd->pd_propnum = prop;
116
pd->pd_proptype = type;
117
pd->pd_numdefault = numdefault;
118
pd->pd_strdefault = strdefault;
119
pd->pd_attr = attr;
120
pd->pd_types = objset_types;
121
pd->pd_values = values;
122
pd->pd_colname = colname;
123
pd->pd_rightalign = rightalign;
124
pd->pd_visible = visible;
125
pd->pd_zfs_mod_supported =
126
zfs_mod_supported_prop(name, objset_types, sfeatures);
127
pd->pd_always_flex = flex;
128
pd->pd_table = idx_tbl;
129
pd->pd_table_size = 0;
130
while (idx_tbl && (idx_tbl++)->pi_name != NULL)
131
pd->pd_table_size++;
132
}
133
134
void
135
zprop_register_string(int prop, const char *name, const char *def,
136
zprop_attr_t attr, int objset_types, const char *values,
137
const char *colname, const struct zfs_mod_supported_features *sfeatures)
138
{
139
zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
140
objset_types, values, colname, B_FALSE, B_TRUE, B_TRUE, NULL,
141
sfeatures);
142
143
}
144
145
void
146
zprop_register_number(int prop, const char *name, uint64_t def,
147
zprop_attr_t attr, int objset_types, const char *values,
148
const char *colname, boolean_t flex,
149
const struct zfs_mod_supported_features *sfeatures)
150
{
151
zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
152
objset_types, values, colname, B_TRUE, B_TRUE, flex, NULL,
153
sfeatures);
154
}
155
156
void
157
zprop_register_index(int prop, const char *name, uint64_t def,
158
zprop_attr_t attr, int objset_types, const char *values,
159
const char *colname, const zprop_index_t *idx_tbl,
160
const struct zfs_mod_supported_features *sfeatures)
161
{
162
zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr,
163
objset_types, values, colname, B_FALSE, B_TRUE, B_TRUE, idx_tbl,
164
sfeatures);
165
}
166
167
void
168
zprop_register_hidden(int prop, const char *name, zprop_type_t type,
169
zprop_attr_t attr, int objset_types, const char *colname, boolean_t flex,
170
const struct zfs_mod_supported_features *sfeatures)
171
{
172
zprop_register_impl(prop, name, type, 0, NULL, attr,
173
objset_types, NULL, colname,
174
type == PROP_TYPE_NUMBER, B_FALSE, flex, NULL, sfeatures);
175
}
176
177
178
/*
179
* A comparison function we can use to order indexes into property tables.
180
*/
181
static int
182
zprop_compare(const void *arg1, const void *arg2)
183
{
184
const zprop_desc_t *p1 = *((zprop_desc_t **)arg1);
185
const zprop_desc_t *p2 = *((zprop_desc_t **)arg2);
186
boolean_t p1ro, p2ro;
187
188
p1ro = (p1->pd_attr == PROP_READONLY);
189
p2ro = (p2->pd_attr == PROP_READONLY);
190
191
if (p1ro == p2ro)
192
return (strcmp(p1->pd_name, p2->pd_name));
193
194
return (p1ro ? -1 : 1);
195
}
196
197
/*
198
* Iterate over all properties in the given property table, calling back
199
* into the specified function for each property. We will continue to
200
* iterate until we either reach the end or the callback function returns
201
* something other than ZPROP_CONT.
202
*/
203
int
204
zprop_iter_common(zprop_func func, void *cb, boolean_t show_all,
205
boolean_t ordered, zfs_type_t type)
206
{
207
int i, num_props, size, prop;
208
zprop_desc_t *prop_tbl;
209
zprop_desc_t **order;
210
211
prop_tbl = zprop_get_proptable(type);
212
num_props = zprop_get_numprops(type);
213
size = num_props * sizeof (zprop_desc_t *);
214
215
#if defined(_KERNEL)
216
order = kmem_alloc(size, KM_SLEEP);
217
#else
218
if ((order = malloc(size)) == NULL)
219
return (ZPROP_CONT);
220
#endif
221
222
for (int j = 0; j < num_props; j++)
223
order[j] = &prop_tbl[j];
224
225
if (ordered) {
226
qsort((void *)order, num_props, sizeof (zprop_desc_t *),
227
zprop_compare);
228
}
229
230
prop = ZPROP_CONT;
231
for (i = 0; i < num_props; i++) {
232
if ((order[i]->pd_visible || show_all) &&
233
order[i]->pd_zfs_mod_supported &&
234
(func(order[i]->pd_propnum, cb) != ZPROP_CONT)) {
235
prop = order[i]->pd_propnum;
236
break;
237
}
238
}
239
240
#if defined(_KERNEL)
241
kmem_free(order, size);
242
#else
243
free(order);
244
#endif
245
return (prop);
246
}
247
248
static boolean_t
249
propname_match(const char *p, size_t len, zprop_desc_t *prop_entry)
250
{
251
const char *propname = prop_entry->pd_name;
252
#ifndef _KERNEL
253
const char *colname = prop_entry->pd_colname;
254
int c;
255
#endif
256
257
ASSERT(propname != NULL);
258
259
if (len == strlen(propname) &&
260
strncmp(p, propname, len) == 0)
261
return (B_TRUE);
262
263
#ifndef _KERNEL
264
if (colname == NULL || len != strlen(colname))
265
return (B_FALSE);
266
267
for (c = 0; c < len; c++)
268
if (p[c] != tolower(colname[c]))
269
break;
270
271
return (colname[c] == '\0');
272
#else
273
return (B_FALSE);
274
#endif
275
}
276
277
typedef struct name_to_prop_cb {
278
const char *propname;
279
zprop_desc_t *prop_tbl;
280
} name_to_prop_cb_t;
281
282
static int
283
zprop_name_to_prop_cb(int prop, void *cb_data)
284
{
285
name_to_prop_cb_t *data = cb_data;
286
287
if (propname_match(data->propname, strlen(data->propname),
288
&data->prop_tbl[prop]))
289
return (prop);
290
291
return (ZPROP_CONT);
292
}
293
294
int
295
zprop_name_to_prop(const char *propname, zfs_type_t type)
296
{
297
int prop;
298
name_to_prop_cb_t cb_data;
299
300
cb_data.propname = propname;
301
cb_data.prop_tbl = zprop_get_proptable(type);
302
303
prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data,
304
B_TRUE, B_FALSE, type);
305
306
return (prop == ZPROP_CONT ? ZPROP_INVAL : prop);
307
}
308
309
int
310
zprop_string_to_index(int prop, const char *string, uint64_t *index,
311
zfs_type_t type)
312
{
313
zprop_desc_t *prop_tbl;
314
const zprop_index_t *idx_tbl;
315
int i;
316
317
if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
318
return (-1);
319
320
ASSERT(prop < zprop_get_numprops(type));
321
prop_tbl = zprop_get_proptable(type);
322
if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
323
return (-1);
324
325
for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
326
if (strcmp(string, idx_tbl[i].pi_name) == 0) {
327
*index = idx_tbl[i].pi_value;
328
return (0);
329
}
330
}
331
332
return (-1);
333
}
334
335
int
336
zprop_index_to_string(int prop, uint64_t index, const char **string,
337
zfs_type_t type)
338
{
339
zprop_desc_t *prop_tbl;
340
const zprop_index_t *idx_tbl;
341
int i;
342
343
if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
344
return (-1);
345
346
ASSERT(prop < zprop_get_numprops(type));
347
prop_tbl = zprop_get_proptable(type);
348
if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
349
return (-1);
350
351
for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
352
if (idx_tbl[i].pi_value == index) {
353
*string = idx_tbl[i].pi_name;
354
return (0);
355
}
356
}
357
358
return (-1);
359
}
360
361
/*
362
* Return a random valid property value. Used by ztest.
363
*/
364
uint64_t
365
zprop_random_value(int prop, uint64_t seed, zfs_type_t type)
366
{
367
zprop_desc_t *prop_tbl;
368
const zprop_index_t *idx_tbl;
369
370
ASSERT((uint_t)prop < zprop_get_numprops(type));
371
prop_tbl = zprop_get_proptable(type);
372
idx_tbl = prop_tbl[prop].pd_table;
373
374
if (idx_tbl == NULL)
375
return (seed);
376
377
return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value);
378
}
379
380
const char *
381
zprop_values(int prop, zfs_type_t type)
382
{
383
zprop_desc_t *prop_tbl;
384
385
ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
386
ASSERT(prop < zprop_get_numprops(type));
387
388
prop_tbl = zprop_get_proptable(type);
389
390
return (prop_tbl[prop].pd_values);
391
}
392
393
/*
394
* Returns TRUE if the property applies to any of the given dataset types.
395
*
396
* If headcheck is set, the check is being made against the head dataset
397
* type of a snapshot which requires to return B_TRUE when the property
398
* is only valid for snapshots.
399
*/
400
boolean_t
401
zprop_valid_for_type(int prop, zfs_type_t type, boolean_t headcheck)
402
{
403
zprop_desc_t *prop_tbl;
404
405
if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
406
return (B_FALSE);
407
408
ASSERT(prop < zprop_get_numprops(type));
409
prop_tbl = zprop_get_proptable(type);
410
if (headcheck && prop_tbl[prop].pd_types == ZFS_TYPE_SNAPSHOT)
411
return (B_TRUE);
412
return ((prop_tbl[prop].pd_types & type) != 0);
413
}
414
415
/*
416
* For user property names, we allow all lowercase alphanumeric characters, plus
417
* a few useful punctuation characters.
418
*/
419
int
420
zprop_valid_char(char c)
421
{
422
return ((c >= 'a' && c <= 'z') ||
423
(c >= '0' && c <= '9') ||
424
c == '-' || c == '_' || c == '.' || c == ':');
425
}
426
427
#ifndef _KERNEL
428
429
/*
430
* Determines the minimum width for the column, and indicates whether it's fixed
431
* or not. Only string columns are non-fixed.
432
*/
433
size_t
434
zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
435
{
436
zprop_desc_t *prop_tbl, *pd;
437
const zprop_index_t *idx;
438
size_t ret;
439
int i;
440
441
ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
442
ASSERT(prop < zprop_get_numprops(type));
443
444
prop_tbl = zprop_get_proptable(type);
445
pd = &prop_tbl[prop];
446
447
if (type != ZFS_TYPE_POOL && type != ZFS_TYPE_VDEV)
448
type = ZFS_TYPE_FILESYSTEM;
449
450
*fixed = !pd->pd_always_flex;
451
452
/*
453
* Start with the width of the column name.
454
*/
455
ret = strlen(pd->pd_colname);
456
457
/*
458
* For fixed-width values, make sure the width is large enough to hold
459
* any possible value.
460
*/
461
switch (pd->pd_proptype) {
462
case PROP_TYPE_NUMBER:
463
/*
464
* The maximum length of a human-readable number is 5 characters
465
* ("20.4M", for example).
466
*/
467
if (ret < 5)
468
ret = 5;
469
/*
470
* 'health' is handled specially because it's a number
471
* internally, but displayed as a fixed 8 character string.
472
*/
473
if (type == ZFS_TYPE_POOL && prop == ZPOOL_PROP_HEALTH)
474
ret = 8;
475
break;
476
477
case PROP_TYPE_INDEX:
478
idx = prop_tbl[prop].pd_table;
479
for (i = 0; idx[i].pi_name != NULL; i++) {
480
if (strlen(idx[i].pi_name) > ret)
481
ret = strlen(idx[i].pi_name);
482
}
483
break;
484
485
case PROP_TYPE_STRING:
486
break;
487
}
488
489
return (ret);
490
}
491
492
#endif
493
494
#if defined(_KERNEL)
495
/* Common routines to initialize property tables */
496
EXPORT_SYMBOL(zprop_register_impl);
497
EXPORT_SYMBOL(zprop_register_string);
498
EXPORT_SYMBOL(zprop_register_number);
499
EXPORT_SYMBOL(zprop_register_index);
500
EXPORT_SYMBOL(zprop_register_hidden);
501
502
/* Common routines for zfs and zpool property management */
503
EXPORT_SYMBOL(zprop_iter_common);
504
EXPORT_SYMBOL(zprop_name_to_prop);
505
EXPORT_SYMBOL(zprop_string_to_index);
506
EXPORT_SYMBOL(zprop_index_to_string);
507
EXPORT_SYMBOL(zprop_random_value);
508
EXPORT_SYMBOL(zprop_values);
509
EXPORT_SYMBOL(zprop_valid_for_type);
510
EXPORT_SYMBOL(zprop_valid_char);
511
#endif
512
513