161145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy * CDDL HEADER START
4eda14cbcSMatt Macy *
5eda14cbcSMatt Macy * The contents of this file are subject to the terms of the
6eda14cbcSMatt Macy * Common Development and Distribution License (the "License").
7eda14cbcSMatt Macy * You may not use this file except in compliance with the License.
8eda14cbcSMatt Macy *
9eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
11eda14cbcSMatt Macy * See the License for the specific language governing permissions
12eda14cbcSMatt Macy * and limitations under the License.
13eda14cbcSMatt Macy *
14eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each
15eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the
17eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying
18eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner]
19eda14cbcSMatt Macy *
20eda14cbcSMatt Macy * CDDL HEADER END
21eda14cbcSMatt Macy */
22eda14cbcSMatt Macy
23eda14cbcSMatt Macy /*
24eda14cbcSMatt Macy * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
25eda14cbcSMatt Macy * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
26eda14cbcSMatt Macy * Copyright (c) 2013, Joyent, Inc. All rights reserved.
27eda14cbcSMatt Macy * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
28eda14cbcSMatt Macy * Copyright (c) 2017, Intel Corporation.
297a7741afSMartin Matuska * Copyright (c) 2019, 2024, Klara, Inc.
30eda14cbcSMatt Macy * Copyright (c) 2019, Allan Jude
31eda14cbcSMatt Macy */
32eda14cbcSMatt Macy
33eda14cbcSMatt Macy #ifndef _KERNEL
34eda14cbcSMatt Macy #include <errno.h>
35eda14cbcSMatt Macy #include <string.h>
36e92ffd9bSMartin Matuska #include <dirent.h>
37e92ffd9bSMartin Matuska #include <search.h>
38eda14cbcSMatt Macy #include <sys/stat.h>
39eda14cbcSMatt Macy #endif
40eda14cbcSMatt Macy #include <sys/debug.h>
41eda14cbcSMatt Macy #include <sys/fs/zfs.h>
42eda14cbcSMatt Macy #include <sys/inttypes.h>
43eda14cbcSMatt Macy #include <sys/types.h>
44eda14cbcSMatt Macy #include <sys/param.h>
45eda14cbcSMatt Macy #include <sys/zfs_sysfs.h>
46eda14cbcSMatt Macy #include "zfeature_common.h"
47eda14cbcSMatt Macy
48eda14cbcSMatt Macy /*
49eda14cbcSMatt Macy * Set to disable all feature checks while opening pools, allowing pools with
50eda14cbcSMatt Macy * unsupported features to be opened. Set for testing only.
51eda14cbcSMatt Macy */
52eda14cbcSMatt Macy boolean_t zfeature_checks_disable = B_FALSE;
53eda14cbcSMatt Macy
54eda14cbcSMatt Macy zfeature_info_t spa_feature_table[SPA_FEATURES];
55eda14cbcSMatt Macy
56eda14cbcSMatt Macy /*
57eda14cbcSMatt Macy * Valid characters for feature guids. This list is mainly for aesthetic
58eda14cbcSMatt Macy * purposes and could be expanded in the future. There are different allowed
59eda14cbcSMatt Macy * characters in the guids reverse dns portion (before the colon) and its
60eda14cbcSMatt Macy * short name (after the colon).
61eda14cbcSMatt Macy */
62eda14cbcSMatt Macy static int
valid_char(char c,boolean_t after_colon)63eda14cbcSMatt Macy valid_char(char c, boolean_t after_colon)
64eda14cbcSMatt Macy {
65eda14cbcSMatt Macy return ((c >= 'a' && c <= 'z') ||
66eda14cbcSMatt Macy (c >= '0' && c <= '9') ||
67eda14cbcSMatt Macy (after_colon && c == '_') ||
68eda14cbcSMatt Macy (!after_colon && (c == '.' || c == '-')));
69eda14cbcSMatt Macy }
70eda14cbcSMatt Macy
71eda14cbcSMatt Macy /*
72eda14cbcSMatt Macy * Every feature guid must contain exactly one colon which separates a reverse
73eda14cbcSMatt Macy * dns organization name from the feature's "short" name (e.g.
74eda14cbcSMatt Macy * "com.company:feature_name").
75eda14cbcSMatt Macy */
76eda14cbcSMatt Macy boolean_t
zfeature_is_valid_guid(const char * name)77eda14cbcSMatt Macy zfeature_is_valid_guid(const char *name)
78eda14cbcSMatt Macy {
79eda14cbcSMatt Macy int i;
80eda14cbcSMatt Macy boolean_t has_colon = B_FALSE;
81eda14cbcSMatt Macy
82eda14cbcSMatt Macy i = 0;
83eda14cbcSMatt Macy while (name[i] != '\0') {
84eda14cbcSMatt Macy char c = name[i++];
85eda14cbcSMatt Macy if (c == ':') {
86eda14cbcSMatt Macy if (has_colon)
87eda14cbcSMatt Macy return (B_FALSE);
88eda14cbcSMatt Macy has_colon = B_TRUE;
89eda14cbcSMatt Macy continue;
90eda14cbcSMatt Macy }
91eda14cbcSMatt Macy if (!valid_char(c, has_colon))
92eda14cbcSMatt Macy return (B_FALSE);
93eda14cbcSMatt Macy }
94eda14cbcSMatt Macy
95eda14cbcSMatt Macy return (has_colon);
96eda14cbcSMatt Macy }
97eda14cbcSMatt Macy
98eda14cbcSMatt Macy boolean_t
zfeature_is_supported(const char * guid)99eda14cbcSMatt Macy zfeature_is_supported(const char *guid)
100eda14cbcSMatt Macy {
101eda14cbcSMatt Macy if (zfeature_checks_disable)
102eda14cbcSMatt Macy return (B_TRUE);
103eda14cbcSMatt Macy
104eda14cbcSMatt Macy for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
105eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[i];
106c170aa9fSMartin Matuska if (!feature->fi_zfs_mod_supported)
107c170aa9fSMartin Matuska continue;
108eda14cbcSMatt Macy if (strcmp(guid, feature->fi_guid) == 0)
109eda14cbcSMatt Macy return (B_TRUE);
110eda14cbcSMatt Macy }
111eda14cbcSMatt Macy return (B_FALSE);
112eda14cbcSMatt Macy }
113eda14cbcSMatt Macy
114eda14cbcSMatt Macy int
zfeature_lookup_guid(const char * guid,spa_feature_t * res)115eda14cbcSMatt Macy zfeature_lookup_guid(const char *guid, spa_feature_t *res)
116eda14cbcSMatt Macy {
117eda14cbcSMatt Macy for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
118eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[i];
119eda14cbcSMatt Macy if (!feature->fi_zfs_mod_supported)
120eda14cbcSMatt Macy continue;
121eda14cbcSMatt Macy if (strcmp(guid, feature->fi_guid) == 0) {
122eda14cbcSMatt Macy if (res != NULL)
123eda14cbcSMatt Macy *res = i;
124eda14cbcSMatt Macy return (0);
125eda14cbcSMatt Macy }
126eda14cbcSMatt Macy }
127eda14cbcSMatt Macy
128eda14cbcSMatt Macy return (ENOENT);
129eda14cbcSMatt Macy }
130eda14cbcSMatt Macy
131eda14cbcSMatt Macy int
zfeature_lookup_name(const char * name,spa_feature_t * res)132eda14cbcSMatt Macy zfeature_lookup_name(const char *name, spa_feature_t *res)
133eda14cbcSMatt Macy {
134eda14cbcSMatt Macy for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
135eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[i];
136eda14cbcSMatt Macy if (!feature->fi_zfs_mod_supported)
137eda14cbcSMatt Macy continue;
138eda14cbcSMatt Macy if (strcmp(name, feature->fi_uname) == 0) {
139eda14cbcSMatt Macy if (res != NULL)
140eda14cbcSMatt Macy *res = i;
141eda14cbcSMatt Macy return (0);
142eda14cbcSMatt Macy }
143eda14cbcSMatt Macy }
144eda14cbcSMatt Macy
145eda14cbcSMatt Macy return (ENOENT);
146eda14cbcSMatt Macy }
147eda14cbcSMatt Macy
148eda14cbcSMatt Macy boolean_t
zfeature_depends_on(spa_feature_t fid,spa_feature_t check)149eda14cbcSMatt Macy zfeature_depends_on(spa_feature_t fid, spa_feature_t check)
150eda14cbcSMatt Macy {
151eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[fid];
152eda14cbcSMatt Macy
153eda14cbcSMatt Macy for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
154eda14cbcSMatt Macy if (feature->fi_depends[i] == check)
155eda14cbcSMatt Macy return (B_TRUE);
156eda14cbcSMatt Macy }
157eda14cbcSMatt Macy return (B_FALSE);
158eda14cbcSMatt Macy }
159eda14cbcSMatt Macy
160eda14cbcSMatt Macy static boolean_t
deps_contains_feature(const spa_feature_t * deps,const spa_feature_t feature)161eda14cbcSMatt Macy deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
162eda14cbcSMatt Macy {
163eda14cbcSMatt Macy for (int i = 0; deps[i] != SPA_FEATURE_NONE; i++)
164eda14cbcSMatt Macy if (deps[i] == feature)
165eda14cbcSMatt Macy return (B_TRUE);
166eda14cbcSMatt Macy
167eda14cbcSMatt Macy return (B_FALSE);
168eda14cbcSMatt Macy }
169eda14cbcSMatt Macy
170e92ffd9bSMartin Matuska #define STRCMP ((int(*)(const void *, const void *))&strcmp)
171e92ffd9bSMartin Matuska struct zfs_mod_supported_features {
172e92ffd9bSMartin Matuska void *tree;
173e92ffd9bSMartin Matuska boolean_t all_features;
174e92ffd9bSMartin Matuska };
175e92ffd9bSMartin Matuska
176e92ffd9bSMartin Matuska struct zfs_mod_supported_features *
zfs_mod_list_supported(const char * scope)177e92ffd9bSMartin Matuska zfs_mod_list_supported(const char *scope)
178e92ffd9bSMartin Matuska {
179e92ffd9bSMartin Matuska #if defined(__FreeBSD__) || defined(_KERNEL) || defined(LIB_ZPOOL_BUILD)
180e92ffd9bSMartin Matuska (void) scope;
181e92ffd9bSMartin Matuska return (NULL);
182e92ffd9bSMartin Matuska #else
183e92ffd9bSMartin Matuska struct zfs_mod_supported_features *ret = calloc(1, sizeof (*ret));
184e92ffd9bSMartin Matuska if (ret == NULL)
185e92ffd9bSMartin Matuska return (NULL);
186e92ffd9bSMartin Matuska
187e92ffd9bSMartin Matuska DIR *sysfs_dir = NULL;
188e92ffd9bSMartin Matuska char path[128];
189e92ffd9bSMartin Matuska
190e92ffd9bSMartin Matuska if (snprintf(path, sizeof (path), "%s/%s",
191e92ffd9bSMartin Matuska ZFS_SYSFS_DIR, scope) < sizeof (path))
192e92ffd9bSMartin Matuska sysfs_dir = opendir(path);
193e92ffd9bSMartin Matuska if (sysfs_dir == NULL && errno == ENOENT) {
194e92ffd9bSMartin Matuska if (snprintf(path, sizeof (path), "%s/%s",
195e92ffd9bSMartin Matuska ZFS_SYSFS_ALT_DIR, scope) < sizeof (path))
196e92ffd9bSMartin Matuska sysfs_dir = opendir(path);
197e92ffd9bSMartin Matuska }
198e92ffd9bSMartin Matuska if (sysfs_dir == NULL) {
199e92ffd9bSMartin Matuska ret->all_features = errno == ENOENT &&
200e92ffd9bSMartin Matuska (access(ZFS_SYSFS_DIR, F_OK) == 0 ||
201e92ffd9bSMartin Matuska access(ZFS_SYSFS_ALT_DIR, F_OK) == 0);
202e92ffd9bSMartin Matuska return (ret);
203e92ffd9bSMartin Matuska }
204e92ffd9bSMartin Matuska
205e92ffd9bSMartin Matuska struct dirent *node;
206e92ffd9bSMartin Matuska while ((node = readdir(sysfs_dir)) != NULL) {
207e92ffd9bSMartin Matuska if (strcmp(node->d_name, ".") == 0 ||
208e92ffd9bSMartin Matuska strcmp(node->d_name, "..") == 0)
209e92ffd9bSMartin Matuska continue;
210e92ffd9bSMartin Matuska
211e92ffd9bSMartin Matuska char *name = strdup(node->d_name);
212e92ffd9bSMartin Matuska if (name == NULL) {
213e92ffd9bSMartin Matuska goto nomem;
214e92ffd9bSMartin Matuska }
215e92ffd9bSMartin Matuska
216e92ffd9bSMartin Matuska if (tsearch(name, &ret->tree, STRCMP) == NULL) {
217e92ffd9bSMartin Matuska /*
218e92ffd9bSMartin Matuska * Don't bother checking for duplicate entries:
219e92ffd9bSMartin Matuska * we're iterating a single directory.
220e92ffd9bSMartin Matuska */
221e92ffd9bSMartin Matuska free(name);
222e92ffd9bSMartin Matuska goto nomem;
223e92ffd9bSMartin Matuska }
224e92ffd9bSMartin Matuska }
225e92ffd9bSMartin Matuska
226e92ffd9bSMartin Matuska end:
227e92ffd9bSMartin Matuska closedir(sysfs_dir);
228e92ffd9bSMartin Matuska return (ret);
229e92ffd9bSMartin Matuska
230e92ffd9bSMartin Matuska nomem:
231e92ffd9bSMartin Matuska zfs_mod_list_supported_free(ret);
232e92ffd9bSMartin Matuska ret = NULL;
233e92ffd9bSMartin Matuska goto end;
234e92ffd9bSMartin Matuska #endif
235e92ffd9bSMartin Matuska }
236e92ffd9bSMartin Matuska
237e92ffd9bSMartin Matuska void
zfs_mod_list_supported_free(struct zfs_mod_supported_features * list)238e92ffd9bSMartin Matuska zfs_mod_list_supported_free(struct zfs_mod_supported_features *list)
239e92ffd9bSMartin Matuska {
240e92ffd9bSMartin Matuska #if !defined(__FreeBSD__) && !defined(_KERNEL) && !defined(LIB_ZPOOL_BUILD)
241e92ffd9bSMartin Matuska if (list) {
242e92ffd9bSMartin Matuska tdestroy(list->tree, free);
243e92ffd9bSMartin Matuska free(list);
244e92ffd9bSMartin Matuska }
245e92ffd9bSMartin Matuska #else
246e92ffd9bSMartin Matuska (void) list;
247e92ffd9bSMartin Matuska #endif
248e92ffd9bSMartin Matuska }
249e92ffd9bSMartin Matuska
250eda14cbcSMatt Macy #if !defined(_KERNEL) && !defined(LIB_ZPOOL_BUILD)
251eda14cbcSMatt Macy static boolean_t
zfs_mod_supported_impl(const char * scope,const char * name,const char * sysfs)252eda14cbcSMatt Macy zfs_mod_supported_impl(const char *scope, const char *name, const char *sysfs)
253eda14cbcSMatt Macy {
254e92ffd9bSMartin Matuska char path[128];
255e92ffd9bSMartin Matuska if (snprintf(path, sizeof (path), "%s%s%s%s%s", sysfs,
256e92ffd9bSMartin Matuska scope == NULL ? "" : "/", scope ?: "",
257e92ffd9bSMartin Matuska name == NULL ? "" : "/", name ?: "") < sizeof (path))
258e92ffd9bSMartin Matuska return (access(path, F_OK) == 0);
259e92ffd9bSMartin Matuska else
260e92ffd9bSMartin Matuska return (B_FALSE);
261eda14cbcSMatt Macy }
262eda14cbcSMatt Macy
263eda14cbcSMatt Macy boolean_t
zfs_mod_supported(const char * scope,const char * name,const struct zfs_mod_supported_features * sfeatures)264e92ffd9bSMartin Matuska zfs_mod_supported(const char *scope, const char *name,
265e92ffd9bSMartin Matuska const struct zfs_mod_supported_features *sfeatures)
266eda14cbcSMatt Macy {
267eda14cbcSMatt Macy boolean_t supported;
268eda14cbcSMatt Macy
269e92ffd9bSMartin Matuska if (sfeatures != NULL)
270e92ffd9bSMartin Matuska return (sfeatures->all_features ||
271e92ffd9bSMartin Matuska tfind(name, &sfeatures->tree, STRCMP));
272e92ffd9bSMartin Matuska
273eda14cbcSMatt Macy /*
274eda14cbcSMatt Macy * Check both the primary and alternate sysfs locations to determine
275eda14cbcSMatt Macy * if the required functionality is supported.
276eda14cbcSMatt Macy */
277eda14cbcSMatt Macy supported = (zfs_mod_supported_impl(scope, name, ZFS_SYSFS_DIR) ||
278eda14cbcSMatt Macy zfs_mod_supported_impl(scope, name, ZFS_SYSFS_ALT_DIR));
279eda14cbcSMatt Macy
280eda14cbcSMatt Macy /*
281eda14cbcSMatt Macy * For backwards compatibility with kernel modules that predate
282eda14cbcSMatt Macy * supported feature/property checking. Report the feature/property
283eda14cbcSMatt Macy * as supported if the kernel module is loaded but the requested
284eda14cbcSMatt Macy * scope directory does not exist.
285eda14cbcSMatt Macy */
286eda14cbcSMatt Macy if (supported == B_FALSE) {
287e92ffd9bSMartin Matuska if ((access(ZFS_SYSFS_DIR, F_OK) == 0 &&
288e92ffd9bSMartin Matuska !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_DIR)) ||
289e92ffd9bSMartin Matuska (access(ZFS_SYSFS_ALT_DIR, F_OK) == 0 &&
290e92ffd9bSMartin Matuska !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_ALT_DIR))) {
291eda14cbcSMatt Macy supported = B_TRUE;
292eda14cbcSMatt Macy }
293eda14cbcSMatt Macy }
294eda14cbcSMatt Macy
295eda14cbcSMatt Macy return (supported);
296eda14cbcSMatt Macy }
297eda14cbcSMatt Macy #endif
298eda14cbcSMatt Macy
299eda14cbcSMatt Macy static boolean_t
zfs_mod_supported_feature(const char * name,const struct zfs_mod_supported_features * sfeatures)300e92ffd9bSMartin Matuska zfs_mod_supported_feature(const char *name,
301e92ffd9bSMartin Matuska const struct zfs_mod_supported_features *sfeatures)
302eda14cbcSMatt Macy {
303eda14cbcSMatt Macy /*
304eda14cbcSMatt Macy * The zfs module spa_feature_table[], whether in-kernel or in
305eda14cbcSMatt Macy * libzpool, always supports all the features. libzfs needs to
306eda14cbcSMatt Macy * query the running module, via sysfs, to determine which
307eda14cbcSMatt Macy * features are supported.
308eda14cbcSMatt Macy *
309eda14cbcSMatt Macy * The equivalent _can_ be done on FreeBSD by way of the sysctl
310ee36e25aSMartin Matuska * tree, but this has not been done yet. Therefore, we return
311681ce946SMartin Matuska * that all features are supported.
312eda14cbcSMatt Macy */
313dae17134SMartin Matuska
314dae17134SMartin Matuska #if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD) || defined(__FreeBSD__)
315e92ffd9bSMartin Matuska (void) name, (void) sfeatures;
316eda14cbcSMatt Macy return (B_TRUE);
317eda14cbcSMatt Macy #else
318e92ffd9bSMartin Matuska return (zfs_mod_supported(ZFS_SYSFS_POOL_FEATURES, name, sfeatures));
319eda14cbcSMatt Macy #endif
320eda14cbcSMatt Macy }
321eda14cbcSMatt Macy
322eda14cbcSMatt Macy static void
zfeature_register(spa_feature_t fid,const char * guid,const char * name,const char * desc,zfeature_flags_t flags,zfeature_type_t type,const spa_feature_t * deps,const struct zfs_mod_supported_features * sfeatures)323eda14cbcSMatt Macy zfeature_register(spa_feature_t fid, const char *guid, const char *name,
324eda14cbcSMatt Macy const char *desc, zfeature_flags_t flags, zfeature_type_t type,
325e92ffd9bSMartin Matuska const spa_feature_t *deps,
326e92ffd9bSMartin Matuska const struct zfs_mod_supported_features *sfeatures)
327eda14cbcSMatt Macy {
328eda14cbcSMatt Macy zfeature_info_t *feature = &spa_feature_table[fid];
329e92ffd9bSMartin Matuska static const spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
330eda14cbcSMatt Macy
331eda14cbcSMatt Macy ASSERT(name != NULL);
332eda14cbcSMatt Macy ASSERT(desc != NULL);
333eda14cbcSMatt Macy ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
334eda14cbcSMatt Macy (flags & ZFEATURE_FLAG_MOS) == 0);
335eda14cbcSMatt Macy ASSERT3U(fid, <, SPA_FEATURES);
336eda14cbcSMatt Macy ASSERT(zfeature_is_valid_guid(guid));
337eda14cbcSMatt Macy
338eda14cbcSMatt Macy if (deps == NULL)
339eda14cbcSMatt Macy deps = nodeps;
340eda14cbcSMatt Macy
341eda14cbcSMatt Macy VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) ||
342eda14cbcSMatt Macy (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET)));
343eda14cbcSMatt Macy
344eda14cbcSMatt Macy feature->fi_feature = fid;
345eda14cbcSMatt Macy feature->fi_guid = guid;
346eda14cbcSMatt Macy feature->fi_uname = name;
347eda14cbcSMatt Macy feature->fi_desc = desc;
348eda14cbcSMatt Macy feature->fi_flags = flags;
349eda14cbcSMatt Macy feature->fi_type = type;
350eda14cbcSMatt Macy feature->fi_depends = deps;
351e92ffd9bSMartin Matuska feature->fi_zfs_mod_supported =
352e92ffd9bSMartin Matuska zfs_mod_supported_feature(guid, sfeatures);
353eda14cbcSMatt Macy }
354eda14cbcSMatt Macy
355eda14cbcSMatt Macy /*
356eda14cbcSMatt Macy * Every feature has a GUID of the form com.example:feature_name. The
357eda14cbcSMatt Macy * reversed DNS name ensures that the feature's GUID is unique across all ZFS
358eda14cbcSMatt Macy * implementations. This allows companies to independently develop and
359eda14cbcSMatt Macy * release features. Examples include org.delphix and org.datto. Previously,
360eda14cbcSMatt Macy * features developed on one implementation have used that implementation's
361eda14cbcSMatt Macy * domain name (e.g. org.illumos and org.zfsonlinux). Use of the org.openzfs
362eda14cbcSMatt Macy * domain name is recommended for new features which are developed by the
363eda14cbcSMatt Macy * OpenZFS community and its platforms. This domain may optionally be used by
364eda14cbcSMatt Macy * companies developing features for initial release through an OpenZFS
365eda14cbcSMatt Macy * implementation. Use of the org.openzfs domain requires reserving the
366eda14cbcSMatt Macy * feature name in advance with the OpenZFS project.
367eda14cbcSMatt Macy */
368eda14cbcSMatt Macy void
zpool_feature_init(void)369eda14cbcSMatt Macy zpool_feature_init(void)
370eda14cbcSMatt Macy {
371e92ffd9bSMartin Matuska struct zfs_mod_supported_features *sfeatures =
372e92ffd9bSMartin Matuska zfs_mod_list_supported(ZFS_SYSFS_POOL_FEATURES);
373e92ffd9bSMartin Matuska
374eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
375eda14cbcSMatt Macy "com.delphix:async_destroy", "async_destroy",
376eda14cbcSMatt Macy "Destroy filesystems asynchronously.",
377e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
378e92ffd9bSMartin Matuska sfeatures);
379eda14cbcSMatt Macy
380eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
381eda14cbcSMatt Macy "com.delphix:empty_bpobj", "empty_bpobj",
382eda14cbcSMatt Macy "Snapshots use less space.",
383e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
384e92ffd9bSMartin Matuska sfeatures);
385eda14cbcSMatt Macy
386eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
387eda14cbcSMatt Macy "org.illumos:lz4_compress", "lz4_compress",
388eda14cbcSMatt Macy "LZ4 compression algorithm support.",
389e92ffd9bSMartin Matuska ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL,
390e92ffd9bSMartin Matuska sfeatures);
391eda14cbcSMatt Macy
392eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
393eda14cbcSMatt Macy "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
394eda14cbcSMatt Macy "Crash dumps to multiple vdev pools.",
395e92ffd9bSMartin Matuska 0, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
396eda14cbcSMatt Macy
397eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
398eda14cbcSMatt Macy "com.delphix:spacemap_histogram", "spacemap_histogram",
399eda14cbcSMatt Macy "Spacemaps maintain space histograms.",
400e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
401e92ffd9bSMartin Matuska sfeatures);
402eda14cbcSMatt Macy
403eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ENABLED_TXG,
404eda14cbcSMatt Macy "com.delphix:enabled_txg", "enabled_txg",
405eda14cbcSMatt Macy "Record txg at which a feature is enabled",
406e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
407e92ffd9bSMartin Matuska sfeatures);
408eda14cbcSMatt Macy
409eda14cbcSMatt Macy {
410eda14cbcSMatt Macy static const spa_feature_t hole_birth_deps[] = {
411eda14cbcSMatt Macy SPA_FEATURE_ENABLED_TXG,
412eda14cbcSMatt Macy SPA_FEATURE_NONE
413eda14cbcSMatt Macy };
414eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_HOLE_BIRTH,
415eda14cbcSMatt Macy "com.delphix:hole_birth", "hole_birth",
416eda14cbcSMatt Macy "Retain hole birth txg for more precise zfs send",
417eda14cbcSMatt Macy ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
418e92ffd9bSMartin Matuska ZFEATURE_TYPE_BOOLEAN, hole_birth_deps, sfeatures);
419eda14cbcSMatt Macy }
420eda14cbcSMatt Macy
421eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_POOL_CHECKPOINT,
422eda14cbcSMatt Macy "com.delphix:zpool_checkpoint", "zpool_checkpoint",
423eda14cbcSMatt Macy "Pool state can be checkpointed, allowing rewind later.",
424e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
425e92ffd9bSMartin Matuska sfeatures);
426eda14cbcSMatt Macy
427eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SPACEMAP_V2,
428eda14cbcSMatt Macy "com.delphix:spacemap_v2", "spacemap_v2",
429eda14cbcSMatt Macy "Space maps representing large segments are more efficient.",
430eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
431e92ffd9bSMartin Matuska ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
432eda14cbcSMatt Macy
433eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
434eda14cbcSMatt Macy "com.delphix:extensible_dataset", "extensible_dataset",
435eda14cbcSMatt Macy "Enhanced dataset functionality, used by other features.",
436e92ffd9bSMartin Matuska 0, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
437eda14cbcSMatt Macy
438eda14cbcSMatt Macy {
439eda14cbcSMatt Macy static const spa_feature_t bookmarks_deps[] = {
440eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
441eda14cbcSMatt Macy SPA_FEATURE_NONE
442eda14cbcSMatt Macy };
443eda14cbcSMatt Macy
444eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_BOOKMARKS,
445eda14cbcSMatt Macy "com.delphix:bookmarks", "bookmarks",
446eda14cbcSMatt Macy "\"zfs bookmark\" command",
447eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
448e92ffd9bSMartin Matuska bookmarks_deps, sfeatures);
449eda14cbcSMatt Macy }
450eda14cbcSMatt Macy
451eda14cbcSMatt Macy {
452eda14cbcSMatt Macy static const spa_feature_t filesystem_limits_deps[] = {
453eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
454eda14cbcSMatt Macy SPA_FEATURE_NONE
455eda14cbcSMatt Macy };
456eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
457eda14cbcSMatt Macy "com.joyent:filesystem_limits", "filesystem_limits",
458eda14cbcSMatt Macy "Filesystem and snapshot limits.",
459eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
460e92ffd9bSMartin Matuska filesystem_limits_deps, sfeatures);
461eda14cbcSMatt Macy }
462eda14cbcSMatt Macy
463eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
464eda14cbcSMatt Macy "com.delphix:embedded_data", "embedded_data",
465eda14cbcSMatt Macy "Blocks which compress very well use even less space.",
466eda14cbcSMatt Macy ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
467e92ffd9bSMartin Matuska ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
468eda14cbcSMatt Macy
469eda14cbcSMatt Macy {
470eda14cbcSMatt Macy static const spa_feature_t livelist_deps[] = {
471eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
472eda14cbcSMatt Macy SPA_FEATURE_NONE
473eda14cbcSMatt Macy };
474eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LIVELIST,
475eda14cbcSMatt Macy "com.delphix:livelist", "livelist",
476eda14cbcSMatt Macy "Improved clone deletion performance.",
477eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
478e92ffd9bSMartin Matuska livelist_deps, sfeatures);
479eda14cbcSMatt Macy }
480eda14cbcSMatt Macy
481eda14cbcSMatt Macy {
482eda14cbcSMatt Macy static const spa_feature_t log_spacemap_deps[] = {
483eda14cbcSMatt Macy SPA_FEATURE_SPACEMAP_V2,
484eda14cbcSMatt Macy SPA_FEATURE_NONE
485eda14cbcSMatt Macy };
486eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LOG_SPACEMAP,
487eda14cbcSMatt Macy "com.delphix:log_spacemap", "log_spacemap",
488eda14cbcSMatt Macy "Log metaslab changes on a single spacemap and "
489eda14cbcSMatt Macy "flush them periodically.",
490eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
491e92ffd9bSMartin Matuska log_spacemap_deps, sfeatures);
492eda14cbcSMatt Macy }
493eda14cbcSMatt Macy
494eda14cbcSMatt Macy {
495eda14cbcSMatt Macy static const spa_feature_t large_blocks_deps[] = {
496eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
497eda14cbcSMatt Macy SPA_FEATURE_NONE
498eda14cbcSMatt Macy };
499eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
500eda14cbcSMatt Macy "org.open-zfs:large_blocks", "large_blocks",
501eda14cbcSMatt Macy "Support for blocks larger than 128KB.",
502eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
503e92ffd9bSMartin Matuska large_blocks_deps, sfeatures);
504eda14cbcSMatt Macy }
505eda14cbcSMatt Macy
506eda14cbcSMatt Macy {
507eda14cbcSMatt Macy static const spa_feature_t large_dnode_deps[] = {
508eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
509eda14cbcSMatt Macy SPA_FEATURE_NONE
510eda14cbcSMatt Macy };
511eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_LARGE_DNODE,
512eda14cbcSMatt Macy "org.zfsonlinux:large_dnode", "large_dnode",
513eda14cbcSMatt Macy "Variable on-disk size of dnodes.",
514eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
515e92ffd9bSMartin Matuska large_dnode_deps, sfeatures);
516eda14cbcSMatt Macy }
517eda14cbcSMatt Macy
518eda14cbcSMatt Macy {
519eda14cbcSMatt Macy static const spa_feature_t sha512_deps[] = {
520eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
521eda14cbcSMatt Macy SPA_FEATURE_NONE
522eda14cbcSMatt Macy };
523eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SHA512,
524eda14cbcSMatt Macy "org.illumos:sha512", "sha512",
525eda14cbcSMatt Macy "SHA-512/256 hash algorithm.",
526eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
527e92ffd9bSMartin Matuska sha512_deps, sfeatures);
528eda14cbcSMatt Macy }
529eda14cbcSMatt Macy
530eda14cbcSMatt Macy {
531eda14cbcSMatt Macy static const spa_feature_t skein_deps[] = {
532eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
533eda14cbcSMatt Macy SPA_FEATURE_NONE
534eda14cbcSMatt Macy };
535eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_SKEIN,
536eda14cbcSMatt Macy "org.illumos:skein", "skein",
537eda14cbcSMatt Macy "Skein hash algorithm.",
538eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
539e92ffd9bSMartin Matuska skein_deps, sfeatures);
540eda14cbcSMatt Macy }
541eda14cbcSMatt Macy
542eda14cbcSMatt Macy {
543eda14cbcSMatt Macy static const spa_feature_t edonr_deps[] = {
544eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
545eda14cbcSMatt Macy SPA_FEATURE_NONE
546eda14cbcSMatt Macy };
547eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_EDONR,
548eda14cbcSMatt Macy "org.illumos:edonr", "edonr",
549eda14cbcSMatt Macy "Edon-R hash algorithm.",
550eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
551e92ffd9bSMartin Matuska edonr_deps, sfeatures);
552eda14cbcSMatt Macy }
553eda14cbcSMatt Macy
554eda14cbcSMatt Macy {
555eda14cbcSMatt Macy static const spa_feature_t redact_books_deps[] = {
556eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_V2,
557eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
558eda14cbcSMatt Macy SPA_FEATURE_BOOKMARKS,
559eda14cbcSMatt Macy SPA_FEATURE_NONE
560eda14cbcSMatt Macy };
561eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_REDACTION_BOOKMARKS,
562eda14cbcSMatt Macy "com.delphix:redaction_bookmarks", "redaction_bookmarks",
563eda14cbcSMatt Macy "Support for bookmarks which store redaction lists for zfs "
564eda14cbcSMatt Macy "redacted send/recv.", 0, ZFEATURE_TYPE_BOOLEAN,
565e92ffd9bSMartin Matuska redact_books_deps, sfeatures);
566eda14cbcSMatt Macy }
567eda14cbcSMatt Macy
568eda14cbcSMatt Macy {
569eda14cbcSMatt Macy static const spa_feature_t redact_datasets_deps[] = {
570eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
571eda14cbcSMatt Macy SPA_FEATURE_NONE
572eda14cbcSMatt Macy };
573eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_REDACTED_DATASETS,
574e92ffd9bSMartin Matuska "com.delphix:redacted_datasets", "redacted_datasets",
575e92ffd9bSMartin Matuska "Support for redacted datasets, produced by receiving "
576e92ffd9bSMartin Matuska "a redacted zfs send stream.",
577e92ffd9bSMartin Matuska ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_UINT64_ARRAY,
578e92ffd9bSMartin Matuska redact_datasets_deps, sfeatures);
579eda14cbcSMatt Macy }
580eda14cbcSMatt Macy
581eda14cbcSMatt Macy {
582eda14cbcSMatt Macy static const spa_feature_t bookmark_written_deps[] = {
583eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_V2,
584eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
585eda14cbcSMatt Macy SPA_FEATURE_BOOKMARKS,
586eda14cbcSMatt Macy SPA_FEATURE_NONE
587eda14cbcSMatt Macy };
588eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_BOOKMARK_WRITTEN,
589eda14cbcSMatt Macy "com.delphix:bookmark_written", "bookmark_written",
590e92ffd9bSMartin Matuska "Additional accounting, enabling the written#<bookmark> "
591e92ffd9bSMartin Matuska "property (space written since a bookmark), "
592e92ffd9bSMartin Matuska "and estimates of send stream sizes for incrementals from "
593e92ffd9bSMartin Matuska "bookmarks.",
594e92ffd9bSMartin Matuska 0, ZFEATURE_TYPE_BOOLEAN, bookmark_written_deps, sfeatures);
595eda14cbcSMatt Macy }
596eda14cbcSMatt Macy
597eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_DEVICE_REMOVAL,
598eda14cbcSMatt Macy "com.delphix:device_removal", "device_removal",
599eda14cbcSMatt Macy "Top-level vdevs can be removed, reducing logical pool size.",
600e92ffd9bSMartin Matuska ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
601eda14cbcSMatt Macy
602eda14cbcSMatt Macy {
603eda14cbcSMatt Macy static const spa_feature_t obsolete_counts_deps[] = {
604eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
605eda14cbcSMatt Macy SPA_FEATURE_DEVICE_REMOVAL,
606eda14cbcSMatt Macy SPA_FEATURE_NONE
607eda14cbcSMatt Macy };
608eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_OBSOLETE_COUNTS,
609eda14cbcSMatt Macy "com.delphix:obsolete_counts", "obsolete_counts",
610e92ffd9bSMartin Matuska "Reduce memory used by removed devices when their blocks "
611e92ffd9bSMartin Matuska "are freed or remapped.",
612eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
613e92ffd9bSMartin Matuska obsolete_counts_deps, sfeatures);
614eda14cbcSMatt Macy }
615eda14cbcSMatt Macy
616eda14cbcSMatt Macy {
617eda14cbcSMatt Macy static const spa_feature_t userobj_accounting_deps[] = {
618eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
619eda14cbcSMatt Macy SPA_FEATURE_NONE
620eda14cbcSMatt Macy };
621eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
622eda14cbcSMatt Macy "org.zfsonlinux:userobj_accounting", "userobj_accounting",
623eda14cbcSMatt Macy "User/Group object accounting.",
624eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
625e92ffd9bSMartin Matuska ZFEATURE_TYPE_BOOLEAN, userobj_accounting_deps, sfeatures);
626eda14cbcSMatt Macy }
627eda14cbcSMatt Macy
628eda14cbcSMatt Macy {
629eda14cbcSMatt Macy static const spa_feature_t bookmark_v2_deps[] = {
630eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
631eda14cbcSMatt Macy SPA_FEATURE_BOOKMARKS,
632eda14cbcSMatt Macy SPA_FEATURE_NONE
633eda14cbcSMatt Macy };
634eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_BOOKMARK_V2,
635eda14cbcSMatt Macy "com.datto:bookmark_v2", "bookmark_v2",
636eda14cbcSMatt Macy "Support for larger bookmarks",
637e92ffd9bSMartin Matuska 0, ZFEATURE_TYPE_BOOLEAN, bookmark_v2_deps, sfeatures);
638eda14cbcSMatt Macy }
639eda14cbcSMatt Macy
640eda14cbcSMatt Macy {
641eda14cbcSMatt Macy static const spa_feature_t encryption_deps[] = {
642eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
643eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_V2,
644eda14cbcSMatt Macy SPA_FEATURE_NONE
645eda14cbcSMatt Macy };
646eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ENCRYPTION,
647eda14cbcSMatt Macy "com.datto:encryption", "encryption",
648eda14cbcSMatt Macy "Support for dataset level encryption",
649eda14cbcSMatt Macy ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
650e92ffd9bSMartin Matuska encryption_deps, sfeatures);
651eda14cbcSMatt Macy }
652eda14cbcSMatt Macy
653eda14cbcSMatt Macy {
654eda14cbcSMatt Macy static const spa_feature_t project_quota_deps[] = {
655eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
656eda14cbcSMatt Macy SPA_FEATURE_NONE
657eda14cbcSMatt Macy };
658eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_PROJECT_QUOTA,
659eda14cbcSMatt Macy "org.zfsonlinux:project_quota", "project_quota",
660eda14cbcSMatt Macy "space/object accounting based on project ID.",
661eda14cbcSMatt Macy ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
662e92ffd9bSMartin Matuska ZFEATURE_TYPE_BOOLEAN, project_quota_deps, sfeatures);
663eda14cbcSMatt Macy }
664eda14cbcSMatt Macy
665eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ALLOCATION_CLASSES,
666eda14cbcSMatt Macy "org.zfsonlinux:allocation_classes", "allocation_classes",
667eda14cbcSMatt Macy "Support for separate allocation classes.",
668e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
669e92ffd9bSMartin Matuska sfeatures);
670eda14cbcSMatt Macy
671eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_RESILVER_DEFER,
672eda14cbcSMatt Macy "com.datto:resilver_defer", "resilver_defer",
673eda14cbcSMatt Macy "Support for deferring new resilvers when one is already running.",
674e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
675e92ffd9bSMartin Matuska sfeatures);
676eda14cbcSMatt Macy
677eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_DEVICE_REBUILD,
678eda14cbcSMatt Macy "org.openzfs:device_rebuild", "device_rebuild",
6797877fdebSMatt Macy "Support for sequential mirror/dRAID device rebuilds",
680e92ffd9bSMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
681e92ffd9bSMartin Matuska sfeatures);
682eda14cbcSMatt Macy
683eda14cbcSMatt Macy {
684eda14cbcSMatt Macy static const spa_feature_t zstd_deps[] = {
685eda14cbcSMatt Macy SPA_FEATURE_EXTENSIBLE_DATASET,
686eda14cbcSMatt Macy SPA_FEATURE_NONE
687eda14cbcSMatt Macy };
688eda14cbcSMatt Macy zfeature_register(SPA_FEATURE_ZSTD_COMPRESS,
689eda14cbcSMatt Macy "org.freebsd:zstd_compress", "zstd_compress",
690eda14cbcSMatt Macy "zstd compression algorithm support.",
691e92ffd9bSMartin Matuska ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, zstd_deps,
692e92ffd9bSMartin Matuska sfeatures);
693eda14cbcSMatt Macy }
6947877fdebSMatt Macy
6957877fdebSMatt Macy zfeature_register(SPA_FEATURE_DRAID,
6967877fdebSMatt Macy "org.openzfs:draid", "draid", "Support for distributed spare RAID",
697e92ffd9bSMartin Matuska ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
698e92ffd9bSMartin Matuska
699c03c5b1cSMartin Matuska {
700c03c5b1cSMartin Matuska static const spa_feature_t zilsaxattr_deps[] = {
701c03c5b1cSMartin Matuska SPA_FEATURE_EXTENSIBLE_DATASET,
702c03c5b1cSMartin Matuska SPA_FEATURE_NONE
703c03c5b1cSMartin Matuska };
704c03c5b1cSMartin Matuska zfeature_register(SPA_FEATURE_ZILSAXATTR,
705c03c5b1cSMartin Matuska "org.openzfs:zilsaxattr", "zilsaxattr",
706c03c5b1cSMartin Matuska "Support for xattr=sa extended attribute logging in ZIL.",
707c03c5b1cSMartin Matuska ZFEATURE_FLAG_PER_DATASET | ZFEATURE_FLAG_READONLY_COMPAT,
708c03c5b1cSMartin Matuska ZFEATURE_TYPE_BOOLEAN, zilsaxattr_deps, sfeatures);
709c03c5b1cSMartin Matuska }
710c03c5b1cSMartin Matuska
711716fd348SMartin Matuska zfeature_register(SPA_FEATURE_HEAD_ERRLOG,
712716fd348SMartin Matuska "com.delphix:head_errlog", "head_errlog",
713716fd348SMartin Matuska "Support for per-dataset on-disk error logs.",
714716fd348SMartin Matuska ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL,
715716fd348SMartin Matuska sfeatures);
716716fd348SMartin Matuska
7171f1e2261SMartin Matuska {
7181f1e2261SMartin Matuska static const spa_feature_t blake3_deps[] = {
7191f1e2261SMartin Matuska SPA_FEATURE_EXTENSIBLE_DATASET,
7201f1e2261SMartin Matuska SPA_FEATURE_NONE
7211f1e2261SMartin Matuska };
7221f1e2261SMartin Matuska zfeature_register(SPA_FEATURE_BLAKE3,
7231f1e2261SMartin Matuska "org.openzfs:blake3", "blake3",
7241f1e2261SMartin Matuska "BLAKE3 hash algorithm.",
7251f1e2261SMartin Matuska ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
7261f1e2261SMartin Matuska blake3_deps, sfeatures);
7271f1e2261SMartin Matuska }
7281f1e2261SMartin Matuska
7292a58b312SMartin Matuska zfeature_register(SPA_FEATURE_BLOCK_CLONING,
7302a58b312SMartin Matuska "com.fudosecurity:block_cloning", "block_cloning",
7312a58b312SMartin Matuska "Support for block cloning via Block Reference Table.",
7322a58b312SMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
7332a58b312SMartin Matuska sfeatures);
7342a58b312SMartin Matuska
735*df58e8b1SMartin Matuska zfeature_register(SPA_FEATURE_BLOCK_CLONING_ENDIAN,
736*df58e8b1SMartin Matuska "com.truenas:block_cloning_endian", "block_cloning_endian",
737*df58e8b1SMartin Matuska "Fixes BRT ZAP endianness on new pools.",
738*df58e8b1SMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
739*df58e8b1SMartin Matuska sfeatures);
740*df58e8b1SMartin Matuska
741d411c1d6SMartin Matuska zfeature_register(SPA_FEATURE_AVZ_V2,
742d411c1d6SMartin Matuska "com.klarasystems:vdev_zaps_v2", "vdev_zaps_v2",
743d411c1d6SMartin Matuska "Support for root vdev ZAP.",
744d411c1d6SMartin Matuska ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL,
745d411c1d6SMartin Matuska sfeatures);
746d411c1d6SMartin Matuska
7472ad756a6SMartin Matuska {
7482ad756a6SMartin Matuska static const spa_feature_t redact_list_spill_deps[] = {
7492ad756a6SMartin Matuska SPA_FEATURE_REDACTION_BOOKMARKS,
7502ad756a6SMartin Matuska SPA_FEATURE_NONE
7512ad756a6SMartin Matuska };
7522ad756a6SMartin Matuska zfeature_register(SPA_FEATURE_REDACTION_LIST_SPILL,
7532ad756a6SMartin Matuska "com.delphix:redaction_list_spill", "redaction_list_spill",
7542ad756a6SMartin Matuska "Support for increased number of redaction_snapshot "
7552ad756a6SMartin Matuska "arguments in zfs redact.", 0, ZFEATURE_TYPE_BOOLEAN,
7562ad756a6SMartin Matuska redact_list_spill_deps, sfeatures);
7572ad756a6SMartin Matuska }
7582ad756a6SMartin Matuska
759e716630dSMartin Matuska zfeature_register(SPA_FEATURE_RAIDZ_EXPANSION,
760e716630dSMartin Matuska "org.openzfs:raidz_expansion", "raidz_expansion",
761e716630dSMartin Matuska "Support for raidz expansion",
762e716630dSMartin Matuska ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
763e716630dSMartin Matuska
764e2df9bb4SMartin Matuska zfeature_register(SPA_FEATURE_FAST_DEDUP,
765e2df9bb4SMartin Matuska "com.klarasystems:fast_dedup", "fast_dedup",
766e2df9bb4SMartin Matuska "Support for advanced deduplication",
767e2df9bb4SMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
768e2df9bb4SMartin Matuska sfeatures);
769e2df9bb4SMartin Matuska
7707a7741afSMartin Matuska {
7717a7741afSMartin Matuska static const spa_feature_t longname_deps[] = {
7727a7741afSMartin Matuska SPA_FEATURE_EXTENSIBLE_DATASET,
7737a7741afSMartin Matuska SPA_FEATURE_NONE
7747a7741afSMartin Matuska };
7757a7741afSMartin Matuska zfeature_register(SPA_FEATURE_LONGNAME,
7767a7741afSMartin Matuska "org.zfsonlinux:longname", "longname",
7777a7741afSMartin Matuska "support filename up to 1024 bytes",
7787a7741afSMartin Matuska ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
7797a7741afSMartin Matuska longname_deps, sfeatures);
7807a7741afSMartin Matuska }
7817a7741afSMartin Matuska
7827a7741afSMartin Matuska {
7837a7741afSMartin Matuska static const spa_feature_t large_microzap_deps[] = {
7847a7741afSMartin Matuska SPA_FEATURE_EXTENSIBLE_DATASET,
7857a7741afSMartin Matuska SPA_FEATURE_LARGE_BLOCKS,
7867a7741afSMartin Matuska SPA_FEATURE_NONE
7877a7741afSMartin Matuska };
7887a7741afSMartin Matuska zfeature_register(SPA_FEATURE_LARGE_MICROZAP,
7897a7741afSMartin Matuska "com.klarasystems:large_microzap", "large_microzap",
7907a7741afSMartin Matuska "Support for microzaps larger than 128KB.",
7917a7741afSMartin Matuska ZFEATURE_FLAG_PER_DATASET | ZFEATURE_FLAG_READONLY_COMPAT,
7927a7741afSMartin Matuska ZFEATURE_TYPE_BOOLEAN, large_microzap_deps, sfeatures);
7937a7741afSMartin Matuska }
7947a7741afSMartin Matuska
795*df58e8b1SMartin Matuska zfeature_register(SPA_FEATURE_DYNAMIC_GANG_HEADER,
796*df58e8b1SMartin Matuska "com.klarasystems:dynamic_gang_header", "dynamic_gang_header",
797*df58e8b1SMartin Matuska "Support for dynamically sized gang headers",
798*df58e8b1SMartin Matuska ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_NO_UPGRADE,
799*df58e8b1SMartin Matuska ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
800*df58e8b1SMartin Matuska
801*df58e8b1SMartin Matuska {
802*df58e8b1SMartin Matuska static const spa_feature_t physical_rewrite_deps[] = {
803*df58e8b1SMartin Matuska SPA_FEATURE_EXTENSIBLE_DATASET,
804*df58e8b1SMartin Matuska SPA_FEATURE_NONE
805*df58e8b1SMartin Matuska };
806*df58e8b1SMartin Matuska zfeature_register(SPA_FEATURE_PHYSICAL_REWRITE,
807*df58e8b1SMartin Matuska "com.truenas:physical_rewrite", "physical_rewrite",
808*df58e8b1SMartin Matuska "Support for preserving logical birth time during rewrite.",
809*df58e8b1SMartin Matuska ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
810*df58e8b1SMartin Matuska ZFEATURE_TYPE_BOOLEAN, physical_rewrite_deps, sfeatures);
811*df58e8b1SMartin Matuska }
812*df58e8b1SMartin Matuska
813e92ffd9bSMartin Matuska zfs_mod_list_supported_free(sfeatures);
814eda14cbcSMatt Macy }
815eda14cbcSMatt Macy
816eda14cbcSMatt Macy #if defined(_KERNEL)
817eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_lookup_guid);
818eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_lookup_name);
819eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_is_supported);
820eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_is_valid_guid);
821eda14cbcSMatt Macy EXPORT_SYMBOL(zfeature_depends_on);
822eda14cbcSMatt Macy EXPORT_SYMBOL(zpool_feature_init);
823eda14cbcSMatt Macy EXPORT_SYMBOL(spa_feature_table);
824eda14cbcSMatt Macy #endif
825