1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6*eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7*eda14cbcSMatt Macy * 8*eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eda14cbcSMatt Macy * or http://www.opensolaris.org/os/licensing. 10*eda14cbcSMatt Macy * See the License for the specific language governing permissions 11*eda14cbcSMatt Macy * and limitations under the License. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14*eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16*eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17*eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18*eda14cbcSMatt Macy * 19*eda14cbcSMatt Macy * CDDL HEADER END 20*eda14cbcSMatt Macy */ 21*eda14cbcSMatt Macy 22*eda14cbcSMatt Macy /* 23*eda14cbcSMatt Macy * Copyright (c) 2011, 2018 by Delphix. All rights reserved. 24*eda14cbcSMatt Macy * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 25*eda14cbcSMatt Macy * Copyright (c) 2013, Joyent, Inc. All rights reserved. 26*eda14cbcSMatt Macy * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. 27*eda14cbcSMatt Macy * Copyright (c) 2017, Intel Corporation. 28*eda14cbcSMatt Macy * Copyright (c) 2019, Klara Inc. 29*eda14cbcSMatt Macy * Copyright (c) 2019, Allan Jude 30*eda14cbcSMatt Macy */ 31*eda14cbcSMatt Macy 32*eda14cbcSMatt Macy #ifndef _KERNEL 33*eda14cbcSMatt Macy #include <errno.h> 34*eda14cbcSMatt Macy #include <string.h> 35*eda14cbcSMatt Macy #include <sys/stat.h> 36*eda14cbcSMatt Macy #endif 37*eda14cbcSMatt Macy #include <sys/debug.h> 38*eda14cbcSMatt Macy #include <sys/fs/zfs.h> 39*eda14cbcSMatt Macy #include <sys/inttypes.h> 40*eda14cbcSMatt Macy #include <sys/types.h> 41*eda14cbcSMatt Macy #include <sys/param.h> 42*eda14cbcSMatt Macy #include <sys/zfs_sysfs.h> 43*eda14cbcSMatt Macy #include "zfeature_common.h" 44*eda14cbcSMatt Macy 45*eda14cbcSMatt Macy /* 46*eda14cbcSMatt Macy * Set to disable all feature checks while opening pools, allowing pools with 47*eda14cbcSMatt Macy * unsupported features to be opened. Set for testing only. 48*eda14cbcSMatt Macy */ 49*eda14cbcSMatt Macy boolean_t zfeature_checks_disable = B_FALSE; 50*eda14cbcSMatt Macy 51*eda14cbcSMatt Macy zfeature_info_t spa_feature_table[SPA_FEATURES]; 52*eda14cbcSMatt Macy 53*eda14cbcSMatt Macy /* 54*eda14cbcSMatt Macy * Valid characters for feature guids. This list is mainly for aesthetic 55*eda14cbcSMatt Macy * purposes and could be expanded in the future. There are different allowed 56*eda14cbcSMatt Macy * characters in the guids reverse dns portion (before the colon) and its 57*eda14cbcSMatt Macy * short name (after the colon). 58*eda14cbcSMatt Macy */ 59*eda14cbcSMatt Macy static int 60*eda14cbcSMatt Macy valid_char(char c, boolean_t after_colon) 61*eda14cbcSMatt Macy { 62*eda14cbcSMatt Macy return ((c >= 'a' && c <= 'z') || 63*eda14cbcSMatt Macy (c >= '0' && c <= '9') || 64*eda14cbcSMatt Macy (after_colon && c == '_') || 65*eda14cbcSMatt Macy (!after_colon && (c == '.' || c == '-'))); 66*eda14cbcSMatt Macy } 67*eda14cbcSMatt Macy 68*eda14cbcSMatt Macy /* 69*eda14cbcSMatt Macy * Every feature guid must contain exactly one colon which separates a reverse 70*eda14cbcSMatt Macy * dns organization name from the feature's "short" name (e.g. 71*eda14cbcSMatt Macy * "com.company:feature_name"). 72*eda14cbcSMatt Macy */ 73*eda14cbcSMatt Macy boolean_t 74*eda14cbcSMatt Macy zfeature_is_valid_guid(const char *name) 75*eda14cbcSMatt Macy { 76*eda14cbcSMatt Macy int i; 77*eda14cbcSMatt Macy boolean_t has_colon = B_FALSE; 78*eda14cbcSMatt Macy 79*eda14cbcSMatt Macy i = 0; 80*eda14cbcSMatt Macy while (name[i] != '\0') { 81*eda14cbcSMatt Macy char c = name[i++]; 82*eda14cbcSMatt Macy if (c == ':') { 83*eda14cbcSMatt Macy if (has_colon) 84*eda14cbcSMatt Macy return (B_FALSE); 85*eda14cbcSMatt Macy has_colon = B_TRUE; 86*eda14cbcSMatt Macy continue; 87*eda14cbcSMatt Macy } 88*eda14cbcSMatt Macy if (!valid_char(c, has_colon)) 89*eda14cbcSMatt Macy return (B_FALSE); 90*eda14cbcSMatt Macy } 91*eda14cbcSMatt Macy 92*eda14cbcSMatt Macy return (has_colon); 93*eda14cbcSMatt Macy } 94*eda14cbcSMatt Macy 95*eda14cbcSMatt Macy boolean_t 96*eda14cbcSMatt Macy zfeature_is_supported(const char *guid) 97*eda14cbcSMatt Macy { 98*eda14cbcSMatt Macy if (zfeature_checks_disable) 99*eda14cbcSMatt Macy return (B_TRUE); 100*eda14cbcSMatt Macy 101*eda14cbcSMatt Macy for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 102*eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[i]; 103*eda14cbcSMatt Macy if (strcmp(guid, feature->fi_guid) == 0) 104*eda14cbcSMatt Macy return (B_TRUE); 105*eda14cbcSMatt Macy } 106*eda14cbcSMatt Macy return (B_FALSE); 107*eda14cbcSMatt Macy } 108*eda14cbcSMatt Macy 109*eda14cbcSMatt Macy int 110*eda14cbcSMatt Macy zfeature_lookup_guid(const char *guid, spa_feature_t *res) 111*eda14cbcSMatt Macy { 112*eda14cbcSMatt Macy for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 113*eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[i]; 114*eda14cbcSMatt Macy if (!feature->fi_zfs_mod_supported) 115*eda14cbcSMatt Macy continue; 116*eda14cbcSMatt Macy if (strcmp(guid, feature->fi_guid) == 0) { 117*eda14cbcSMatt Macy if (res != NULL) 118*eda14cbcSMatt Macy *res = i; 119*eda14cbcSMatt Macy return (0); 120*eda14cbcSMatt Macy } 121*eda14cbcSMatt Macy } 122*eda14cbcSMatt Macy 123*eda14cbcSMatt Macy return (ENOENT); 124*eda14cbcSMatt Macy } 125*eda14cbcSMatt Macy 126*eda14cbcSMatt Macy int 127*eda14cbcSMatt Macy zfeature_lookup_name(const char *name, spa_feature_t *res) 128*eda14cbcSMatt Macy { 129*eda14cbcSMatt Macy for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { 130*eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[i]; 131*eda14cbcSMatt Macy if (!feature->fi_zfs_mod_supported) 132*eda14cbcSMatt Macy continue; 133*eda14cbcSMatt Macy if (strcmp(name, feature->fi_uname) == 0) { 134*eda14cbcSMatt Macy if (res != NULL) 135*eda14cbcSMatt Macy *res = i; 136*eda14cbcSMatt Macy return (0); 137*eda14cbcSMatt Macy } 138*eda14cbcSMatt Macy } 139*eda14cbcSMatt Macy 140*eda14cbcSMatt Macy return (ENOENT); 141*eda14cbcSMatt Macy } 142*eda14cbcSMatt Macy 143*eda14cbcSMatt Macy boolean_t 144*eda14cbcSMatt Macy zfeature_depends_on(spa_feature_t fid, spa_feature_t check) 145*eda14cbcSMatt Macy { 146*eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[fid]; 147*eda14cbcSMatt Macy 148*eda14cbcSMatt Macy for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) { 149*eda14cbcSMatt Macy if (feature->fi_depends[i] == check) 150*eda14cbcSMatt Macy return (B_TRUE); 151*eda14cbcSMatt Macy } 152*eda14cbcSMatt Macy return (B_FALSE); 153*eda14cbcSMatt Macy } 154*eda14cbcSMatt Macy 155*eda14cbcSMatt Macy static boolean_t 156*eda14cbcSMatt Macy deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature) 157*eda14cbcSMatt Macy { 158*eda14cbcSMatt Macy for (int i = 0; deps[i] != SPA_FEATURE_NONE; i++) 159*eda14cbcSMatt Macy if (deps[i] == feature) 160*eda14cbcSMatt Macy return (B_TRUE); 161*eda14cbcSMatt Macy 162*eda14cbcSMatt Macy return (B_FALSE); 163*eda14cbcSMatt Macy } 164*eda14cbcSMatt Macy 165*eda14cbcSMatt Macy #if !defined(_KERNEL) && !defined(LIB_ZPOOL_BUILD) 166*eda14cbcSMatt Macy static boolean_t 167*eda14cbcSMatt Macy zfs_mod_supported_impl(const char *scope, const char *name, const char *sysfs) 168*eda14cbcSMatt Macy { 169*eda14cbcSMatt Macy boolean_t supported = B_FALSE; 170*eda14cbcSMatt Macy char *path; 171*eda14cbcSMatt Macy 172*eda14cbcSMatt Macy int len = asprintf(&path, "%s%s%s%s%s", sysfs, 173*eda14cbcSMatt Macy scope == NULL ? "" : "/", scope == NULL ? "" : scope, 174*eda14cbcSMatt Macy name == NULL ? "" : "/", name == NULL ? "" : name); 175*eda14cbcSMatt Macy if (len > 0) { 176*eda14cbcSMatt Macy struct stat64 statbuf; 177*eda14cbcSMatt Macy supported = !!(stat64(path, &statbuf) == 0); 178*eda14cbcSMatt Macy free(path); 179*eda14cbcSMatt Macy } 180*eda14cbcSMatt Macy 181*eda14cbcSMatt Macy return (supported); 182*eda14cbcSMatt Macy } 183*eda14cbcSMatt Macy 184*eda14cbcSMatt Macy boolean_t 185*eda14cbcSMatt Macy zfs_mod_supported(const char *scope, const char *name) 186*eda14cbcSMatt Macy { 187*eda14cbcSMatt Macy boolean_t supported; 188*eda14cbcSMatt Macy 189*eda14cbcSMatt Macy /* 190*eda14cbcSMatt Macy * Check both the primary and alternate sysfs locations to determine 191*eda14cbcSMatt Macy * if the required functionality is supported. 192*eda14cbcSMatt Macy */ 193*eda14cbcSMatt Macy supported = (zfs_mod_supported_impl(scope, name, ZFS_SYSFS_DIR) || 194*eda14cbcSMatt Macy zfs_mod_supported_impl(scope, name, ZFS_SYSFS_ALT_DIR)); 195*eda14cbcSMatt Macy 196*eda14cbcSMatt Macy /* 197*eda14cbcSMatt Macy * For backwards compatibility with kernel modules that predate 198*eda14cbcSMatt Macy * supported feature/property checking. Report the feature/property 199*eda14cbcSMatt Macy * as supported if the kernel module is loaded but the requested 200*eda14cbcSMatt Macy * scope directory does not exist. 201*eda14cbcSMatt Macy */ 202*eda14cbcSMatt Macy if (supported == B_FALSE) { 203*eda14cbcSMatt Macy struct stat64 statbuf; 204*eda14cbcSMatt Macy if ((stat64(ZFS_SYSFS_DIR, &statbuf) == 0) && 205*eda14cbcSMatt Macy !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_DIR) && 206*eda14cbcSMatt Macy !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_ALT_DIR)) { 207*eda14cbcSMatt Macy supported = B_TRUE; 208*eda14cbcSMatt Macy } 209*eda14cbcSMatt Macy } 210*eda14cbcSMatt Macy 211*eda14cbcSMatt Macy return (supported); 212*eda14cbcSMatt Macy } 213*eda14cbcSMatt Macy #endif 214*eda14cbcSMatt Macy 215*eda14cbcSMatt Macy static boolean_t 216*eda14cbcSMatt Macy zfs_mod_supported_feature(const char *name) 217*eda14cbcSMatt Macy { 218*eda14cbcSMatt Macy /* 219*eda14cbcSMatt Macy * The zfs module spa_feature_table[], whether in-kernel or in 220*eda14cbcSMatt Macy * libzpool, always supports all the features. libzfs needs to 221*eda14cbcSMatt Macy * query the running module, via sysfs, to determine which 222*eda14cbcSMatt Macy * features are supported. 223*eda14cbcSMatt Macy * 224*eda14cbcSMatt Macy * The equivalent _can_ be done on FreeBSD by way of the sysctl 225*eda14cbcSMatt Macy * tree, but this has not been done yet. 226*eda14cbcSMatt Macy */ 227*eda14cbcSMatt Macy #if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD) || defined(__FreeBSD__) 228*eda14cbcSMatt Macy return (B_TRUE); 229*eda14cbcSMatt Macy #else 230*eda14cbcSMatt Macy return (zfs_mod_supported(ZFS_SYSFS_POOL_FEATURES, name)); 231*eda14cbcSMatt Macy #endif 232*eda14cbcSMatt Macy } 233*eda14cbcSMatt Macy 234*eda14cbcSMatt Macy static void 235*eda14cbcSMatt Macy zfeature_register(spa_feature_t fid, const char *guid, const char *name, 236*eda14cbcSMatt Macy const char *desc, zfeature_flags_t flags, zfeature_type_t type, 237*eda14cbcSMatt Macy const spa_feature_t *deps) 238*eda14cbcSMatt Macy { 239*eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[fid]; 240*eda14cbcSMatt Macy static spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 241*eda14cbcSMatt Macy 242*eda14cbcSMatt Macy ASSERT(name != NULL); 243*eda14cbcSMatt Macy ASSERT(desc != NULL); 244*eda14cbcSMatt Macy ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 || 245*eda14cbcSMatt Macy (flags & ZFEATURE_FLAG_MOS) == 0); 246*eda14cbcSMatt Macy ASSERT3U(fid, <, SPA_FEATURES); 247*eda14cbcSMatt Macy ASSERT(zfeature_is_valid_guid(guid)); 248*eda14cbcSMatt Macy 249*eda14cbcSMatt Macy if (deps == NULL) 250*eda14cbcSMatt Macy deps = nodeps; 251*eda14cbcSMatt Macy 252*eda14cbcSMatt Macy VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) || 253*eda14cbcSMatt Macy (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET))); 254*eda14cbcSMatt Macy 255*eda14cbcSMatt Macy feature->fi_feature = fid; 256*eda14cbcSMatt Macy feature->fi_guid = guid; 257*eda14cbcSMatt Macy feature->fi_uname = name; 258*eda14cbcSMatt Macy feature->fi_desc = desc; 259*eda14cbcSMatt Macy feature->fi_flags = flags; 260*eda14cbcSMatt Macy feature->fi_type = type; 261*eda14cbcSMatt Macy feature->fi_depends = deps; 262*eda14cbcSMatt Macy feature->fi_zfs_mod_supported = zfs_mod_supported_feature(guid); 263*eda14cbcSMatt Macy } 264*eda14cbcSMatt Macy 265*eda14cbcSMatt Macy /* 266*eda14cbcSMatt Macy * Every feature has a GUID of the form com.example:feature_name. The 267*eda14cbcSMatt Macy * reversed DNS name ensures that the feature's GUID is unique across all ZFS 268*eda14cbcSMatt Macy * implementations. This allows companies to independently develop and 269*eda14cbcSMatt Macy * release features. Examples include org.delphix and org.datto. Previously, 270*eda14cbcSMatt Macy * features developed on one implementation have used that implementation's 271*eda14cbcSMatt Macy * domain name (e.g. org.illumos and org.zfsonlinux). Use of the org.openzfs 272*eda14cbcSMatt Macy * domain name is recommended for new features which are developed by the 273*eda14cbcSMatt Macy * OpenZFS community and its platforms. This domain may optionally be used by 274*eda14cbcSMatt Macy * companies developing features for initial release through an OpenZFS 275*eda14cbcSMatt Macy * implementation. Use of the org.openzfs domain requires reserving the 276*eda14cbcSMatt Macy * feature name in advance with the OpenZFS project. 277*eda14cbcSMatt Macy */ 278*eda14cbcSMatt Macy void 279*eda14cbcSMatt Macy zpool_feature_init(void) 280*eda14cbcSMatt Macy { 281*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ASYNC_DESTROY, 282*eda14cbcSMatt Macy "com.delphix:async_destroy", "async_destroy", 283*eda14cbcSMatt Macy "Destroy filesystems asynchronously.", 284*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 285*eda14cbcSMatt Macy 286*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, 287*eda14cbcSMatt Macy "com.delphix:empty_bpobj", "empty_bpobj", 288*eda14cbcSMatt Macy "Snapshots use less space.", 289*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 290*eda14cbcSMatt Macy 291*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LZ4_COMPRESS, 292*eda14cbcSMatt Macy "org.illumos:lz4_compress", "lz4_compress", 293*eda14cbcSMatt Macy "LZ4 compression algorithm support.", 294*eda14cbcSMatt Macy ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL); 295*eda14cbcSMatt Macy 296*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, 297*eda14cbcSMatt Macy "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump", 298*eda14cbcSMatt Macy "Crash dumps to multiple vdev pools.", 299*eda14cbcSMatt Macy 0, ZFEATURE_TYPE_BOOLEAN, NULL); 300*eda14cbcSMatt Macy 301*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, 302*eda14cbcSMatt Macy "com.delphix:spacemap_histogram", "spacemap_histogram", 303*eda14cbcSMatt Macy "Spacemaps maintain space histograms.", 304*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 305*eda14cbcSMatt Macy 306*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ENABLED_TXG, 307*eda14cbcSMatt Macy "com.delphix:enabled_txg", "enabled_txg", 308*eda14cbcSMatt Macy "Record txg at which a feature is enabled", 309*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 310*eda14cbcSMatt Macy 311*eda14cbcSMatt Macy { 312*eda14cbcSMatt Macy static const spa_feature_t hole_birth_deps[] = { 313*eda14cbcSMatt Macy SPA_FEATURE_ENABLED_TXG, 314*eda14cbcSMatt Macy SPA_FEATURE_NONE 315*eda14cbcSMatt Macy }; 316*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_HOLE_BIRTH, 317*eda14cbcSMatt Macy "com.delphix:hole_birth", "hole_birth", 318*eda14cbcSMatt Macy "Retain hole birth txg for more precise zfs send", 319*eda14cbcSMatt Macy ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 320*eda14cbcSMatt Macy ZFEATURE_TYPE_BOOLEAN, hole_birth_deps); 321*eda14cbcSMatt Macy } 322*eda14cbcSMatt Macy 323*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_POOL_CHECKPOINT, 324*eda14cbcSMatt Macy "com.delphix:zpool_checkpoint", "zpool_checkpoint", 325*eda14cbcSMatt Macy "Pool state can be checkpointed, allowing rewind later.", 326*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 327*eda14cbcSMatt Macy 328*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SPACEMAP_V2, 329*eda14cbcSMatt Macy "com.delphix:spacemap_v2", "spacemap_v2", 330*eda14cbcSMatt Macy "Space maps representing large segments are more efficient.", 331*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 332*eda14cbcSMatt Macy ZFEATURE_TYPE_BOOLEAN, NULL); 333*eda14cbcSMatt Macy 334*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET, 335*eda14cbcSMatt Macy "com.delphix:extensible_dataset", "extensible_dataset", 336*eda14cbcSMatt Macy "Enhanced dataset functionality, used by other features.", 337*eda14cbcSMatt Macy 0, ZFEATURE_TYPE_BOOLEAN, NULL); 338*eda14cbcSMatt Macy 339*eda14cbcSMatt Macy { 340*eda14cbcSMatt Macy static const spa_feature_t bookmarks_deps[] = { 341*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 342*eda14cbcSMatt Macy SPA_FEATURE_NONE 343*eda14cbcSMatt Macy }; 344*eda14cbcSMatt Macy 345*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_BOOKMARKS, 346*eda14cbcSMatt Macy "com.delphix:bookmarks", "bookmarks", 347*eda14cbcSMatt Macy "\"zfs bookmark\" command", 348*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, 349*eda14cbcSMatt Macy bookmarks_deps); 350*eda14cbcSMatt Macy } 351*eda14cbcSMatt Macy 352*eda14cbcSMatt Macy { 353*eda14cbcSMatt Macy static const spa_feature_t filesystem_limits_deps[] = { 354*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 355*eda14cbcSMatt Macy SPA_FEATURE_NONE 356*eda14cbcSMatt Macy }; 357*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_FS_SS_LIMIT, 358*eda14cbcSMatt Macy "com.joyent:filesystem_limits", "filesystem_limits", 359*eda14cbcSMatt Macy "Filesystem and snapshot limits.", 360*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, 361*eda14cbcSMatt Macy filesystem_limits_deps); 362*eda14cbcSMatt Macy } 363*eda14cbcSMatt Macy 364*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EMBEDDED_DATA, 365*eda14cbcSMatt Macy "com.delphix:embedded_data", "embedded_data", 366*eda14cbcSMatt Macy "Blocks which compress very well use even less space.", 367*eda14cbcSMatt Macy ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, 368*eda14cbcSMatt Macy ZFEATURE_TYPE_BOOLEAN, NULL); 369*eda14cbcSMatt Macy 370*eda14cbcSMatt Macy { 371*eda14cbcSMatt Macy static const spa_feature_t livelist_deps[] = { 372*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 373*eda14cbcSMatt Macy SPA_FEATURE_NONE 374*eda14cbcSMatt Macy }; 375*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LIVELIST, 376*eda14cbcSMatt Macy "com.delphix:livelist", "livelist", 377*eda14cbcSMatt Macy "Improved clone deletion performance.", 378*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, 379*eda14cbcSMatt Macy livelist_deps); 380*eda14cbcSMatt Macy } 381*eda14cbcSMatt Macy 382*eda14cbcSMatt Macy { 383*eda14cbcSMatt Macy static const spa_feature_t log_spacemap_deps[] = { 384*eda14cbcSMatt Macy SPA_FEATURE_SPACEMAP_V2, 385*eda14cbcSMatt Macy SPA_FEATURE_NONE 386*eda14cbcSMatt Macy }; 387*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LOG_SPACEMAP, 388*eda14cbcSMatt Macy "com.delphix:log_spacemap", "log_spacemap", 389*eda14cbcSMatt Macy "Log metaslab changes on a single spacemap and " 390*eda14cbcSMatt Macy "flush them periodically.", 391*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, 392*eda14cbcSMatt Macy log_spacemap_deps); 393*eda14cbcSMatt Macy } 394*eda14cbcSMatt Macy 395*eda14cbcSMatt Macy { 396*eda14cbcSMatt Macy static const spa_feature_t large_blocks_deps[] = { 397*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 398*eda14cbcSMatt Macy SPA_FEATURE_NONE 399*eda14cbcSMatt Macy }; 400*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LARGE_BLOCKS, 401*eda14cbcSMatt Macy "org.open-zfs:large_blocks", "large_blocks", 402*eda14cbcSMatt Macy "Support for blocks larger than 128KB.", 403*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, 404*eda14cbcSMatt Macy large_blocks_deps); 405*eda14cbcSMatt Macy } 406*eda14cbcSMatt Macy 407*eda14cbcSMatt Macy { 408*eda14cbcSMatt Macy static const spa_feature_t large_dnode_deps[] = { 409*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 410*eda14cbcSMatt Macy SPA_FEATURE_NONE 411*eda14cbcSMatt Macy }; 412*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LARGE_DNODE, 413*eda14cbcSMatt Macy "org.zfsonlinux:large_dnode", "large_dnode", 414*eda14cbcSMatt Macy "Variable on-disk size of dnodes.", 415*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, 416*eda14cbcSMatt Macy large_dnode_deps); 417*eda14cbcSMatt Macy } 418*eda14cbcSMatt Macy 419*eda14cbcSMatt Macy { 420*eda14cbcSMatt Macy static const spa_feature_t sha512_deps[] = { 421*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 422*eda14cbcSMatt Macy SPA_FEATURE_NONE 423*eda14cbcSMatt Macy }; 424*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SHA512, 425*eda14cbcSMatt Macy "org.illumos:sha512", "sha512", 426*eda14cbcSMatt Macy "SHA-512/256 hash algorithm.", 427*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, 428*eda14cbcSMatt Macy sha512_deps); 429*eda14cbcSMatt Macy } 430*eda14cbcSMatt Macy 431*eda14cbcSMatt Macy { 432*eda14cbcSMatt Macy static const spa_feature_t skein_deps[] = { 433*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 434*eda14cbcSMatt Macy SPA_FEATURE_NONE 435*eda14cbcSMatt Macy }; 436*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SKEIN, 437*eda14cbcSMatt Macy "org.illumos:skein", "skein", 438*eda14cbcSMatt Macy "Skein hash algorithm.", 439*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, 440*eda14cbcSMatt Macy skein_deps); 441*eda14cbcSMatt Macy } 442*eda14cbcSMatt Macy 443*eda14cbcSMatt Macy #if !defined(__FreeBSD__) 444*eda14cbcSMatt Macy 445*eda14cbcSMatt Macy { 446*eda14cbcSMatt Macy static const spa_feature_t edonr_deps[] = { 447*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 448*eda14cbcSMatt Macy SPA_FEATURE_NONE 449*eda14cbcSMatt Macy }; 450*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EDONR, 451*eda14cbcSMatt Macy "org.illumos:edonr", "edonr", 452*eda14cbcSMatt Macy "Edon-R hash algorithm.", 453*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, 454*eda14cbcSMatt Macy edonr_deps); 455*eda14cbcSMatt Macy } 456*eda14cbcSMatt Macy #endif 457*eda14cbcSMatt Macy 458*eda14cbcSMatt Macy { 459*eda14cbcSMatt Macy static const spa_feature_t redact_books_deps[] = { 460*eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_V2, 461*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 462*eda14cbcSMatt Macy SPA_FEATURE_BOOKMARKS, 463*eda14cbcSMatt Macy SPA_FEATURE_NONE 464*eda14cbcSMatt Macy }; 465*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_REDACTION_BOOKMARKS, 466*eda14cbcSMatt Macy "com.delphix:redaction_bookmarks", "redaction_bookmarks", 467*eda14cbcSMatt Macy "Support for bookmarks which store redaction lists for zfs " 468*eda14cbcSMatt Macy "redacted send/recv.", 0, ZFEATURE_TYPE_BOOLEAN, 469*eda14cbcSMatt Macy redact_books_deps); 470*eda14cbcSMatt Macy } 471*eda14cbcSMatt Macy 472*eda14cbcSMatt Macy { 473*eda14cbcSMatt Macy static const spa_feature_t redact_datasets_deps[] = { 474*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 475*eda14cbcSMatt Macy SPA_FEATURE_NONE 476*eda14cbcSMatt Macy }; 477*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_REDACTED_DATASETS, 478*eda14cbcSMatt Macy "com.delphix:redacted_datasets", "redacted_datasets", "Support for " 479*eda14cbcSMatt Macy "redacted datasets, produced by receiving a redacted zfs send " 480*eda14cbcSMatt Macy "stream.", ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_UINT64_ARRAY, 481*eda14cbcSMatt Macy redact_datasets_deps); 482*eda14cbcSMatt Macy } 483*eda14cbcSMatt Macy 484*eda14cbcSMatt Macy { 485*eda14cbcSMatt Macy static const spa_feature_t bookmark_written_deps[] = { 486*eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_V2, 487*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 488*eda14cbcSMatt Macy SPA_FEATURE_BOOKMARKS, 489*eda14cbcSMatt Macy SPA_FEATURE_NONE 490*eda14cbcSMatt Macy }; 491*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_BOOKMARK_WRITTEN, 492*eda14cbcSMatt Macy "com.delphix:bookmark_written", "bookmark_written", 493*eda14cbcSMatt Macy "Additional accounting, enabling the written#<bookmark> property" 494*eda14cbcSMatt Macy "(space written since a bookmark), and estimates of send stream " 495*eda14cbcSMatt Macy "sizes for incrementals from bookmarks.", 496*eda14cbcSMatt Macy 0, ZFEATURE_TYPE_BOOLEAN, bookmark_written_deps); 497*eda14cbcSMatt Macy } 498*eda14cbcSMatt Macy 499*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_DEVICE_REMOVAL, 500*eda14cbcSMatt Macy "com.delphix:device_removal", "device_removal", 501*eda14cbcSMatt Macy "Top-level vdevs can be removed, reducing logical pool size.", 502*eda14cbcSMatt Macy ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL); 503*eda14cbcSMatt Macy 504*eda14cbcSMatt Macy { 505*eda14cbcSMatt Macy static const spa_feature_t obsolete_counts_deps[] = { 506*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 507*eda14cbcSMatt Macy SPA_FEATURE_DEVICE_REMOVAL, 508*eda14cbcSMatt Macy SPA_FEATURE_NONE 509*eda14cbcSMatt Macy }; 510*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_OBSOLETE_COUNTS, 511*eda14cbcSMatt Macy "com.delphix:obsolete_counts", "obsolete_counts", 512*eda14cbcSMatt Macy "Reduce memory used by removed devices when their blocks are " 513*eda14cbcSMatt Macy "freed or remapped.", 514*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, 515*eda14cbcSMatt Macy obsolete_counts_deps); 516*eda14cbcSMatt Macy } 517*eda14cbcSMatt Macy 518*eda14cbcSMatt Macy { 519*eda14cbcSMatt Macy static const spa_feature_t userobj_accounting_deps[] = { 520*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 521*eda14cbcSMatt Macy SPA_FEATURE_NONE 522*eda14cbcSMatt Macy }; 523*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING, 524*eda14cbcSMatt Macy "org.zfsonlinux:userobj_accounting", "userobj_accounting", 525*eda14cbcSMatt Macy "User/Group object accounting.", 526*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET, 527*eda14cbcSMatt Macy ZFEATURE_TYPE_BOOLEAN, userobj_accounting_deps); 528*eda14cbcSMatt Macy } 529*eda14cbcSMatt Macy 530*eda14cbcSMatt Macy { 531*eda14cbcSMatt Macy static const spa_feature_t bookmark_v2_deps[] = { 532*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 533*eda14cbcSMatt Macy SPA_FEATURE_BOOKMARKS, 534*eda14cbcSMatt Macy SPA_FEATURE_NONE 535*eda14cbcSMatt Macy }; 536*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_BOOKMARK_V2, 537*eda14cbcSMatt Macy "com.datto:bookmark_v2", "bookmark_v2", 538*eda14cbcSMatt Macy "Support for larger bookmarks", 539*eda14cbcSMatt Macy 0, ZFEATURE_TYPE_BOOLEAN, bookmark_v2_deps); 540*eda14cbcSMatt Macy } 541*eda14cbcSMatt Macy 542*eda14cbcSMatt Macy { 543*eda14cbcSMatt Macy static const spa_feature_t encryption_deps[] = { 544*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 545*eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_V2, 546*eda14cbcSMatt Macy SPA_FEATURE_NONE 547*eda14cbcSMatt Macy }; 548*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ENCRYPTION, 549*eda14cbcSMatt Macy "com.datto:encryption", "encryption", 550*eda14cbcSMatt Macy "Support for dataset level encryption", 551*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, 552*eda14cbcSMatt Macy encryption_deps); 553*eda14cbcSMatt Macy } 554*eda14cbcSMatt Macy 555*eda14cbcSMatt Macy { 556*eda14cbcSMatt Macy static const spa_feature_t project_quota_deps[] = { 557*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 558*eda14cbcSMatt Macy SPA_FEATURE_NONE 559*eda14cbcSMatt Macy }; 560*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_PROJECT_QUOTA, 561*eda14cbcSMatt Macy "org.zfsonlinux:project_quota", "project_quota", 562*eda14cbcSMatt Macy "space/object accounting based on project ID.", 563*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET, 564*eda14cbcSMatt Macy ZFEATURE_TYPE_BOOLEAN, project_quota_deps); 565*eda14cbcSMatt Macy } 566*eda14cbcSMatt Macy 567*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ALLOCATION_CLASSES, 568*eda14cbcSMatt Macy "org.zfsonlinux:allocation_classes", "allocation_classes", 569*eda14cbcSMatt Macy "Support for separate allocation classes.", 570*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 571*eda14cbcSMatt Macy 572*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_RESILVER_DEFER, 573*eda14cbcSMatt Macy "com.datto:resilver_defer", "resilver_defer", 574*eda14cbcSMatt Macy "Support for deferring new resilvers when one is already running.", 575*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 576*eda14cbcSMatt Macy 577*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_DEVICE_REBUILD, 578*eda14cbcSMatt Macy "org.openzfs:device_rebuild", "device_rebuild", 579*eda14cbcSMatt Macy "Support for sequential device rebuilds", 580*eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL); 581*eda14cbcSMatt Macy 582*eda14cbcSMatt Macy { 583*eda14cbcSMatt Macy static const spa_feature_t zstd_deps[] = { 584*eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET, 585*eda14cbcSMatt Macy SPA_FEATURE_NONE 586*eda14cbcSMatt Macy }; 587*eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ZSTD_COMPRESS, 588*eda14cbcSMatt Macy "org.freebsd:zstd_compress", "zstd_compress", 589*eda14cbcSMatt Macy "zstd compression algorithm support.", 590*eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, zstd_deps); 591*eda14cbcSMatt Macy } 592*eda14cbcSMatt Macy } 593*eda14cbcSMatt Macy 594*eda14cbcSMatt Macy #if defined(_KERNEL) 595*eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_lookup_guid); 596*eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_lookup_name); 597*eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_is_supported); 598*eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_is_valid_guid); 599*eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_depends_on); 600*eda14cbcSMatt Macy EXPORT_SYMBOL(zpool_feature_init); 601*eda14cbcSMatt Macy EXPORT_SYMBOL(spa_feature_table); 602*eda14cbcSMatt Macy #endif 603