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