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/* 23332547Smav * Copyright (c) 2011, 2017 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. 27296519Smav * Copyright (c) 2014 Integros [integros.com] 28236884Smm */ 29236884Smm 30236884Smm#ifdef _KERNEL 31236884Smm#include <sys/systm.h> 32236884Smm#else 33236884Smm#include <errno.h> 34236884Smm#include <string.h> 35236884Smm#endif 36236884Smm#include <sys/debug.h> 37236884Smm#include <sys/fs/zfs.h> 38236884Smm#include <sys/types.h> 39236884Smm#include "zfeature_common.h" 40236884Smm 41236884Smm/* 42236884Smm * Set to disable all feature checks while opening pools, allowing pools with 43236884Smm * unsupported features to be opened. Set for testing only. 44236884Smm */ 45236884Smmboolean_t zfeature_checks_disable = B_FALSE; 46236884Smm 47236884Smmzfeature_info_t spa_feature_table[SPA_FEATURES]; 48236884Smm 49236884Smm/* 50236884Smm * Valid characters for feature guids. This list is mainly for aesthetic 51236884Smm * purposes and could be expanded in the future. There are different allowed 52236884Smm * characters in the guids reverse dns portion (before the colon) and its 53236884Smm * short name (after the colon). 54236884Smm */ 55236884Smmstatic int 56236884Smmvalid_char(char c, boolean_t after_colon) 57236884Smm{ 58236884Smm return ((c >= 'a' && c <= 'z') || 59236884Smm (c >= '0' && c <= '9') || 60274337Sdelphij (after_colon && c == '_') || 61274337Sdelphij (!after_colon && (c == '.' || c == '-'))); 62236884Smm} 63236884Smm 64236884Smm/* 65236884Smm * Every feature guid must contain exactly one colon which separates a reverse 66236884Smm * dns organization name from the feature's "short" name (e.g. 67236884Smm * "com.company:feature_name"). 68236884Smm */ 69236884Smmboolean_t 70236884Smmzfeature_is_valid_guid(const char *name) 71236884Smm{ 72236884Smm int i; 73236884Smm boolean_t has_colon = B_FALSE; 74236884Smm 75236884Smm i = 0; 76236884Smm while (name[i] != '\0') { 77236884Smm char c = name[i++]; 78236884Smm if (c == ':') { 79236884Smm if (has_colon) 80236884Smm return (B_FALSE); 81236884Smm has_colon = B_TRUE; 82236884Smm continue; 83236884Smm } 84236884Smm if (!valid_char(c, has_colon)) 85236884Smm return (B_FALSE); 86236884Smm } 87236884Smm 88236884Smm return (has_colon); 89236884Smm} 90236884Smm 91236884Smmboolean_t 92236884Smmzfeature_is_supported(const char *guid) 93236884Smm{ 94236884Smm if (zfeature_checks_disable) 95236884Smm return (B_TRUE); 96236884Smm 97259813Sdelphij for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 98236884Smm zfeature_info_t *feature = &spa_feature_table[i]; 99259813Sdelphij if (strcmp(guid, feature->fi_guid) == 0) 100259813Sdelphij return (B_TRUE); 101236884Smm } 102259813Sdelphij return (B_FALSE); 103236884Smm} 104236884Smm 105236884Smmint 106259813Sdelphijzfeature_lookup_name(const char *name, spa_feature_t *res) 107236884Smm{ 108259813Sdelphij for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 109236884Smm zfeature_info_t *feature = &spa_feature_table[i]; 110236884Smm if (strcmp(name, feature->fi_uname) == 0) { 111236884Smm if (res != NULL) 112259813Sdelphij *res = i; 113236884Smm return (0); 114236884Smm } 115236884Smm } 116236884Smm 117236884Smm return (ENOENT); 118236884Smm} 119236884Smm 120260150Sdelphijboolean_t 121289562Smavzfeature_depends_on(spa_feature_t fid, spa_feature_t check) 122289562Smav{ 123260150Sdelphij zfeature_info_t *feature = &spa_feature_table[fid]; 124260150Sdelphij 125260150Sdelphij for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) { 126260150Sdelphij if (feature->fi_depends[i] == check) 127260150Sdelphij return (B_TRUE); 128260150Sdelphij } 129260150Sdelphij return (B_FALSE); 130260150Sdelphij} 131260150Sdelphij 132236884Smmstatic void 133259813Sdelphijzfeature_register(spa_feature_t fid, const char *guid, const char *name, 134286708Smav const char *desc, zfeature_flags_t flags, const spa_feature_t *deps) 135236884Smm{ 136236884Smm zfeature_info_t *feature = &spa_feature_table[fid]; 137259813Sdelphij static spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 138236884Smm 139236884Smm ASSERT(name != NULL); 140236884Smm ASSERT(desc != NULL); 141286708Smav ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 || 142286708Smav (flags & ZFEATURE_FLAG_MOS) == 0); 143236884Smm ASSERT3U(fid, <, SPA_FEATURES); 144236884Smm ASSERT(zfeature_is_valid_guid(guid)); 145236884Smm 146236884Smm if (deps == NULL) 147236884Smm deps = nodeps; 148236884Smm 149259813Sdelphij feature->fi_feature = fid; 150236884Smm feature->fi_guid = guid; 151236884Smm feature->fi_uname = name; 152236884Smm feature->fi_desc = desc; 153286708Smav feature->fi_flags = flags; 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", 162286708Smav "Destroy filesystems asynchronously.", 163286708Smav ZFEATURE_FLAG_READONLY_COMPAT, NULL); 164260150Sdelphij 165239774Smm zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, 166239774Smm "com.delphix:empty_bpobj", "empty_bpobj", 167286708Smav "Snapshots use less space.", 168286708Smav ZFEATURE_FLAG_READONLY_COMPAT, NULL); 169260150Sdelphij 170246586Sdelphij zfeature_register(SPA_FEATURE_LZ4_COMPRESS, 171246586Sdelphij "org.illumos:lz4_compress", "lz4_compress", 172286708Smav "LZ4 compression algorithm support.", 173286708Smav ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL); 174260150Sdelphij 175255750Sdelphij zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, 176255750Sdelphij "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump", 177286708Smav "Crash dumps to multiple vdev pools.", 178286708Smav 0, NULL); 179260150Sdelphij 180258717Savg zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, 181258717Savg "com.delphix:spacemap_histogram", "spacemap_histogram", 182286708Smav "Spacemaps maintain space histograms.", 183286708Smav ZFEATURE_FLAG_READONLY_COMPAT, NULL); 184260150Sdelphij 185260150Sdelphij zfeature_register(SPA_FEATURE_ENABLED_TXG, 186260150Sdelphij "com.delphix:enabled_txg", "enabled_txg", 187286708Smav "Record txg at which a feature is enabled", 188286708Smav ZFEATURE_FLAG_READONLY_COMPAT, 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", 195286708Smav ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 196286708Smav hole_birth_deps); 197260150Sdelphij 198259813Sdelphij zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET, 199259813Sdelphij "com.delphix:extensible_dataset", "extensible_dataset", 200259813Sdelphij "Enhanced dataset functionality, used by other features.", 201286708Smav 0, NULL); 202260183Sdelphij 203260183Sdelphij static const spa_feature_t bookmarks_deps[] = { 204260183Sdelphij SPA_FEATURE_EXTENSIBLE_DATASET, 205260183Sdelphij SPA_FEATURE_NONE 206260183Sdelphij }; 207260183Sdelphij zfeature_register(SPA_FEATURE_BOOKMARKS, 208260183Sdelphij "com.delphix:bookmarks", "bookmarks", 209260183Sdelphij "\"zfs bookmark\" command", 210286708Smav ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps); 211264835Sdelphij 212264835Sdelphij static const spa_feature_t filesystem_limits_deps[] = { 213264835Sdelphij SPA_FEATURE_EXTENSIBLE_DATASET, 214264835Sdelphij SPA_FEATURE_NONE 215264835Sdelphij }; 216264835Sdelphij zfeature_register(SPA_FEATURE_FS_SS_LIMIT, 217264835Sdelphij "com.joyent:filesystem_limits", "filesystem_limits", 218286708Smav "Filesystem and snapshot limits.", 219286708Smav ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps); 220268075Sdelphij 221268075Sdelphij zfeature_register(SPA_FEATURE_EMBEDDED_DATA, 222268075Sdelphij "com.delphix:embedded_data", "embedded_data", 223268075Sdelphij "Blocks which compress very well use even less space.", 224286708Smav ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 225286708Smav NULL); 226274337Sdelphij 227332547Smav zfeature_register(SPA_FEATURE_POOL_CHECKPOINT, 228332547Smav "com.delphix:zpool_checkpoint", "zpool_checkpoint", 229332547Smav "Pool state can be checkpointed, allowing rewind later.", 230332547Smav ZFEATURE_FLAG_READONLY_COMPAT, NULL); 231332547Smav 232339104Smav zfeature_register(SPA_FEATURE_SPACEMAP_V2, 233339104Smav "com.delphix:spacemap_v2", "spacemap_v2", 234339104Smav "Space maps representing large segments are more efficient.", 235339104Smav ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 236339104Smav NULL); 237339104Smav 238274337Sdelphij static const spa_feature_t large_blocks_deps[] = { 239274337Sdelphij SPA_FEATURE_EXTENSIBLE_DATASET, 240274337Sdelphij SPA_FEATURE_NONE 241274337Sdelphij }; 242274337Sdelphij zfeature_register(SPA_FEATURE_LARGE_BLOCKS, 243274337Sdelphij "org.open-zfs:large_blocks", "large_blocks", 244286708Smav "Support for blocks larger than 128KB.", 245286708Smav ZFEATURE_FLAG_PER_DATASET, large_blocks_deps); 246351805Savg static const spa_feature_t sha512_deps[] = { 247351805Savg SPA_FEATURE_EXTENSIBLE_DATASET, 248351805Savg SPA_FEATURE_NONE 249351805Savg }; 250289422Smav zfeature_register(SPA_FEATURE_SHA512, 251289422Smav "org.illumos:sha512", "sha512", 252289422Smav "SHA-512/256 hash algorithm.", 253351805Savg ZFEATURE_FLAG_PER_DATASET, sha512_deps); 254351805Savg 255351805Savg static const spa_feature_t skein_deps[] = { 256351805Savg SPA_FEATURE_EXTENSIBLE_DATASET, 257351805Savg SPA_FEATURE_NONE 258351805Savg }; 259289422Smav zfeature_register(SPA_FEATURE_SKEIN, 260289422Smav "org.illumos:skein", "skein", 261289422Smav "Skein hash algorithm.", 262351805Savg ZFEATURE_FLAG_PER_DATASET, skein_deps); 263301010Sallanjude 264301010Sallanjude#ifdef illumos 265351805Savg static const spa_feature_t edonr_deps[] = { 266351805Savg SPA_FEATURE_EXTENSIBLE_DATASET, 267351805Savg SPA_FEATURE_NONE 268351805Savg }; 269289422Smav zfeature_register(SPA_FEATURE_EDONR, 270289422Smav "org.illumos:edonr", "edonr", 271289422Smav "Edon-R hash algorithm.", 272351805Savg ZFEATURE_FLAG_PER_DATASET, edonr_deps); 273289422Smav#endif 274332525Smav 275332525Smav zfeature_register(SPA_FEATURE_DEVICE_REMOVAL, 276332525Smav "com.delphix:device_removal", "device_removal", 277332525Smav "Top-level vdevs can be removed, reducing logical pool size.", 278332525Smav ZFEATURE_FLAG_MOS, NULL); 279332525Smav 280332525Smav static const spa_feature_t obsolete_counts_deps[] = { 281332525Smav SPA_FEATURE_EXTENSIBLE_DATASET, 282332525Smav SPA_FEATURE_DEVICE_REMOVAL, 283332525Smav SPA_FEATURE_NONE 284332525Smav }; 285332525Smav zfeature_register(SPA_FEATURE_OBSOLETE_COUNTS, 286332525Smav "com.delphix:obsolete_counts", "obsolete_counts", 287332525Smav "Reduce memory used by removed devices when their blocks are " 288332525Smav "freed or remapped.", 289332525Smav ZFEATURE_FLAG_READONLY_COMPAT, obsolete_counts_deps); 290236884Smm} 291