zfeature_common.c revision 268658
143105Sdfr/* 243105Sdfr * CDDL HEADER START 343105Sdfr * 443105Sdfr * The contents of this file are subject to the terms of the 543105Sdfr * Common Development and Distribution License (the "License"). 643105Sdfr * You may not use this file except in compliance with the License. 743105Sdfr * 843105Sdfr * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 943105Sdfr * or http://www.opensolaris.org/os/licensing. 1043105Sdfr * See the License for the specific language governing permissions 1143105Sdfr * and limitations under the License. 1243105Sdfr * 1343105Sdfr * When distributing Covered Code, include this CDDL HEADER in each 1443105Sdfr * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1543105Sdfr * If applicable, add the following below this CDDL HEADER, with the 1643105Sdfr * fields enclosed by brackets "[]" replaced with your own identifying 1743105Sdfr * information: Portions Copyright [yyyy] [name of copyright owner] 1843105Sdfr * 1943105Sdfr * CDDL HEADER END 2043105Sdfr */ 2143105Sdfr 2243105Sdfr/* 2343105Sdfr * Copyright (c) 2013 by Delphix. All rights reserved. 2443105Sdfr * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 2543105Sdfr * Copyright (c) 2013, Joyent, Inc. All rights reserved. 2643105Sdfr * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. 27116181Sobrien */ 28116181Sobrien 29116181Sobrien#ifdef _KERNEL 3043105Sdfr#include <sys/systm.h> 3143105Sdfr#else 3243105Sdfr#include <errno.h> 3343105Sdfr#include <string.h> 3443105Sdfr#endif 3543105Sdfr#include <sys/debug.h> 3643105Sdfr#include <sys/fs/zfs.h> 3749558Sphk#include <sys/types.h> 3866834Sphk#include "zfeature_common.h" 3966834Sphk 40109279Smdodd/* 4143105Sdfr * Set to disable all feature checks while opening pools, allowing pools with 42135690Speter * unsupported features to be opened. Set for testing only. 4343105Sdfr */ 4448104Syokotaboolean_t zfeature_checks_disable = B_FALSE; 4548104Syokota 46146211Snyanzfeature_info_t spa_feature_table[SPA_FEATURES]; 47146211Snyan 4848104Syokota/* 4948104Syokota * Valid characters for feature guids. This list is mainly for aesthetic 5048104Syokota * purposes and could be expanded in the future. There are different allowed 5148104Syokota * characters in the guids reverse dns portion (before the colon) and its 52130312Sjhb * short name (after the colon). 5348104Syokota */ 5448104Syokotastatic int 5548104Syokotavalid_char(char c, boolean_t after_colon) 5648104Syokota{ 5748104Syokota return ((c >= 'a' && c <= 'z') || 5848104Syokota (c >= '0' && c <= '9') || 59135690Speter c == (after_colon ? '_' : '.')); 6048104Syokota} 6143105Sdfr 6243105Sdfr/* 6343105Sdfr * Every feature guid must contain exactly one colon which separates a reverse 6443105Sdfr * dns organization name from the feature's "short" name (e.g. 6548104Syokota * "com.company:feature_name"). 6643105Sdfr */ 6762225Speterboolean_t 68109279Smdoddzfeature_is_valid_guid(const char *name) 69109279Smdodd{ 70109279Smdodd int i; 71109279Smdodd boolean_t has_colon = B_FALSE; 72109279Smdodd 73109279Smdodd i = 0; 7443105Sdfr while (name[i] != '\0') { 75109279Smdodd char c = name[i++]; 76109279Smdodd if (c == ':') { 77109279Smdodd if (has_colon) 78109279Smdodd return (B_FALSE); 79109279Smdodd has_colon = B_TRUE; 8062225Speter continue; 8162225Speter } 8262225Speter if (!valid_char(c, has_colon)) 8362225Speter return (B_FALSE); 8462225Speter } 8543105Sdfr 8643105Sdfr return (has_colon); 8743105Sdfr} 8843105Sdfr 8947618Sdfrboolean_t 9047618Sdfrzfeature_is_supported(const char *guid) 9147618Sdfr{ 9247618Sdfr if (zfeature_checks_disable) 9343105Sdfr return (B_TRUE); 9451052Sdfr 9543105Sdfr for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 9643105Sdfr zfeature_info_t *feature = &spa_feature_table[i]; 9743105Sdfr if (strcmp(guid, feature->fi_guid) == 0) 9843105Sdfr return (B_TRUE); 9943105Sdfr } 10051052Sdfr return (B_FALSE); 10143105Sdfr} 10243105Sdfr 103102418Siwasakiint 104102418Siwasakizfeature_lookup_name(const char *name, spa_feature_t *res) 105102418Siwasaki{ 106102418Siwasaki for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 107102418Siwasaki zfeature_info_t *feature = &spa_feature_table[i]; 108102418Siwasaki if (strcmp(name, feature->fi_uname) == 0) { 109102418Siwasaki if (res != NULL) 110102418Siwasaki *res = i; 111121704Snjl return (0); 112121704Snjl } 113121704Snjl } 114121704Snjl 115102418Siwasaki return (ENOENT); 116109279Smdodd} 117109279Smdodd 118109279Smdoddboolean_t 119109279Smdoddzfeature_depends_on(spa_feature_t fid, spa_feature_t check) { 120102418Siwasaki zfeature_info_t *feature = &spa_feature_table[fid]; 121102418Siwasaki 122102418Siwasaki for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) { 123102418Siwasaki if (feature->fi_depends[i] == check) 124102418Siwasaki return (B_TRUE); 125102418Siwasaki } 126102418Siwasaki return (B_FALSE); 127102418Siwasaki} 128102418Siwasaki 129102418Siwasakistatic void 130102418Siwasakizfeature_register(spa_feature_t fid, const char *guid, const char *name, 131102418Siwasaki const char *desc, boolean_t readonly, boolean_t mos, 132102418Siwasaki boolean_t activate_on_enable, const spa_feature_t *deps) 133102418Siwasaki{ 134102418Siwasaki zfeature_info_t *feature = &spa_feature_table[fid]; 135102418Siwasaki static spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 136109279Smdodd 137109279Smdodd ASSERT(name != NULL); 138109279Smdodd ASSERT(desc != NULL); 139102418Siwasaki ASSERT(!readonly || !mos); 140102418Siwasaki ASSERT3U(fid, <, SPA_FEATURES); 141102418Siwasaki ASSERT(zfeature_is_valid_guid(guid)); 142102418Siwasaki 143102418Siwasaki if (deps == NULL) 144102418Siwasaki deps = nodeps; 14548104Syokota 14648104Syokota feature->fi_feature = fid; 14748104Syokota feature->fi_guid = guid; 14848104Syokota feature->fi_uname = name; 14948104Syokota feature->fi_desc = desc; 15048104Syokota feature->fi_can_readonly = readonly; 15148104Syokota feature->fi_mos = mos; 15248104Syokota feature->fi_activate_on_enable = activate_on_enable; 15348104Syokota feature->fi_depends = deps; 15448104Syokota} 15548104Syokota 15656836Spetervoid 15748104Syokotazpool_feature_init(void) 15848104Syokota{ 15948104Syokota zfeature_register(SPA_FEATURE_ASYNC_DESTROY, 16055849Syokota "com.delphix:async_destroy", "async_destroy", 16148104Syokota "Destroy filesystems asynchronously.", B_TRUE, B_FALSE, 16248183Syokota B_FALSE, NULL); 16356836Speter 16456836Speter zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, 16548104Syokota "com.delphix:empty_bpobj", "empty_bpobj", 16655849Syokota "Snapshots use less space.", B_TRUE, B_FALSE, 16755849Syokota B_FALSE, NULL); 16855849Syokota 16955849Syokota zfeature_register(SPA_FEATURE_LZ4_COMPRESS, 17058872Syokota "org.illumos:lz4_compress", "lz4_compress", 17155849Syokota "LZ4 compression algorithm support.", B_FALSE, B_FALSE, 17255849Syokota B_TRUE, NULL); 17355849Syokota 17448104Syokota zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, 17548104Syokota "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump", 17648104Syokota "Crash dumps to multiple vdev pools.", B_FALSE, B_FALSE, 17748104Syokota B_FALSE, NULL); 17848104Syokota 17948104Syokota zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, 18048104Syokota "com.delphix:spacemap_histogram", "spacemap_histogram", 18148104Syokota "Spacemaps maintain space histograms.", B_TRUE, B_FALSE, 18248104Syokota B_FALSE, NULL); 18348104Syokota 18448104Syokota zfeature_register(SPA_FEATURE_ENABLED_TXG, 18548104Syokota "com.delphix:enabled_txg", "enabled_txg", 18648104Syokota "Record txg at which a feature is enabled", B_TRUE, B_FALSE, 18748104Syokota B_FALSE, NULL); 18848104Syokota 18948183Syokota static spa_feature_t hole_birth_deps[] = { SPA_FEATURE_ENABLED_TXG, 19048104Syokota SPA_FEATURE_NONE }; 19148104Syokota zfeature_register(SPA_FEATURE_HOLE_BIRTH, 19248104Syokota "com.delphix:hole_birth", "hole_birth", 19348104Syokota "Retain hole birth txg for more precise zfs send", 19448104Syokota B_FALSE, B_TRUE, B_TRUE, hole_birth_deps); 19548104Syokota 19648104Syokota zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET, 19748104Syokota "com.delphix:extensible_dataset", "extensible_dataset", 19848104Syokota "Enhanced dataset functionality, used by other features.", 19948104Syokota B_FALSE, B_FALSE, B_FALSE, NULL); 20048104Syokota 20148104Syokota static const spa_feature_t bookmarks_deps[] = { 20278262Speter SPA_FEATURE_EXTENSIBLE_DATASET, 20348104Syokota SPA_FEATURE_NONE 20448104Syokota }; 20548104Syokota zfeature_register(SPA_FEATURE_BOOKMARKS, 20661704Speter "com.delphix:bookmarks", "bookmarks", 207117167Sjhb "\"zfs bookmark\" command", 20848104Syokota B_TRUE, B_FALSE, B_FALSE, bookmarks_deps); 20961704Speter 21061704Speter static const spa_feature_t filesystem_limits_deps[] = { 21148104Syokota SPA_FEATURE_EXTENSIBLE_DATASET, 21248104Syokota SPA_FEATURE_NONE 21348104Syokota }; 21448104Syokota zfeature_register(SPA_FEATURE_FS_SS_LIMIT, 21548104Syokota "com.joyent:filesystem_limits", "filesystem_limits", 21648104Syokota "Filesystem and snapshot limits.", B_TRUE, B_FALSE, B_FALSE, 21748104Syokota filesystem_limits_deps); 21848104Syokota 21948104Syokota zfeature_register(SPA_FEATURE_EMBEDDED_DATA, 22048104Syokota "com.delphix:embedded_data", "embedded_data", 22148104Syokota "Blocks which compress very well use even less space.", 22248104Syokota B_FALSE, B_TRUE, B_TRUE, NULL); 22348104Syokota} 22448104Syokota