1990b4856Slling /* 2990b4856Slling * CDDL HEADER START 3990b4856Slling * 4990b4856Slling * The contents of this file are subject to the terms of the 5990b4856Slling * Common Development and Distribution License (the "License"). 6990b4856Slling * You may not use this file except in compliance with the License. 7990b4856Slling * 8990b4856Slling * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9990b4856Slling * or http://www.opensolaris.org/os/licensing. 10990b4856Slling * See the License for the specific language governing permissions 11990b4856Slling * and limitations under the License. 12990b4856Slling * 13990b4856Slling * When distributing Covered Code, include this CDDL HEADER in each 14990b4856Slling * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15990b4856Slling * If applicable, add the following below this CDDL HEADER, with the 16990b4856Slling * fields enclosed by brackets "[]" replaced with your own identifying 17990b4856Slling * information: Portions Copyright [yyyy] [name of copyright owner] 18990b4856Slling * 19990b4856Slling * CDDL HEADER END 20990b4856Slling */ 21990b4856Slling /* 2283d7f9feSTom Erickson * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23990b4856Slling * Use is subject to license terms. 24990b4856Slling */ 25*4445fffbSMatthew Ahrens /* 26*4445fffbSMatthew Ahrens * Copyright (c) 2012 by Delphix. All rights reserved. 27*4445fffbSMatthew Ahrens */ 28990b4856Slling 29990b4856Slling /* 30990b4856Slling * Common routines used by zfs and zpool property management. 31990b4856Slling */ 32990b4856Slling 33990b4856Slling #include <sys/zio.h> 34990b4856Slling #include <sys/spa.h> 35990b4856Slling #include <sys/zfs_acl.h> 36990b4856Slling #include <sys/zfs_ioctl.h> 37990b4856Slling #include <sys/zfs_znode.h> 38990b4856Slling #include <sys/fs/zfs.h> 39990b4856Slling 40990b4856Slling #include "zfs_prop.h" 41990b4856Slling #include "zfs_deleg.h" 42990b4856Slling 43990b4856Slling #if defined(_KERNEL) 44990b4856Slling #include <sys/systm.h> 45990b4856Slling #include <util/qsort.h> 46990b4856Slling #else 47990b4856Slling #include <stdlib.h> 48990b4856Slling #include <string.h> 49990b4856Slling #include <ctype.h> 50990b4856Slling #endif 51990b4856Slling 52990b4856Slling static zprop_desc_t * 53990b4856Slling zprop_get_proptable(zfs_type_t type) 54990b4856Slling { 55990b4856Slling if (type == ZFS_TYPE_POOL) 56990b4856Slling return (zpool_prop_get_table()); 57990b4856Slling else 58990b4856Slling return (zfs_prop_get_table()); 59990b4856Slling } 60990b4856Slling 61990b4856Slling static int 62990b4856Slling zprop_get_numprops(zfs_type_t type) 63990b4856Slling { 64990b4856Slling if (type == ZFS_TYPE_POOL) 65990b4856Slling return (ZPOOL_NUM_PROPS); 66990b4856Slling else 67990b4856Slling return (ZFS_NUM_PROPS); 68990b4856Slling } 69990b4856Slling 70990b4856Slling void 7183d7f9feSTom Erickson zprop_register_impl(int prop, const char *name, zprop_type_t type, 72990b4856Slling uint64_t numdefault, const char *strdefault, zprop_attr_t attr, 73990b4856Slling int objset_types, const char *values, const char *colname, 74990b4856Slling boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl) 75990b4856Slling { 76990b4856Slling zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types); 77990b4856Slling zprop_desc_t *pd; 78990b4856Slling 79990b4856Slling pd = &prop_tbl[prop]; 80990b4856Slling 81990b4856Slling ASSERT(pd->pd_name == NULL || pd->pd_name == name); 82b24ab676SJeff Bonwick ASSERT(name != NULL); 83b24ab676SJeff Bonwick ASSERT(colname != NULL); 84990b4856Slling 85990b4856Slling pd->pd_name = name; 86990b4856Slling pd->pd_propnum = prop; 87990b4856Slling pd->pd_proptype = type; 88990b4856Slling pd->pd_numdefault = numdefault; 89990b4856Slling pd->pd_strdefault = strdefault; 90990b4856Slling pd->pd_attr = attr; 91990b4856Slling pd->pd_types = objset_types; 92990b4856Slling pd->pd_values = values; 93990b4856Slling pd->pd_colname = colname; 94990b4856Slling pd->pd_rightalign = rightalign; 95990b4856Slling pd->pd_visible = visible; 96990b4856Slling pd->pd_table = idx_tbl; 97b24ab676SJeff Bonwick pd->pd_table_size = 0; 98b24ab676SJeff Bonwick while (idx_tbl && (idx_tbl++)->pi_name != NULL) 99b24ab676SJeff Bonwick pd->pd_table_size++; 100990b4856Slling } 101990b4856Slling 102990b4856Slling void 10383d7f9feSTom Erickson zprop_register_string(int prop, const char *name, const char *def, 104990b4856Slling zprop_attr_t attr, int objset_types, const char *values, 105990b4856Slling const char *colname) 106990b4856Slling { 10783d7f9feSTom Erickson zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr, 108990b4856Slling objset_types, values, colname, B_FALSE, B_TRUE, NULL); 109990b4856Slling 110990b4856Slling } 111990b4856Slling 112990b4856Slling void 11383d7f9feSTom Erickson zprop_register_number(int prop, const char *name, uint64_t def, 11483d7f9feSTom Erickson zprop_attr_t attr, int objset_types, const char *values, 11583d7f9feSTom Erickson const char *colname) 116990b4856Slling { 11783d7f9feSTom Erickson zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, 118990b4856Slling objset_types, values, colname, B_TRUE, B_TRUE, NULL); 119990b4856Slling } 120990b4856Slling 121990b4856Slling void 12283d7f9feSTom Erickson zprop_register_index(int prop, const char *name, uint64_t def, 12383d7f9feSTom Erickson zprop_attr_t attr, int objset_types, const char *values, 12483d7f9feSTom Erickson const char *colname, const zprop_index_t *idx_tbl) 125990b4856Slling { 12683d7f9feSTom Erickson zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, 127990b4856Slling objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl); 128990b4856Slling } 129990b4856Slling 130990b4856Slling void 13183d7f9feSTom Erickson zprop_register_hidden(int prop, const char *name, zprop_type_t type, 132990b4856Slling zprop_attr_t attr, int objset_types, const char *colname) 133990b4856Slling { 13483d7f9feSTom Erickson zprop_register_impl(prop, name, type, 0, NULL, attr, 135*4445fffbSMatthew Ahrens objset_types, NULL, colname, 136*4445fffbSMatthew Ahrens type == PROP_TYPE_NUMBER, B_FALSE, NULL); 137990b4856Slling } 138990b4856Slling 139990b4856Slling 140990b4856Slling /* 141990b4856Slling * A comparison function we can use to order indexes into property tables. 142990b4856Slling */ 143990b4856Slling static int 144990b4856Slling zprop_compare(const void *arg1, const void *arg2) 145990b4856Slling { 146990b4856Slling const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); 147990b4856Slling const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); 148990b4856Slling boolean_t p1ro, p2ro; 149990b4856Slling 150990b4856Slling p1ro = (p1->pd_attr == PROP_READONLY); 151990b4856Slling p2ro = (p2->pd_attr == PROP_READONLY); 152990b4856Slling 153990b4856Slling if (p1ro == p2ro) 154990b4856Slling return (strcmp(p1->pd_name, p2->pd_name)); 155990b4856Slling 156990b4856Slling return (p1ro ? -1 : 1); 157990b4856Slling } 158990b4856Slling 159990b4856Slling /* 160990b4856Slling * Iterate over all properties in the given property table, calling back 161990b4856Slling * into the specified function for each property. We will continue to 162990b4856Slling * iterate until we either reach the end or the callback function returns 163990b4856Slling * something other than ZPROP_CONT. 164990b4856Slling */ 165990b4856Slling int 166990b4856Slling zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, 167990b4856Slling boolean_t ordered, zfs_type_t type) 168990b4856Slling { 169990b4856Slling int i, num_props, size, prop; 170990b4856Slling zprop_desc_t *prop_tbl; 171990b4856Slling zprop_desc_t **order; 172990b4856Slling 173990b4856Slling prop_tbl = zprop_get_proptable(type); 174990b4856Slling num_props = zprop_get_numprops(type); 175990b4856Slling size = num_props * sizeof (zprop_desc_t *); 176990b4856Slling 177990b4856Slling #if defined(_KERNEL) 178990b4856Slling order = kmem_alloc(size, KM_SLEEP); 179990b4856Slling #else 180990b4856Slling if ((order = malloc(size)) == NULL) 181990b4856Slling return (ZPROP_CONT); 182990b4856Slling #endif 183990b4856Slling 184990b4856Slling for (int j = 0; j < num_props; j++) 185990b4856Slling order[j] = &prop_tbl[j]; 186990b4856Slling 187990b4856Slling if (ordered) { 188990b4856Slling qsort((void *)order, num_props, sizeof (zprop_desc_t *), 189990b4856Slling zprop_compare); 190990b4856Slling } 191990b4856Slling 192990b4856Slling prop = ZPROP_CONT; 193990b4856Slling for (i = 0; i < num_props; i++) { 194990b4856Slling if ((order[i]->pd_visible || show_all) && 195990b4856Slling (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { 196990b4856Slling prop = order[i]->pd_propnum; 197990b4856Slling break; 198990b4856Slling } 199990b4856Slling } 200990b4856Slling 201990b4856Slling #if defined(_KERNEL) 202990b4856Slling kmem_free(order, size); 203990b4856Slling #else 204990b4856Slling free(order); 205990b4856Slling #endif 206990b4856Slling return (prop); 207990b4856Slling } 208990b4856Slling 209990b4856Slling static boolean_t 210990b4856Slling propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) 211990b4856Slling { 212990b4856Slling const char *propname = prop_entry->pd_name; 213990b4856Slling #ifndef _KERNEL 214990b4856Slling const char *colname = prop_entry->pd_colname; 215990b4856Slling int c; 216990b4856Slling #endif 217990b4856Slling 218990b4856Slling if (len == strlen(propname) && 219990b4856Slling strncmp(p, propname, len) == 0) 220990b4856Slling return (B_TRUE); 221990b4856Slling 222990b4856Slling #ifndef _KERNEL 22314843421SMatthew Ahrens if (colname == NULL || len != strlen(colname)) 224990b4856Slling return (B_FALSE); 225990b4856Slling 226990b4856Slling for (c = 0; c < len; c++) 227990b4856Slling if (p[c] != tolower(colname[c])) 228990b4856Slling break; 229990b4856Slling 230990b4856Slling return (colname[c] == '\0'); 231990b4856Slling #else 232990b4856Slling return (B_FALSE); 233990b4856Slling #endif 234990b4856Slling } 235990b4856Slling 236990b4856Slling typedef struct name_to_prop_cb { 237990b4856Slling const char *propname; 238990b4856Slling zprop_desc_t *prop_tbl; 239990b4856Slling } name_to_prop_cb_t; 240990b4856Slling 241990b4856Slling static int 242990b4856Slling zprop_name_to_prop_cb(int prop, void *cb_data) 243990b4856Slling { 244990b4856Slling name_to_prop_cb_t *data = cb_data; 245990b4856Slling 246990b4856Slling if (propname_match(data->propname, strlen(data->propname), 247990b4856Slling &data->prop_tbl[prop])) 248990b4856Slling return (prop); 249990b4856Slling 250990b4856Slling return (ZPROP_CONT); 251990b4856Slling } 252990b4856Slling 253990b4856Slling int 254990b4856Slling zprop_name_to_prop(const char *propname, zfs_type_t type) 255990b4856Slling { 256990b4856Slling int prop; 257990b4856Slling name_to_prop_cb_t cb_data; 258990b4856Slling 259990b4856Slling cb_data.propname = propname; 260990b4856Slling cb_data.prop_tbl = zprop_get_proptable(type); 261990b4856Slling 262990b4856Slling prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data, 263990b4856Slling B_TRUE, B_FALSE, type); 264990b4856Slling 265990b4856Slling return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 266990b4856Slling } 267990b4856Slling 268990b4856Slling int 269990b4856Slling zprop_string_to_index(int prop, const char *string, uint64_t *index, 270990b4856Slling zfs_type_t type) 271990b4856Slling { 272990b4856Slling zprop_desc_t *prop_tbl; 273990b4856Slling const zprop_index_t *idx_tbl; 274990b4856Slling int i; 275990b4856Slling 27679912923Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 27779912923Sgw25295 return (-1); 27879912923Sgw25295 27979912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 280990b4856Slling prop_tbl = zprop_get_proptable(type); 281990b4856Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 282990b4856Slling return (-1); 283990b4856Slling 284990b4856Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 285990b4856Slling if (strcmp(string, idx_tbl[i].pi_name) == 0) { 286990b4856Slling *index = idx_tbl[i].pi_value; 287990b4856Slling return (0); 288990b4856Slling } 289990b4856Slling } 290990b4856Slling 291990b4856Slling return (-1); 292990b4856Slling } 293990b4856Slling 294990b4856Slling int 295990b4856Slling zprop_index_to_string(int prop, uint64_t index, const char **string, 296990b4856Slling zfs_type_t type) 297990b4856Slling { 298990b4856Slling zprop_desc_t *prop_tbl; 299990b4856Slling const zprop_index_t *idx_tbl; 300990b4856Slling int i; 301990b4856Slling 30279912923Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 30379912923Sgw25295 return (-1); 30479912923Sgw25295 30579912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 306990b4856Slling prop_tbl = zprop_get_proptable(type); 307990b4856Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 308990b4856Slling return (-1); 309990b4856Slling 310990b4856Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 311990b4856Slling if (idx_tbl[i].pi_value == index) { 312990b4856Slling *string = idx_tbl[i].pi_name; 313990b4856Slling return (0); 314990b4856Slling } 315990b4856Slling } 316990b4856Slling 317990b4856Slling return (-1); 318990b4856Slling } 319990b4856Slling 320b24ab676SJeff Bonwick /* 321b24ab676SJeff Bonwick * Return a random valid property value. Used by ztest. 322b24ab676SJeff Bonwick */ 323b24ab676SJeff Bonwick uint64_t 324b24ab676SJeff Bonwick zprop_random_value(int prop, uint64_t seed, zfs_type_t type) 325b24ab676SJeff Bonwick { 326b24ab676SJeff Bonwick zprop_desc_t *prop_tbl; 327b24ab676SJeff Bonwick const zprop_index_t *idx_tbl; 328b24ab676SJeff Bonwick 329b24ab676SJeff Bonwick ASSERT((uint_t)prop < zprop_get_numprops(type)); 330b24ab676SJeff Bonwick prop_tbl = zprop_get_proptable(type); 331b24ab676SJeff Bonwick idx_tbl = prop_tbl[prop].pd_table; 332b24ab676SJeff Bonwick 333b24ab676SJeff Bonwick if (idx_tbl == NULL) 334b24ab676SJeff Bonwick return (seed); 335b24ab676SJeff Bonwick 336b24ab676SJeff Bonwick return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value); 337b24ab676SJeff Bonwick } 338b24ab676SJeff Bonwick 339990b4856Slling const char * 340990b4856Slling zprop_values(int prop, zfs_type_t type) 341990b4856Slling { 342990b4856Slling zprop_desc_t *prop_tbl; 343990b4856Slling 34479912923Sgw25295 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 34579912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 34679912923Sgw25295 347990b4856Slling prop_tbl = zprop_get_proptable(type); 348990b4856Slling 349990b4856Slling return (prop_tbl[prop].pd_values); 350990b4856Slling } 351990b4856Slling 352990b4856Slling /* 353990b4856Slling * Returns TRUE if the property applies to any of the given dataset types. 354990b4856Slling */ 35579912923Sgw25295 boolean_t 356990b4856Slling zprop_valid_for_type(int prop, zfs_type_t type) 357990b4856Slling { 35879912923Sgw25295 zprop_desc_t *prop_tbl; 359990b4856Slling 36079912923Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 36179912923Sgw25295 return (B_FALSE); 36279912923Sgw25295 36379912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 36479912923Sgw25295 prop_tbl = zprop_get_proptable(type); 365990b4856Slling return ((prop_tbl[prop].pd_types & type) != 0); 366990b4856Slling } 367990b4856Slling 368990b4856Slling #ifndef _KERNEL 369990b4856Slling 370990b4856Slling /* 371990b4856Slling * Determines the minimum width for the column, and indicates whether it's fixed 372990b4856Slling * or not. Only string columns are non-fixed. 373990b4856Slling */ 374990b4856Slling size_t 375990b4856Slling zprop_width(int prop, boolean_t *fixed, zfs_type_t type) 376990b4856Slling { 377990b4856Slling zprop_desc_t *prop_tbl, *pd; 378990b4856Slling const zprop_index_t *idx; 379990b4856Slling size_t ret; 380990b4856Slling int i; 381990b4856Slling 38279912923Sgw25295 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 38379912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 38479912923Sgw25295 385990b4856Slling prop_tbl = zprop_get_proptable(type); 386990b4856Slling pd = &prop_tbl[prop]; 387990b4856Slling 388990b4856Slling *fixed = B_TRUE; 389990b4856Slling 390990b4856Slling /* 391990b4856Slling * Start with the width of the column name. 392990b4856Slling */ 393990b4856Slling ret = strlen(pd->pd_colname); 394990b4856Slling 395990b4856Slling /* 396990b4856Slling * For fixed-width values, make sure the width is large enough to hold 397990b4856Slling * any possible value. 398990b4856Slling */ 399990b4856Slling switch (pd->pd_proptype) { 400990b4856Slling case PROP_TYPE_NUMBER: 401990b4856Slling /* 402990b4856Slling * The maximum length of a human-readable number is 5 characters 403990b4856Slling * ("20.4M", for example). 404990b4856Slling */ 405990b4856Slling if (ret < 5) 406990b4856Slling ret = 5; 407990b4856Slling /* 408990b4856Slling * 'creation' is handled specially because it's a number 409990b4856Slling * internally, but displayed as a date string. 410990b4856Slling */ 411990b4856Slling if (prop == ZFS_PROP_CREATION) 412990b4856Slling *fixed = B_FALSE; 413990b4856Slling break; 414990b4856Slling case PROP_TYPE_INDEX: 415990b4856Slling idx = prop_tbl[prop].pd_table; 416990b4856Slling for (i = 0; idx[i].pi_name != NULL; i++) { 417990b4856Slling if (strlen(idx[i].pi_name) > ret) 418990b4856Slling ret = strlen(idx[i].pi_name); 419990b4856Slling } 420990b4856Slling break; 421990b4856Slling 422990b4856Slling case PROP_TYPE_STRING: 423990b4856Slling *fixed = B_FALSE; 424990b4856Slling break; 425990b4856Slling } 426990b4856Slling 427990b4856Slling return (ret); 428990b4856Slling } 429990b4856Slling 430990b4856Slling #endif 431