xref: /freebsd-src/sys/contrib/openzfs/module/zcommon/zfeature_common.c (revision eda14cbc264d6969b02f2b1994cef11148e914f1)
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