xref: /freebsd/sys/contrib/openzfs/module/zcommon/zprop_common.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
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 *
zprop_get_proptable(zfs_type_t type)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
zprop_get_numprops(zfs_type_t type)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
zfs_mod_supported_prop(const char * name,zfs_type_t type,const struct zfs_mod_supported_features * sfeatures)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
zprop_register_impl(int prop,const char * name,zprop_type_t type,uint64_t numdefault,const char * strdefault,zprop_attr_t attr,int objset_types,const char * values,const char * colname,boolean_t rightalign,boolean_t visible,boolean_t flex,const zprop_index_t * idx_tbl,const struct zfs_mod_supported_features * sfeatures)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
zprop_register_string(int prop,const char * name,const char * def,zprop_attr_t attr,int objset_types,const char * values,const char * colname,const struct zfs_mod_supported_features * sfeatures)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
zprop_register_number(int prop,const char * name,uint64_t def,zprop_attr_t attr,int objset_types,const char * values,const char * colname,boolean_t flex,const struct zfs_mod_supported_features * sfeatures)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
zprop_register_index(int prop,const char * name,uint64_t def,zprop_attr_t attr,int objset_types,const char * values,const char * colname,const zprop_index_t * idx_tbl,const struct zfs_mod_supported_features * sfeatures)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
zprop_register_hidden(int prop,const char * name,zprop_type_t type,zprop_attr_t attr,int objset_types,const char * colname,boolean_t flex,const struct zfs_mod_supported_features * sfeatures)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
zprop_compare(const void * arg1,const void * arg2)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
zprop_iter_common(zprop_func func,void * cb,boolean_t show_all,boolean_t ordered,zfs_type_t type)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
propname_match(const char * p,size_t len,zprop_desc_t * prop_entry)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
zprop_name_to_prop_cb(int prop,void * cb_data)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
zprop_name_to_prop(const char * propname,zfs_type_t type)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
zprop_string_to_index(int prop,const char * string,uint64_t * index,zfs_type_t type)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
zprop_index_to_string(int prop,uint64_t index,const char ** string,zfs_type_t type)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
zprop_random_value(int prop,uint64_t seed,zfs_type_t type)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 *
zprop_values(int prop,zfs_type_t type)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
zprop_valid_for_type(int prop,zfs_type_t type,boolean_t headcheck)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
zprop_valid_char(char c)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
zprop_width(int prop,boolean_t * fixed,zfs_type_t type)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