1 1.1 haad /* 2 1.1 haad * CDDL HEADER START 3 1.1 haad * 4 1.1 haad * The contents of this file are subject to the terms of the 5 1.1 haad * Common Development and Distribution License (the "License"). 6 1.1 haad * You may not use this file except in compliance with the License. 7 1.1 haad * 8 1.1 haad * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 1.1 haad * or http://www.opensolaris.org/os/licensing. 10 1.1 haad * See the License for the specific language governing permissions 11 1.1 haad * and limitations under the License. 12 1.1 haad * 13 1.1 haad * When distributing Covered Code, include this CDDL HEADER in each 14 1.1 haad * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 1.1 haad * If applicable, add the following below this CDDL HEADER, with the 16 1.1 haad * fields enclosed by brackets "[]" replaced with your own identifying 17 1.1 haad * information: Portions Copyright [yyyy] [name of copyright owner] 18 1.1 haad * 19 1.1 haad * CDDL HEADER END 20 1.1 haad */ 21 1.1 haad /* 22 1.2 chs * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 1.1 haad * Use is subject to license terms. 24 1.1 haad */ 25 1.2 chs /* 26 1.2 chs * Copyright (c) 2012 by Delphix. All rights reserved. 27 1.2 chs */ 28 1.1 haad 29 1.1 haad /* 30 1.1 haad * Common routines used by zfs and zpool property management. 31 1.1 haad */ 32 1.1 haad 33 1.1 haad #include <sys/zio.h> 34 1.1 haad #include <sys/spa.h> 35 1.1 haad #include <sys/zfs_acl.h> 36 1.1 haad #include <sys/zfs_ioctl.h> 37 1.1 haad #include <sys/zfs_znode.h> 38 1.1 haad #include <sys/fs/zfs.h> 39 1.1 haad 40 1.1 haad #include "zfs_prop.h" 41 1.1 haad #include "zfs_deleg.h" 42 1.1 haad 43 1.1 haad #if defined(_KERNEL) 44 1.1 haad #include <sys/systm.h> 45 1.2 chs #ifdef __FreeBSD__ 46 1.2 chs #include <sys/libkern.h> 47 1.2 chs #else 48 1.1 haad #include <util/qsort.h> 49 1.2 chs #endif 50 1.1 haad #else 51 1.1 haad #include <stdlib.h> 52 1.1 haad #include <string.h> 53 1.1 haad #include <ctype.h> 54 1.1 haad #endif 55 1.1 haad 56 1.1 haad static zprop_desc_t * 57 1.1 haad zprop_get_proptable(zfs_type_t type) 58 1.1 haad { 59 1.1 haad if (type == ZFS_TYPE_POOL) 60 1.1 haad return (zpool_prop_get_table()); 61 1.1 haad else 62 1.1 haad return (zfs_prop_get_table()); 63 1.1 haad } 64 1.1 haad 65 1.1 haad static int 66 1.1 haad zprop_get_numprops(zfs_type_t type) 67 1.1 haad { 68 1.1 haad if (type == ZFS_TYPE_POOL) 69 1.1 haad return (ZPOOL_NUM_PROPS); 70 1.1 haad else 71 1.1 haad return (ZFS_NUM_PROPS); 72 1.1 haad } 73 1.1 haad 74 1.1 haad void 75 1.2 chs zprop_register_impl(int prop, const char *name, zprop_type_t type, 76 1.1 haad uint64_t numdefault, const char *strdefault, zprop_attr_t attr, 77 1.1 haad int objset_types, const char *values, const char *colname, 78 1.1 haad boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl) 79 1.1 haad { 80 1.1 haad zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types); 81 1.1 haad zprop_desc_t *pd; 82 1.1 haad 83 1.1 haad pd = &prop_tbl[prop]; 84 1.1 haad 85 1.1 haad ASSERT(pd->pd_name == NULL || pd->pd_name == name); 86 1.2 chs ASSERT(name != NULL); 87 1.2 chs ASSERT(colname != NULL); 88 1.1 haad 89 1.1 haad pd->pd_name = name; 90 1.1 haad pd->pd_propnum = prop; 91 1.1 haad pd->pd_proptype = type; 92 1.1 haad pd->pd_numdefault = numdefault; 93 1.1 haad pd->pd_strdefault = strdefault; 94 1.1 haad pd->pd_attr = attr; 95 1.1 haad pd->pd_types = objset_types; 96 1.1 haad pd->pd_values = values; 97 1.1 haad pd->pd_colname = colname; 98 1.1 haad pd->pd_rightalign = rightalign; 99 1.1 haad pd->pd_visible = visible; 100 1.1 haad pd->pd_table = idx_tbl; 101 1.2 chs pd->pd_table_size = 0; 102 1.2 chs while (idx_tbl && (idx_tbl++)->pi_name != NULL) 103 1.2 chs pd->pd_table_size++; 104 1.1 haad } 105 1.1 haad 106 1.1 haad void 107 1.2 chs zprop_register_string(int prop, const char *name, const char *def, 108 1.1 haad zprop_attr_t attr, int objset_types, const char *values, 109 1.1 haad const char *colname) 110 1.1 haad { 111 1.2 chs zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr, 112 1.1 haad objset_types, values, colname, B_FALSE, B_TRUE, NULL); 113 1.1 haad 114 1.1 haad } 115 1.1 haad 116 1.1 haad void 117 1.2 chs zprop_register_number(int prop, const char *name, uint64_t def, 118 1.2 chs zprop_attr_t attr, int objset_types, const char *values, 119 1.2 chs const char *colname) 120 1.1 haad { 121 1.2 chs zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, 122 1.1 haad objset_types, values, colname, B_TRUE, B_TRUE, NULL); 123 1.1 haad } 124 1.1 haad 125 1.1 haad void 126 1.2 chs zprop_register_index(int prop, const char *name, uint64_t def, 127 1.2 chs zprop_attr_t attr, int objset_types, const char *values, 128 1.2 chs const char *colname, const zprop_index_t *idx_tbl) 129 1.1 haad { 130 1.2 chs zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, 131 1.1 haad objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl); 132 1.1 haad } 133 1.1 haad 134 1.1 haad void 135 1.2 chs zprop_register_hidden(int prop, const char *name, zprop_type_t type, 136 1.1 haad zprop_attr_t attr, int objset_types, const char *colname) 137 1.1 haad { 138 1.2 chs zprop_register_impl(prop, name, type, 0, NULL, attr, 139 1.2 chs objset_types, NULL, colname, 140 1.2 chs type == PROP_TYPE_NUMBER, B_FALSE, NULL); 141 1.1 haad } 142 1.1 haad 143 1.1 haad 144 1.1 haad /* 145 1.1 haad * A comparison function we can use to order indexes into property tables. 146 1.1 haad */ 147 1.1 haad static int 148 1.1 haad zprop_compare(const void *arg1, const void *arg2) 149 1.1 haad { 150 1.1 haad const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); 151 1.1 haad const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); 152 1.1 haad boolean_t p1ro, p2ro; 153 1.1 haad 154 1.1 haad p1ro = (p1->pd_attr == PROP_READONLY); 155 1.1 haad p2ro = (p2->pd_attr == PROP_READONLY); 156 1.1 haad 157 1.1 haad if (p1ro == p2ro) 158 1.1 haad return (strcmp(p1->pd_name, p2->pd_name)); 159 1.1 haad 160 1.1 haad return (p1ro ? -1 : 1); 161 1.1 haad } 162 1.1 haad 163 1.1 haad /* 164 1.1 haad * Iterate over all properties in the given property table, calling back 165 1.1 haad * into the specified function for each property. We will continue to 166 1.1 haad * iterate until we either reach the end or the callback function returns 167 1.1 haad * something other than ZPROP_CONT. 168 1.1 haad */ 169 1.1 haad int 170 1.1 haad zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, 171 1.1 haad boolean_t ordered, zfs_type_t type) 172 1.1 haad { 173 1.2 chs int i, j, num_props, size, prop; 174 1.1 haad zprop_desc_t *prop_tbl; 175 1.1 haad zprop_desc_t **order; 176 1.1 haad 177 1.1 haad prop_tbl = zprop_get_proptable(type); 178 1.1 haad num_props = zprop_get_numprops(type); 179 1.1 haad size = num_props * sizeof (zprop_desc_t *); 180 1.1 haad 181 1.1 haad #if defined(_KERNEL) 182 1.1 haad order = kmem_alloc(size, KM_SLEEP); 183 1.1 haad #else 184 1.1 haad if ((order = malloc(size)) == NULL) 185 1.1 haad return (ZPROP_CONT); 186 1.1 haad #endif 187 1.1 haad 188 1.2 chs for (j = 0; j < num_props; j++) 189 1.1 haad order[j] = &prop_tbl[j]; 190 1.1 haad 191 1.1 haad if (ordered) { 192 1.1 haad qsort((void *)order, num_props, sizeof (zprop_desc_t *), 193 1.1 haad zprop_compare); 194 1.1 haad } 195 1.1 haad 196 1.1 haad prop = ZPROP_CONT; 197 1.1 haad for (i = 0; i < num_props; i++) { 198 1.1 haad if ((order[i]->pd_visible || show_all) && 199 1.1 haad (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { 200 1.1 haad prop = order[i]->pd_propnum; 201 1.1 haad break; 202 1.1 haad } 203 1.1 haad } 204 1.1 haad 205 1.1 haad #if defined(_KERNEL) 206 1.1 haad kmem_free(order, size); 207 1.1 haad #else 208 1.1 haad free(order); 209 1.1 haad #endif 210 1.1 haad return (prop); 211 1.1 haad } 212 1.1 haad 213 1.1 haad static boolean_t 214 1.1 haad propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) 215 1.1 haad { 216 1.1 haad const char *propname = prop_entry->pd_name; 217 1.1 haad #ifndef _KERNEL 218 1.1 haad const char *colname = prop_entry->pd_colname; 219 1.1 haad int c; 220 1.1 haad #endif 221 1.1 haad 222 1.1 haad if (len == strlen(propname) && 223 1.1 haad strncmp(p, propname, len) == 0) 224 1.1 haad return (B_TRUE); 225 1.1 haad 226 1.1 haad #ifndef _KERNEL 227 1.2 chs if (colname == NULL || len != strlen(colname)) 228 1.1 haad return (B_FALSE); 229 1.1 haad 230 1.1 haad for (c = 0; c < len; c++) 231 1.1 haad if (p[c] != tolower(colname[c])) 232 1.1 haad break; 233 1.1 haad 234 1.1 haad return (colname[c] == '\0'); 235 1.1 haad #else 236 1.1 haad return (B_FALSE); 237 1.1 haad #endif 238 1.1 haad } 239 1.1 haad 240 1.1 haad typedef struct name_to_prop_cb { 241 1.1 haad const char *propname; 242 1.1 haad zprop_desc_t *prop_tbl; 243 1.1 haad } name_to_prop_cb_t; 244 1.1 haad 245 1.1 haad static int 246 1.1 haad zprop_name_to_prop_cb(int prop, void *cb_data) 247 1.1 haad { 248 1.1 haad name_to_prop_cb_t *data = cb_data; 249 1.1 haad 250 1.1 haad if (propname_match(data->propname, strlen(data->propname), 251 1.1 haad &data->prop_tbl[prop])) 252 1.1 haad return (prop); 253 1.1 haad 254 1.1 haad return (ZPROP_CONT); 255 1.1 haad } 256 1.1 haad 257 1.1 haad int 258 1.1 haad zprop_name_to_prop(const char *propname, zfs_type_t type) 259 1.1 haad { 260 1.1 haad int prop; 261 1.1 haad name_to_prop_cb_t cb_data; 262 1.1 haad 263 1.1 haad cb_data.propname = propname; 264 1.1 haad cb_data.prop_tbl = zprop_get_proptable(type); 265 1.1 haad 266 1.1 haad prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data, 267 1.1 haad B_TRUE, B_FALSE, type); 268 1.1 haad 269 1.1 haad return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 270 1.1 haad } 271 1.1 haad 272 1.1 haad int 273 1.1 haad zprop_string_to_index(int prop, const char *string, uint64_t *index, 274 1.1 haad zfs_type_t type) 275 1.1 haad { 276 1.1 haad zprop_desc_t *prop_tbl; 277 1.1 haad const zprop_index_t *idx_tbl; 278 1.1 haad int i; 279 1.1 haad 280 1.1 haad if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 281 1.1 haad return (-1); 282 1.1 haad 283 1.1 haad ASSERT(prop < zprop_get_numprops(type)); 284 1.1 haad prop_tbl = zprop_get_proptable(type); 285 1.1 haad if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 286 1.1 haad return (-1); 287 1.1 haad 288 1.1 haad for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 289 1.1 haad if (strcmp(string, idx_tbl[i].pi_name) == 0) { 290 1.1 haad *index = idx_tbl[i].pi_value; 291 1.1 haad return (0); 292 1.1 haad } 293 1.1 haad } 294 1.1 haad 295 1.1 haad return (-1); 296 1.1 haad } 297 1.1 haad 298 1.1 haad int 299 1.1 haad zprop_index_to_string(int prop, uint64_t index, const char **string, 300 1.1 haad zfs_type_t type) 301 1.1 haad { 302 1.1 haad zprop_desc_t *prop_tbl; 303 1.1 haad const zprop_index_t *idx_tbl; 304 1.1 haad int i; 305 1.1 haad 306 1.1 haad if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 307 1.1 haad return (-1); 308 1.1 haad 309 1.1 haad ASSERT(prop < zprop_get_numprops(type)); 310 1.1 haad prop_tbl = zprop_get_proptable(type); 311 1.1 haad if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 312 1.1 haad return (-1); 313 1.1 haad 314 1.1 haad for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 315 1.1 haad if (idx_tbl[i].pi_value == index) { 316 1.1 haad *string = idx_tbl[i].pi_name; 317 1.1 haad return (0); 318 1.1 haad } 319 1.1 haad } 320 1.1 haad 321 1.1 haad return (-1); 322 1.1 haad } 323 1.1 haad 324 1.2 chs /* 325 1.2 chs * Return a random valid property value. Used by ztest. 326 1.2 chs */ 327 1.2 chs uint64_t 328 1.2 chs zprop_random_value(int prop, uint64_t seed, zfs_type_t type) 329 1.2 chs { 330 1.2 chs zprop_desc_t *prop_tbl; 331 1.2 chs const zprop_index_t *idx_tbl; 332 1.2 chs 333 1.2 chs ASSERT((uint_t)prop < zprop_get_numprops(type)); 334 1.2 chs prop_tbl = zprop_get_proptable(type); 335 1.2 chs idx_tbl = prop_tbl[prop].pd_table; 336 1.2 chs 337 1.2 chs if (idx_tbl == NULL) 338 1.2 chs return (seed); 339 1.2 chs 340 1.2 chs return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value); 341 1.2 chs } 342 1.2 chs 343 1.1 haad const char * 344 1.1 haad zprop_values(int prop, zfs_type_t type) 345 1.1 haad { 346 1.1 haad zprop_desc_t *prop_tbl; 347 1.1 haad 348 1.1 haad ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 349 1.1 haad ASSERT(prop < zprop_get_numprops(type)); 350 1.1 haad 351 1.1 haad prop_tbl = zprop_get_proptable(type); 352 1.1 haad 353 1.1 haad return (prop_tbl[prop].pd_values); 354 1.1 haad } 355 1.1 haad 356 1.1 haad /* 357 1.1 haad * Returns TRUE if the property applies to any of the given dataset types. 358 1.1 haad */ 359 1.1 haad boolean_t 360 1.1 haad zprop_valid_for_type(int prop, zfs_type_t type) 361 1.1 haad { 362 1.1 haad zprop_desc_t *prop_tbl; 363 1.1 haad 364 1.1 haad if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 365 1.1 haad return (B_FALSE); 366 1.1 haad 367 1.1 haad ASSERT(prop < zprop_get_numprops(type)); 368 1.1 haad prop_tbl = zprop_get_proptable(type); 369 1.1 haad return ((prop_tbl[prop].pd_types & type) != 0); 370 1.1 haad } 371 1.1 haad 372 1.1 haad #ifndef _KERNEL 373 1.1 haad 374 1.1 haad /* 375 1.1 haad * Determines the minimum width for the column, and indicates whether it's fixed 376 1.1 haad * or not. Only string columns are non-fixed. 377 1.1 haad */ 378 1.1 haad size_t 379 1.1 haad zprop_width(int prop, boolean_t *fixed, zfs_type_t type) 380 1.1 haad { 381 1.1 haad zprop_desc_t *prop_tbl, *pd; 382 1.1 haad const zprop_index_t *idx; 383 1.1 haad size_t ret; 384 1.1 haad int i; 385 1.1 haad 386 1.1 haad ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 387 1.1 haad ASSERT(prop < zprop_get_numprops(type)); 388 1.1 haad 389 1.1 haad prop_tbl = zprop_get_proptable(type); 390 1.1 haad pd = &prop_tbl[prop]; 391 1.1 haad 392 1.1 haad *fixed = B_TRUE; 393 1.1 haad 394 1.1 haad /* 395 1.1 haad * Start with the width of the column name. 396 1.1 haad */ 397 1.1 haad ret = strlen(pd->pd_colname); 398 1.1 haad 399 1.1 haad /* 400 1.1 haad * For fixed-width values, make sure the width is large enough to hold 401 1.1 haad * any possible value. 402 1.1 haad */ 403 1.1 haad switch (pd->pd_proptype) { 404 1.1 haad case PROP_TYPE_NUMBER: 405 1.1 haad /* 406 1.1 haad * The maximum length of a human-readable number is 5 characters 407 1.1 haad * ("20.4M", for example). 408 1.1 haad */ 409 1.1 haad if (ret < 5) 410 1.1 haad ret = 5; 411 1.1 haad /* 412 1.1 haad * 'creation' is handled specially because it's a number 413 1.1 haad * internally, but displayed as a date string. 414 1.1 haad */ 415 1.1 haad if (prop == ZFS_PROP_CREATION) 416 1.1 haad *fixed = B_FALSE; 417 1.1 haad break; 418 1.1 haad case PROP_TYPE_INDEX: 419 1.1 haad idx = prop_tbl[prop].pd_table; 420 1.1 haad for (i = 0; idx[i].pi_name != NULL; i++) { 421 1.1 haad if (strlen(idx[i].pi_name) > ret) 422 1.1 haad ret = strlen(idx[i].pi_name); 423 1.1 haad } 424 1.1 haad break; 425 1.1 haad 426 1.1 haad case PROP_TYPE_STRING: 427 1.1 haad *fixed = B_FALSE; 428 1.1 haad break; 429 1.1 haad } 430 1.1 haad 431 1.1 haad return (ret); 432 1.1 haad } 433 1.1 haad 434 1.1 haad #endif 435