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