xref: /onnv-gate/usr/src/common/zfs/zprop_common.c (revision 11976:3791e5495b0d)
15094Slling /*
25094Slling  * CDDL HEADER START
35094Slling  *
45094Slling  * The contents of this file are subject to the terms of the
55094Slling  * Common Development and Distribution License (the "License").
65094Slling  * You may not use this file except in compliance with the License.
75094Slling  *
85094Slling  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95094Slling  * or http://www.opensolaris.org/os/licensing.
105094Slling  * See the License for the specific language governing permissions
115094Slling  * and limitations under the License.
125094Slling  *
135094Slling  * When distributing Covered Code, include this CDDL HEADER in each
145094Slling  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155094Slling  * If applicable, add the following below this CDDL HEADER, with the
165094Slling  * fields enclosed by brackets "[]" replaced with your own identifying
175094Slling  * information: Portions Copyright [yyyy] [name of copyright owner]
185094Slling  *
195094Slling  * CDDL HEADER END
205094Slling  */
215094Slling /*
22*11976STom.Erickson@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
235094Slling  * Use is subject to license terms.
245094Slling  */
255094Slling 
265094Slling /*
275094Slling  * Common routines used by zfs and zpool property management.
285094Slling  */
295094Slling 
305094Slling #include <sys/zio.h>
315094Slling #include <sys/spa.h>
325094Slling #include <sys/zfs_acl.h>
335094Slling #include <sys/zfs_ioctl.h>
345094Slling #include <sys/zfs_znode.h>
355094Slling #include <sys/fs/zfs.h>
365094Slling 
375094Slling #include "zfs_prop.h"
385094Slling #include "zfs_deleg.h"
395094Slling 
405094Slling #if defined(_KERNEL)
415094Slling #include <sys/systm.h>
425094Slling #include <util/qsort.h>
435094Slling #else
445094Slling #include <stdlib.h>
455094Slling #include <string.h>
465094Slling #include <ctype.h>
475094Slling #endif
485094Slling 
495094Slling static zprop_desc_t *
zprop_get_proptable(zfs_type_t type)505094Slling zprop_get_proptable(zfs_type_t type)
515094Slling {
525094Slling 	if (type == ZFS_TYPE_POOL)
535094Slling 		return (zpool_prop_get_table());
545094Slling 	else
555094Slling 		return (zfs_prop_get_table());
565094Slling }
575094Slling 
585094Slling static int
zprop_get_numprops(zfs_type_t type)595094Slling zprop_get_numprops(zfs_type_t type)
605094Slling {
615094Slling 	if (type == ZFS_TYPE_POOL)
625094Slling 		return (ZPOOL_NUM_PROPS);
635094Slling 	else
645094Slling 		return (ZFS_NUM_PROPS);
655094Slling }
665094Slling 
675094Slling 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,const zprop_index_t * idx_tbl)68*11976STom.Erickson@Sun.COM zprop_register_impl(int prop, const char *name, zprop_type_t type,
695094Slling     uint64_t numdefault, const char *strdefault, zprop_attr_t attr,
705094Slling     int objset_types, const char *values, const char *colname,
715094Slling     boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl)
725094Slling {
735094Slling 	zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types);
745094Slling 	zprop_desc_t *pd;
755094Slling 
765094Slling 	pd = &prop_tbl[prop];
775094Slling 
785094Slling 	ASSERT(pd->pd_name == NULL || pd->pd_name == name);
7910922SJeff.Bonwick@Sun.COM 	ASSERT(name != NULL);
8010922SJeff.Bonwick@Sun.COM 	ASSERT(colname != NULL);
815094Slling 
825094Slling 	pd->pd_name = name;
835094Slling 	pd->pd_propnum = prop;
845094Slling 	pd->pd_proptype = type;
855094Slling 	pd->pd_numdefault = numdefault;
865094Slling 	pd->pd_strdefault = strdefault;
875094Slling 	pd->pd_attr = attr;
885094Slling 	pd->pd_types = objset_types;
895094Slling 	pd->pd_values = values;
905094Slling 	pd->pd_colname = colname;
915094Slling 	pd->pd_rightalign = rightalign;
925094Slling 	pd->pd_visible = visible;
935094Slling 	pd->pd_table = idx_tbl;
9410922SJeff.Bonwick@Sun.COM 	pd->pd_table_size = 0;
9510922SJeff.Bonwick@Sun.COM 	while (idx_tbl && (idx_tbl++)->pi_name != NULL)
9610922SJeff.Bonwick@Sun.COM 		pd->pd_table_size++;
975094Slling }
985094Slling 
995094Slling 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)100*11976STom.Erickson@Sun.COM zprop_register_string(int prop, const char *name, const char *def,
1015094Slling     zprop_attr_t attr, int objset_types, const char *values,
1025094Slling     const char *colname)
1035094Slling {
104*11976STom.Erickson@Sun.COM 	zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
1055094Slling 	    objset_types, values, colname, B_FALSE, B_TRUE, NULL);
1065094Slling 
1075094Slling }
1085094Slling 
1095094Slling 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)110*11976STom.Erickson@Sun.COM zprop_register_number(int prop, const char *name, uint64_t def,
111*11976STom.Erickson@Sun.COM     zprop_attr_t attr, int objset_types, const char *values,
112*11976STom.Erickson@Sun.COM     const char *colname)
1135094Slling {
114*11976STom.Erickson@Sun.COM 	zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
1155094Slling 	    objset_types, values, colname, B_TRUE, B_TRUE, NULL);
1165094Slling }
1175094Slling 
1185094Slling 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)119*11976STom.Erickson@Sun.COM zprop_register_index(int prop, const char *name, uint64_t def,
120*11976STom.Erickson@Sun.COM     zprop_attr_t attr, int objset_types, const char *values,
121*11976STom.Erickson@Sun.COM     const char *colname, const zprop_index_t *idx_tbl)
1225094Slling {
123*11976STom.Erickson@Sun.COM 	zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr,
1245094Slling 	    objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl);
1255094Slling }
1265094Slling 
1275094Slling void
zprop_register_hidden(int prop,const char * name,zprop_type_t type,zprop_attr_t attr,int objset_types,const char * colname)128*11976STom.Erickson@Sun.COM zprop_register_hidden(int prop, const char *name, zprop_type_t type,
1295094Slling     zprop_attr_t attr, int objset_types, const char *colname)
1305094Slling {
131*11976STom.Erickson@Sun.COM 	zprop_register_impl(prop, name, type, 0, NULL, attr,
1325094Slling 	    objset_types, NULL, colname, B_FALSE, B_FALSE, NULL);
1335094Slling }
1345094Slling 
1355094Slling 
1365094Slling /*
1375094Slling  * A comparison function we can use to order indexes into property tables.
1385094Slling  */
1395094Slling static int
zprop_compare(const void * arg1,const void * arg2)1405094Slling zprop_compare(const void *arg1, const void *arg2)
1415094Slling {
1425094Slling 	const zprop_desc_t *p1 = *((zprop_desc_t **)arg1);
1435094Slling 	const zprop_desc_t *p2 = *((zprop_desc_t **)arg2);
1445094Slling 	boolean_t p1ro, p2ro;
1455094Slling 
1465094Slling 	p1ro = (p1->pd_attr == PROP_READONLY);
1475094Slling 	p2ro = (p2->pd_attr == PROP_READONLY);
1485094Slling 
1495094Slling 	if (p1ro == p2ro)
1505094Slling 		return (strcmp(p1->pd_name, p2->pd_name));
1515094Slling 
1525094Slling 	return (p1ro ? -1 : 1);
1535094Slling }
1545094Slling 
1555094Slling /*
1565094Slling  * Iterate over all properties in the given property table, calling back
1575094Slling  * into the specified function for each property. We will continue to
1585094Slling  * iterate until we either reach the end or the callback function returns
1595094Slling  * something other than ZPROP_CONT.
1605094Slling  */
1615094Slling int
zprop_iter_common(zprop_func func,void * cb,boolean_t show_all,boolean_t ordered,zfs_type_t type)1625094Slling zprop_iter_common(zprop_func func, void *cb, boolean_t show_all,
1635094Slling     boolean_t ordered, zfs_type_t type)
1645094Slling {
1655094Slling 	int i, num_props, size, prop;
1665094Slling 	zprop_desc_t *prop_tbl;
1675094Slling 	zprop_desc_t **order;
1685094Slling 
1695094Slling 	prop_tbl = zprop_get_proptable(type);
1705094Slling 	num_props = zprop_get_numprops(type);
1715094Slling 	size = num_props * sizeof (zprop_desc_t *);
1725094Slling 
1735094Slling #if defined(_KERNEL)
1745094Slling 	order = kmem_alloc(size, KM_SLEEP);
1755094Slling #else
1765094Slling 	if ((order = malloc(size)) == NULL)
1775094Slling 		return (ZPROP_CONT);
1785094Slling #endif
1795094Slling 
1805094Slling 	for (int j = 0; j < num_props; j++)
1815094Slling 		order[j] = &prop_tbl[j];
1825094Slling 
1835094Slling 	if (ordered) {
1845094Slling 		qsort((void *)order, num_props, sizeof (zprop_desc_t *),
1855094Slling 		    zprop_compare);
1865094Slling 	}
1875094Slling 
1885094Slling 	prop = ZPROP_CONT;
1895094Slling 	for (i = 0; i < num_props; i++) {
1905094Slling 		if ((order[i]->pd_visible || show_all) &&
1915094Slling 		    (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) {
1925094Slling 			prop = order[i]->pd_propnum;
1935094Slling 			break;
1945094Slling 		}
1955094Slling 	}
1965094Slling 
1975094Slling #if defined(_KERNEL)
1985094Slling 	kmem_free(order, size);
1995094Slling #else
2005094Slling 	free(order);
2015094Slling #endif
2025094Slling 	return (prop);
2035094Slling }
2045094Slling 
2055094Slling static boolean_t
propname_match(const char * p,size_t len,zprop_desc_t * prop_entry)2065094Slling propname_match(const char *p, size_t len, zprop_desc_t *prop_entry)
2075094Slling {
2085094Slling 	const char *propname = prop_entry->pd_name;
2095094Slling #ifndef _KERNEL
2105094Slling 	const char *colname = prop_entry->pd_colname;
2115094Slling 	int c;
2125094Slling #endif
2135094Slling 
2145094Slling 	if (len == strlen(propname) &&
2155094Slling 	    strncmp(p, propname, len) == 0)
2165094Slling 		return (B_TRUE);
2175094Slling 
2185094Slling #ifndef _KERNEL
2199396SMatthew.Ahrens@Sun.COM 	if (colname == NULL || len != strlen(colname))
2205094Slling 		return (B_FALSE);
2215094Slling 
2225094Slling 	for (c = 0; c < len; c++)
2235094Slling 		if (p[c] != tolower(colname[c]))
2245094Slling 			break;
2255094Slling 
2265094Slling 	return (colname[c] == '\0');
2275094Slling #else
2285094Slling 	return (B_FALSE);
2295094Slling #endif
2305094Slling }
2315094Slling 
2325094Slling typedef struct name_to_prop_cb {
2335094Slling 	const char *propname;
2345094Slling 	zprop_desc_t *prop_tbl;
2355094Slling } name_to_prop_cb_t;
2365094Slling 
2375094Slling static int
zprop_name_to_prop_cb(int prop,void * cb_data)2385094Slling zprop_name_to_prop_cb(int prop, void *cb_data)
2395094Slling {
2405094Slling 	name_to_prop_cb_t *data = cb_data;
2415094Slling 
2425094Slling 	if (propname_match(data->propname, strlen(data->propname),
2435094Slling 	    &data->prop_tbl[prop]))
2445094Slling 		return (prop);
2455094Slling 
2465094Slling 	return (ZPROP_CONT);
2475094Slling }
2485094Slling 
2495094Slling int
zprop_name_to_prop(const char * propname,zfs_type_t type)2505094Slling zprop_name_to_prop(const char *propname, zfs_type_t type)
2515094Slling {
2525094Slling 	int prop;
2535094Slling 	name_to_prop_cb_t cb_data;
2545094Slling 
2555094Slling 	cb_data.propname = propname;
2565094Slling 	cb_data.prop_tbl = zprop_get_proptable(type);
2575094Slling 
2585094Slling 	prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data,
2595094Slling 	    B_TRUE, B_FALSE, type);
2605094Slling 
2615094Slling 	return (prop == ZPROP_CONT ? ZPROP_INVAL : prop);
2625094Slling }
2635094Slling 
2645094Slling int
zprop_string_to_index(int prop,const char * string,uint64_t * index,zfs_type_t type)2655094Slling zprop_string_to_index(int prop, const char *string, uint64_t *index,
2665094Slling     zfs_type_t type)
2675094Slling {
2685094Slling 	zprop_desc_t *prop_tbl;
2695094Slling 	const zprop_index_t *idx_tbl;
2705094Slling 	int i;
2715094Slling 
2726692Sgw25295 	if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
2736692Sgw25295 		return (-1);
2746692Sgw25295 
2756692Sgw25295 	ASSERT(prop < zprop_get_numprops(type));
2765094Slling 	prop_tbl = zprop_get_proptable(type);
2775094Slling 	if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
2785094Slling 		return (-1);
2795094Slling 
2805094Slling 	for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
2815094Slling 		if (strcmp(string, idx_tbl[i].pi_name) == 0) {
2825094Slling 			*index = idx_tbl[i].pi_value;
2835094Slling 			return (0);
2845094Slling 		}
2855094Slling 	}
2865094Slling 
2875094Slling 	return (-1);
2885094Slling }
2895094Slling 
2905094Slling int
zprop_index_to_string(int prop,uint64_t index,const char ** string,zfs_type_t type)2915094Slling zprop_index_to_string(int prop, uint64_t index, const char **string,
2925094Slling     zfs_type_t type)
2935094Slling {
2945094Slling 	zprop_desc_t *prop_tbl;
2955094Slling 	const zprop_index_t *idx_tbl;
2965094Slling 	int i;
2975094Slling 
2986692Sgw25295 	if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
2996692Sgw25295 		return (-1);
3006692Sgw25295 
3016692Sgw25295 	ASSERT(prop < zprop_get_numprops(type));
3025094Slling 	prop_tbl = zprop_get_proptable(type);
3035094Slling 	if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
3045094Slling 		return (-1);
3055094Slling 
3065094Slling 	for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
3075094Slling 		if (idx_tbl[i].pi_value == index) {
3085094Slling 			*string = idx_tbl[i].pi_name;
3095094Slling 			return (0);
3105094Slling 		}
3115094Slling 	}
3125094Slling 
3135094Slling 	return (-1);
3145094Slling }
3155094Slling 
31610922SJeff.Bonwick@Sun.COM /*
31710922SJeff.Bonwick@Sun.COM  * Return a random valid property value.  Used by ztest.
31810922SJeff.Bonwick@Sun.COM  */
31910922SJeff.Bonwick@Sun.COM uint64_t
zprop_random_value(int prop,uint64_t seed,zfs_type_t type)32010922SJeff.Bonwick@Sun.COM zprop_random_value(int prop, uint64_t seed, zfs_type_t type)
32110922SJeff.Bonwick@Sun.COM {
32210922SJeff.Bonwick@Sun.COM 	zprop_desc_t *prop_tbl;
32310922SJeff.Bonwick@Sun.COM 	const zprop_index_t *idx_tbl;
32410922SJeff.Bonwick@Sun.COM 
32510922SJeff.Bonwick@Sun.COM 	ASSERT((uint_t)prop < zprop_get_numprops(type));
32610922SJeff.Bonwick@Sun.COM 	prop_tbl = zprop_get_proptable(type);
32710922SJeff.Bonwick@Sun.COM 	idx_tbl = prop_tbl[prop].pd_table;
32810922SJeff.Bonwick@Sun.COM 
32910922SJeff.Bonwick@Sun.COM 	if (idx_tbl == NULL)
33010922SJeff.Bonwick@Sun.COM 		return (seed);
33110922SJeff.Bonwick@Sun.COM 
33210922SJeff.Bonwick@Sun.COM 	return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value);
33310922SJeff.Bonwick@Sun.COM }
33410922SJeff.Bonwick@Sun.COM 
3355094Slling const char *
zprop_values(int prop,zfs_type_t type)3365094Slling zprop_values(int prop, zfs_type_t type)
3375094Slling {
3385094Slling 	zprop_desc_t *prop_tbl;
3395094Slling 
3406692Sgw25295 	ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
3416692Sgw25295 	ASSERT(prop < zprop_get_numprops(type));
3426692Sgw25295 
3435094Slling 	prop_tbl = zprop_get_proptable(type);
3445094Slling 
3455094Slling 	return (prop_tbl[prop].pd_values);
3465094Slling }
3475094Slling 
3485094Slling /*
3495094Slling  * Returns TRUE if the property applies to any of the given dataset types.
3505094Slling  */
3516692Sgw25295 boolean_t
zprop_valid_for_type(int prop,zfs_type_t type)3525094Slling zprop_valid_for_type(int prop, zfs_type_t type)
3535094Slling {
3546692Sgw25295 	zprop_desc_t *prop_tbl;
3555094Slling 
3566692Sgw25295 	if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
3576692Sgw25295 		return (B_FALSE);
3586692Sgw25295 
3596692Sgw25295 	ASSERT(prop < zprop_get_numprops(type));
3606692Sgw25295 	prop_tbl = zprop_get_proptable(type);
3615094Slling 	return ((prop_tbl[prop].pd_types & type) != 0);
3625094Slling }
3635094Slling 
3645094Slling #ifndef _KERNEL
3655094Slling 
3665094Slling /*
3675094Slling  * Determines the minimum width for the column, and indicates whether it's fixed
3685094Slling  * or not.  Only string columns are non-fixed.
3695094Slling  */
3705094Slling size_t
zprop_width(int prop,boolean_t * fixed,zfs_type_t type)3715094Slling zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
3725094Slling {
3735094Slling 	zprop_desc_t *prop_tbl, *pd;
3745094Slling 	const zprop_index_t *idx;
3755094Slling 	size_t ret;
3765094Slling 	int i;
3775094Slling 
3786692Sgw25295 	ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
3796692Sgw25295 	ASSERT(prop < zprop_get_numprops(type));
3806692Sgw25295 
3815094Slling 	prop_tbl = zprop_get_proptable(type);
3825094Slling 	pd = &prop_tbl[prop];
3835094Slling 
3845094Slling 	*fixed = B_TRUE;
3855094Slling 
3865094Slling 	/*
3875094Slling 	 * Start with the width of the column name.
3885094Slling 	 */
3895094Slling 	ret = strlen(pd->pd_colname);
3905094Slling 
3915094Slling 	/*
3925094Slling 	 * For fixed-width values, make sure the width is large enough to hold
3935094Slling 	 * any possible value.
3945094Slling 	 */
3955094Slling 	switch (pd->pd_proptype) {
3965094Slling 	case PROP_TYPE_NUMBER:
3975094Slling 		/*
3985094Slling 		 * The maximum length of a human-readable number is 5 characters
3995094Slling 		 * ("20.4M", for example).
4005094Slling 		 */
4015094Slling 		if (ret < 5)
4025094Slling 			ret = 5;
4035094Slling 		/*
4045094Slling 		 * 'creation' is handled specially because it's a number
4055094Slling 		 * internally, but displayed as a date string.
4065094Slling 		 */
4075094Slling 		if (prop == ZFS_PROP_CREATION)
4085094Slling 			*fixed = B_FALSE;
4095094Slling 		break;
4105094Slling 	case PROP_TYPE_INDEX:
4115094Slling 		idx = prop_tbl[prop].pd_table;
4125094Slling 		for (i = 0; idx[i].pi_name != NULL; i++) {
4135094Slling 			if (strlen(idx[i].pi_name) > ret)
4145094Slling 				ret = strlen(idx[i].pi_name);
4155094Slling 		}
4165094Slling 		break;
4175094Slling 
4185094Slling 	case PROP_TYPE_STRING:
4195094Slling 		*fixed = B_FALSE;
4205094Slling 		break;
4215094Slling 	}
4225094Slling 
4235094Slling 	return (ret);
4245094Slling }
4255094Slling 
4265094Slling #endif
427