zfeature_common.c revision 274337
1236884Smm/* 2236884Smm * CDDL HEADER START 3236884Smm * 4236884Smm * The contents of this file are subject to the terms of the 5236884Smm * Common Development and Distribution License (the "License"). 6236884Smm * You may not use this file except in compliance with the License. 7236884Smm * 8236884Smm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9236884Smm * or http://www.opensolaris.org/os/licensing. 10236884Smm * See the License for the specific language governing permissions 11236884Smm * and limitations under the License. 12236884Smm * 13236884Smm * When distributing Covered Code, include this CDDL HEADER in each 14236884Smm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15236884Smm * If applicable, add the following below this CDDL HEADER, with the 16236884Smm * fields enclosed by brackets "[]" replaced with your own identifying 17236884Smm * information: Portions Copyright [yyyy] [name of copyright owner] 18236884Smm * 19236884Smm * CDDL HEADER END 20236884Smm */ 21236884Smm 22236884Smm/* 23258717Savg * Copyright (c) 2013 by Delphix. All rights reserved. 24246586Sdelphij * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 25255750Sdelphij * Copyright (c) 2013, Joyent, Inc. All rights reserved. 26268126Sdelphij * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. 27236884Smm */ 28236884Smm 29236884Smm#ifdef _KERNEL 30236884Smm#include <sys/systm.h> 31236884Smm#else 32236884Smm#include <errno.h> 33236884Smm#include <string.h> 34236884Smm#endif 35236884Smm#include <sys/debug.h> 36236884Smm#include <sys/fs/zfs.h> 37236884Smm#include <sys/types.h> 38236884Smm#include "zfeature_common.h" 39236884Smm 40236884Smm/* 41236884Smm * Set to disable all feature checks while opening pools, allowing pools with 42236884Smm * unsupported features to be opened. Set for testing only. 43236884Smm */ 44236884Smmboolean_t zfeature_checks_disable = B_FALSE; 45236884Smm 46236884Smmzfeature_info_t spa_feature_table[SPA_FEATURES]; 47236884Smm 48236884Smm/* 49236884Smm * Valid characters for feature guids. This list is mainly for aesthetic 50236884Smm * purposes and could be expanded in the future. There are different allowed 51236884Smm * characters in the guids reverse dns portion (before the colon) and its 52236884Smm * short name (after the colon). 53236884Smm */ 54236884Smmstatic int 55236884Smmvalid_char(char c, boolean_t after_colon) 56236884Smm{ 57236884Smm return ((c >= 'a' && c <= 'z') || 58236884Smm (c >= '0' && c <= '9') || 59274337Sdelphij (after_colon && c == '_') || 60274337Sdelphij (!after_colon && (c == '.' || c == '-'))); 61236884Smm} 62236884Smm 63236884Smm/* 64236884Smm * Every feature guid must contain exactly one colon which separates a reverse 65236884Smm * dns organization name from the feature's "short" name (e.g. 66236884Smm * "com.company:feature_name"). 67236884Smm */ 68236884Smmboolean_t 69236884Smmzfeature_is_valid_guid(const char *name) 70236884Smm{ 71236884Smm int i; 72236884Smm boolean_t has_colon = B_FALSE; 73236884Smm 74236884Smm i = 0; 75236884Smm while (name[i] != '\0') { 76236884Smm char c = name[i++]; 77236884Smm if (c == ':') { 78236884Smm if (has_colon) 79236884Smm return (B_FALSE); 80236884Smm has_colon = B_TRUE; 81236884Smm continue; 82236884Smm } 83236884Smm if (!valid_char(c, has_colon)) 84236884Smm return (B_FALSE); 85236884Smm } 86236884Smm 87236884Smm return (has_colon); 88236884Smm} 89236884Smm 90236884Smmboolean_t 91236884Smmzfeature_is_supported(const char *guid) 92236884Smm{ 93236884Smm if (zfeature_checks_disable) 94236884Smm return (B_TRUE); 95236884Smm 96259813Sdelphij for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 97236884Smm zfeature_info_t *feature = &spa_feature_table[i]; 98259813Sdelphij if (strcmp(guid, feature->fi_guid) == 0) 99259813Sdelphij return (B_TRUE); 100236884Smm } 101259813Sdelphij return (B_FALSE); 102236884Smm} 103236884Smm 104236884Smmint 105259813Sdelphijzfeature_lookup_name(const char *name, spa_feature_t *res) 106236884Smm{ 107259813Sdelphij for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 108236884Smm zfeature_info_t *feature = &spa_feature_table[i]; 109236884Smm if (strcmp(name, feature->fi_uname) == 0) { 110236884Smm if (res != NULL) 111259813Sdelphij *res = i; 112236884Smm return (0); 113236884Smm } 114236884Smm } 115236884Smm 116236884Smm return (ENOENT); 117236884Smm} 118236884Smm 119260150Sdelphijboolean_t 120260150Sdelphijzfeature_depends_on(spa_feature_t fid, spa_feature_t check) { 121260150Sdelphij zfeature_info_t *feature = &spa_feature_table[fid]; 122260150Sdelphij 123260150Sdelphij for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) { 124260150Sdelphij if (feature->fi_depends[i] == check) 125260150Sdelphij return (B_TRUE); 126260150Sdelphij } 127260150Sdelphij return (B_FALSE); 128260150Sdelphij} 129260150Sdelphij 130236884Smmstatic void 131259813Sdelphijzfeature_register(spa_feature_t fid, const char *guid, const char *name, 132259813Sdelphij const char *desc, boolean_t readonly, boolean_t mos, 133260150Sdelphij boolean_t activate_on_enable, const spa_feature_t *deps) 134236884Smm{ 135236884Smm zfeature_info_t *feature = &spa_feature_table[fid]; 136259813Sdelphij static spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 137236884Smm 138236884Smm ASSERT(name != NULL); 139236884Smm ASSERT(desc != NULL); 140236884Smm ASSERT(!readonly || !mos); 141236884Smm ASSERT3U(fid, <, SPA_FEATURES); 142236884Smm ASSERT(zfeature_is_valid_guid(guid)); 143236884Smm 144236884Smm if (deps == NULL) 145236884Smm deps = nodeps; 146236884Smm 147259813Sdelphij feature->fi_feature = fid; 148236884Smm feature->fi_guid = guid; 149236884Smm feature->fi_uname = name; 150236884Smm feature->fi_desc = desc; 151236884Smm feature->fi_can_readonly = readonly; 152236884Smm feature->fi_mos = mos; 153260150Sdelphij feature->fi_activate_on_enable = activate_on_enable; 154236884Smm feature->fi_depends = deps; 155236884Smm} 156236884Smm 157236884Smmvoid 158236884Smmzpool_feature_init(void) 159236884Smm{ 160236884Smm zfeature_register(SPA_FEATURE_ASYNC_DESTROY, 161236884Smm "com.delphix:async_destroy", "async_destroy", 162260150Sdelphij "Destroy filesystems asynchronously.", B_TRUE, B_FALSE, 163260150Sdelphij B_FALSE, NULL); 164260150Sdelphij 165239774Smm zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, 166239774Smm "com.delphix:empty_bpobj", "empty_bpobj", 167260150Sdelphij "Snapshots use less space.", B_TRUE, B_FALSE, 168260150Sdelphij B_FALSE, NULL); 169260150Sdelphij 170246586Sdelphij zfeature_register(SPA_FEATURE_LZ4_COMPRESS, 171246586Sdelphij "org.illumos:lz4_compress", "lz4_compress", 172260150Sdelphij "LZ4 compression algorithm support.", B_FALSE, B_FALSE, 173268126Sdelphij B_TRUE, NULL); 174260150Sdelphij 175255750Sdelphij zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, 176255750Sdelphij "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump", 177260150Sdelphij "Crash dumps to multiple vdev pools.", B_FALSE, B_FALSE, 178260150Sdelphij B_FALSE, NULL); 179260150Sdelphij 180258717Savg zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, 181258717Savg "com.delphix:spacemap_histogram", "spacemap_histogram", 182260150Sdelphij "Spacemaps maintain space histograms.", B_TRUE, B_FALSE, 183260150Sdelphij B_FALSE, NULL); 184260150Sdelphij 185260150Sdelphij zfeature_register(SPA_FEATURE_ENABLED_TXG, 186260150Sdelphij "com.delphix:enabled_txg", "enabled_txg", 187260150Sdelphij "Record txg at which a feature is enabled", B_TRUE, B_FALSE, 188260150Sdelphij B_FALSE, NULL); 189260150Sdelphij 190260150Sdelphij static spa_feature_t hole_birth_deps[] = { SPA_FEATURE_ENABLED_TXG, 191260150Sdelphij SPA_FEATURE_NONE }; 192260150Sdelphij zfeature_register(SPA_FEATURE_HOLE_BIRTH, 193260150Sdelphij "com.delphix:hole_birth", "hole_birth", 194260150Sdelphij "Retain hole birth txg for more precise zfs send", 195260150Sdelphij B_FALSE, B_TRUE, B_TRUE, hole_birth_deps); 196260150Sdelphij 197259813Sdelphij zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET, 198259813Sdelphij "com.delphix:extensible_dataset", "extensible_dataset", 199259813Sdelphij "Enhanced dataset functionality, used by other features.", 200260150Sdelphij B_FALSE, B_FALSE, B_FALSE, NULL); 201260183Sdelphij 202260183Sdelphij static const spa_feature_t bookmarks_deps[] = { 203260183Sdelphij SPA_FEATURE_EXTENSIBLE_DATASET, 204260183Sdelphij SPA_FEATURE_NONE 205260183Sdelphij }; 206260183Sdelphij zfeature_register(SPA_FEATURE_BOOKMARKS, 207260183Sdelphij "com.delphix:bookmarks", "bookmarks", 208260183Sdelphij "\"zfs bookmark\" command", 209260183Sdelphij B_TRUE, B_FALSE, B_FALSE, bookmarks_deps); 210264835Sdelphij 211264835Sdelphij static const spa_feature_t filesystem_limits_deps[] = { 212264835Sdelphij SPA_FEATURE_EXTENSIBLE_DATASET, 213264835Sdelphij SPA_FEATURE_NONE 214264835Sdelphij }; 215264835Sdelphij zfeature_register(SPA_FEATURE_FS_SS_LIMIT, 216264835Sdelphij "com.joyent:filesystem_limits", "filesystem_limits", 217264835Sdelphij "Filesystem and snapshot limits.", B_TRUE, B_FALSE, B_FALSE, 218264835Sdelphij filesystem_limits_deps); 219268075Sdelphij 220268075Sdelphij zfeature_register(SPA_FEATURE_EMBEDDED_DATA, 221268075Sdelphij "com.delphix:embedded_data", "embedded_data", 222268075Sdelphij "Blocks which compress very well use even less space.", 223268075Sdelphij B_FALSE, B_TRUE, B_TRUE, NULL); 224274337Sdelphij 225274337Sdelphij static const spa_feature_t large_blocks_deps[] = { 226274337Sdelphij SPA_FEATURE_EXTENSIBLE_DATASET, 227274337Sdelphij SPA_FEATURE_NONE 228274337Sdelphij }; 229274337Sdelphij zfeature_register(SPA_FEATURE_LARGE_BLOCKS, 230274337Sdelphij "org.open-zfs:large_blocks", "large_blocks", 231274337Sdelphij "Support for blocks larger than 128KB.", B_FALSE, B_FALSE, B_FALSE, 232274337Sdelphij large_blocks_deps); 233236884Smm} 234