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