aboutsummaryrefslogtreecommitdiffstats
path: root/module/zcommon/zfeature_common.c
diff options
context:
space:
mode:
authorнаб <[email protected]>2021-12-17 01:43:10 +0100
committerGitHub <[email protected]>2021-12-16 16:43:10 -0800
commiteb51a9d74742bd2dc4e31c1806532149593101df (patch)
treed3ec2ed57a9a8e573f5304f6ca401160fe4ed3a9 /module/zcommon/zfeature_common.c
parent8fdc6f618cf19e1894f5a803e043e80e762a86b1 (diff)
zcommon: pre-iterate over sysfs instead of statting every feature
If sufficient memory (<2K, realistically) is available, libzfs_init() can be significantly shorted by iterating over the correct sysfs directory before registrations, we can turn 168 stats into 15/18 syscalls (3 opens (6 if built in), 3 fstats, 6 getdentses, and 3 closes), a tenfoldish reduction; this is probably a bit faster, too. The list is always optional, and registration functions (and one-off users) can simply pass NULL, which will fall back to the previous mechanism Also, don't allocate in zfs_mod_supported_impl, and use use access() instead of stat(), since existence is really what we care about Also, fix pre-prop-checking compat in fallback for built-in ZFS Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Tony Nguyen <[email protected]> Signed-off-by: Ahelenia Ziemiańska <[email protected]> Closes #12089
Diffstat (limited to 'module/zcommon/zfeature_common.c')
-rw-r--r--module/zcommon/zfeature_common.c537
1 files changed, 319 insertions, 218 deletions
diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c
index 8d84c6d15..c7278fa00 100644
--- a/module/zcommon/zfeature_common.c
+++ b/module/zcommon/zfeature_common.c
@@ -32,6 +32,8 @@
#ifndef _KERNEL
#include <errno.h>
#include <string.h>
+#include <dirent.h>
+#include <search.h>
#include <sys/stat.h>
#endif
#include <sys/debug.h>
@@ -164,30 +166,109 @@ deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
return (B_FALSE);
}
+#define STRCMP ((int(*)(const void *, const void *))&strcmp)
+struct zfs_mod_supported_features {
+ void *tree;
+ boolean_t all_features;
+};
+
+struct zfs_mod_supported_features *
+zfs_mod_list_supported(const char *scope)
+{
+#if defined(__FreeBSD__) || defined(_KERNEL) || defined(LIB_ZPOOL_BUILD)
+ (void) scope;
+ return (NULL);
+#else
+ struct zfs_mod_supported_features *ret = calloc(1, sizeof (*ret));
+ if (ret == NULL)
+ return (NULL);
+
+ DIR *sysfs_dir = NULL;
+ char path[128];
+
+ if (snprintf(path, sizeof (path), "%s/%s",
+ ZFS_SYSFS_DIR, scope) < sizeof (path))
+ sysfs_dir = opendir(path);
+ if (sysfs_dir == NULL && errno == ENOENT) {
+ if (snprintf(path, sizeof (path), "%s/%s",
+ ZFS_SYSFS_ALT_DIR, scope) < sizeof (path))
+ sysfs_dir = opendir(path);
+ }
+ if (sysfs_dir == NULL) {
+ ret->all_features = errno == ENOENT &&
+ (access(ZFS_SYSFS_DIR, F_OK) == 0 ||
+ access(ZFS_SYSFS_ALT_DIR, F_OK) == 0);
+ return (ret);
+ }
+
+ struct dirent *node;
+ while ((node = readdir(sysfs_dir)) != NULL) {
+ if (strcmp(node->d_name, ".") == 0 ||
+ strcmp(node->d_name, "..") == 0)
+ continue;
+
+ char *name = strdup(node->d_name);
+ if (name == NULL) {
+ goto nomem;
+ }
+
+ if (tsearch(name, &ret->tree, STRCMP) == NULL) {
+ /*
+ * Don't bother checking for duplicate entries:
+ * we're iterating a single directory.
+ */
+ free(name);
+ goto nomem;
+ }
+ }
+
+end:
+ closedir(sysfs_dir);
+ return (ret);
+
+nomem:
+ zfs_mod_list_supported_free(ret);
+ ret = NULL;
+ goto end;
+#endif
+}
+
+void
+zfs_mod_list_supported_free(struct zfs_mod_supported_features *list)
+{
+#if !defined(__FreeBSD__) && !defined(_KERNEL) && !defined(LIB_ZPOOL_BUILD)
+ if (list) {
+ tdestroy(list->tree, free);
+ free(list);
+ }
+#else
+ (void) list;
+#endif
+}
+
#if !defined(_KERNEL) && !defined(LIB_ZPOOL_BUILD)
static boolean_t
zfs_mod_supported_impl(const char *scope, const char *name, const char *sysfs)
{
- boolean_t supported = B_FALSE;
- char *path;
-
- int len = asprintf(&path, "%s%s%s%s%s", sysfs,
- scope == NULL ? "" : "/", scope == NULL ? "" : scope,
- name == NULL ? "" : "/", name == NULL ? "" : name);
- if (len > 0) {
- struct stat64 statbuf;
- supported = !!(stat64(path, &statbuf) == 0);
- free(path);
- }
-
- return (supported);
+ char path[128];
+ if (snprintf(path, sizeof (path), "%s%s%s%s%s", sysfs,
+ scope == NULL ? "" : "/", scope ?: "",
+ name == NULL ? "" : "/", name ?: "") < sizeof (path))
+ return (access(path, F_OK) == 0);
+ else
+ return (B_FALSE);
}
boolean_t
-zfs_mod_supported(const char *scope, const char *name)
+zfs_mod_supported(const char *scope, const char *name,
+ const struct zfs_mod_supported_features *sfeatures)
{
boolean_t supported;
+ if (sfeatures != NULL)
+ return (sfeatures->all_features ||
+ tfind(name, &sfeatures->tree, STRCMP));
+
/*
* Check both the primary and alternate sysfs locations to determine
* if the required functionality is supported.
@@ -202,10 +283,10 @@ zfs_mod_supported(const char *scope, const char *name)
* scope directory does not exist.
*/
if (supported == B_FALSE) {
- struct stat64 statbuf;
- if ((stat64(ZFS_SYSFS_DIR, &statbuf) == 0) &&
- !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_DIR) &&
- !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_ALT_DIR)) {
+ if ((access(ZFS_SYSFS_DIR, F_OK) == 0 &&
+ !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_DIR)) ||
+ (access(ZFS_SYSFS_ALT_DIR, F_OK) == 0 &&
+ !zfs_mod_supported_impl(scope, NULL, ZFS_SYSFS_ALT_DIR))) {
supported = B_TRUE;
}
}
@@ -215,7 +296,8 @@ zfs_mod_supported(const char *scope, const char *name)
#endif
static boolean_t
-zfs_mod_supported_feature(const char *name)
+zfs_mod_supported_feature(const char *name,
+ const struct zfs_mod_supported_features *sfeatures)
{
/*
* The zfs module spa_feature_table[], whether in-kernel or in
@@ -229,17 +311,18 @@ zfs_mod_supported_feature(const char *name)
*/
#if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD) || defined(__FreeBSD__)
- (void) name;
+ (void) name, (void) sfeatures;
return (B_TRUE);
#else
- return (zfs_mod_supported(ZFS_SYSFS_POOL_FEATURES, name));
+ return (zfs_mod_supported(ZFS_SYSFS_POOL_FEATURES, name, sfeatures));
#endif
}
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 spa_feature_t *deps,
+ const struct zfs_mod_supported_features *sfeatures)
{
zfeature_info_t *feature = &spa_feature_table[fid];
static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
@@ -264,7 +347,8 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
feature->fi_flags = flags;
feature->fi_type = type;
feature->fi_depends = deps;
- feature->fi_zfs_mod_supported = zfs_mod_supported_feature(guid);
+ feature->fi_zfs_mod_supported =
+ zfs_mod_supported_feature(guid, sfeatures);
}
/*
@@ -283,318 +367,335 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
void
zpool_feature_init(void)
{
+ struct zfs_mod_supported_features *sfeatures =
+ zfs_mod_list_supported(ZFS_SYSFS_POOL_FEATURES);
+
zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
"com.delphix:async_destroy", "async_destroy",
"Destroy filesystems asynchronously.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
"com.delphix:empty_bpobj", "empty_bpobj",
"Snapshots use less space.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
"org.illumos:lz4_compress", "lz4_compress",
"LZ4 compression algorithm support.",
- ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
"com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
"Crash dumps to multiple vdev pools.",
- 0, ZFEATURE_TYPE_BOOLEAN, NULL);
+ 0, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
"com.delphix:spacemap_histogram", "spacemap_histogram",
"Spacemaps maintain space histograms.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_ENABLED_TXG,
"com.delphix:enabled_txg", "enabled_txg",
"Record txg at which a feature is enabled",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
{
- static const spa_feature_t hole_birth_deps[] = {
- SPA_FEATURE_ENABLED_TXG,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_HOLE_BIRTH,
- "com.delphix:hole_birth", "hole_birth",
- "Retain hole birth txg for more precise zfs send",
- ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
- ZFEATURE_TYPE_BOOLEAN, hole_birth_deps);
+ static const spa_feature_t hole_birth_deps[] = {
+ SPA_FEATURE_ENABLED_TXG,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_HOLE_BIRTH,
+ "com.delphix:hole_birth", "hole_birth",
+ "Retain hole birth txg for more precise zfs send",
+ ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+ ZFEATURE_TYPE_BOOLEAN, hole_birth_deps, sfeatures);
}
zfeature_register(SPA_FEATURE_POOL_CHECKPOINT,
"com.delphix:zpool_checkpoint", "zpool_checkpoint",
"Pool state can be checkpointed, allowing rewind later.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_SPACEMAP_V2,
"com.delphix:spacemap_v2", "spacemap_v2",
"Space maps representing large segments are more efficient.",
ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
- ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
"com.delphix:extensible_dataset", "extensible_dataset",
"Enhanced dataset functionality, used by other features.",
- 0, ZFEATURE_TYPE_BOOLEAN, NULL);
+ 0, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
{
- static const spa_feature_t bookmarks_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
-
- zfeature_register(SPA_FEATURE_BOOKMARKS,
- "com.delphix:bookmarks", "bookmarks",
- "\"zfs bookmark\" command",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
- bookmarks_deps);
+ static const spa_feature_t bookmarks_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+
+ zfeature_register(SPA_FEATURE_BOOKMARKS,
+ "com.delphix:bookmarks", "bookmarks",
+ "\"zfs bookmark\" command",
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+ bookmarks_deps, sfeatures);
}
{
- static const spa_feature_t filesystem_limits_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
- "com.joyent:filesystem_limits", "filesystem_limits",
- "Filesystem and snapshot limits.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
- filesystem_limits_deps);
+ static const spa_feature_t filesystem_limits_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
+ "com.joyent:filesystem_limits", "filesystem_limits",
+ "Filesystem and snapshot limits.",
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+ filesystem_limits_deps, sfeatures);
}
zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
"com.delphix:embedded_data", "embedded_data",
"Blocks which compress very well use even less space.",
ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
- ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
{
- static const spa_feature_t livelist_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_LIVELIST,
- "com.delphix:livelist", "livelist",
- "Improved clone deletion performance.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
- livelist_deps);
+ static const spa_feature_t livelist_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_LIVELIST,
+ "com.delphix:livelist", "livelist",
+ "Improved clone deletion performance.",
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+ livelist_deps, sfeatures);
}
{
- static const spa_feature_t log_spacemap_deps[] = {
- SPA_FEATURE_SPACEMAP_V2,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_LOG_SPACEMAP,
- "com.delphix:log_spacemap", "log_spacemap",
- "Log metaslab changes on a single spacemap and "
- "flush them periodically.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
- log_spacemap_deps);
+ static const spa_feature_t log_spacemap_deps[] = {
+ SPA_FEATURE_SPACEMAP_V2,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_LOG_SPACEMAP,
+ "com.delphix:log_spacemap", "log_spacemap",
+ "Log metaslab changes on a single spacemap and "
+ "flush them periodically.",
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+ log_spacemap_deps, sfeatures);
}
{
- static const spa_feature_t large_blocks_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
- "org.open-zfs:large_blocks", "large_blocks",
- "Support for blocks larger than 128KB.",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
- large_blocks_deps);
+ static const spa_feature_t large_blocks_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
+ "org.open-zfs:large_blocks", "large_blocks",
+ "Support for blocks larger than 128KB.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ large_blocks_deps, sfeatures);
}
{
- static const spa_feature_t large_dnode_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_LARGE_DNODE,
- "org.zfsonlinux:large_dnode", "large_dnode",
- "Variable on-disk size of dnodes.",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
- large_dnode_deps);
+ static const spa_feature_t large_dnode_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_LARGE_DNODE,
+ "org.zfsonlinux:large_dnode", "large_dnode",
+ "Variable on-disk size of dnodes.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ large_dnode_deps, sfeatures);
}
{
- static const spa_feature_t sha512_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_SHA512,
- "org.illumos:sha512", "sha512",
- "SHA-512/256 hash algorithm.",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
- sha512_deps);
+ static const spa_feature_t sha512_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_SHA512,
+ "org.illumos:sha512", "sha512",
+ "SHA-512/256 hash algorithm.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ sha512_deps, sfeatures);
}
{
- static const spa_feature_t skein_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_SKEIN,
- "org.illumos:skein", "skein",
- "Skein hash algorithm.",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
- skein_deps);
+ static const spa_feature_t skein_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_SKEIN,
+ "org.illumos:skein", "skein",
+ "Skein hash algorithm.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ skein_deps, sfeatures);
}
{
- static const spa_feature_t edonr_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_EDONR,
- "org.illumos:edonr", "edonr",
- "Edon-R hash algorithm.",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
- edonr_deps);
+ static const spa_feature_t edonr_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_EDONR,
+ "org.illumos:edonr", "edonr",
+ "Edon-R hash algorithm.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ edonr_deps, sfeatures);
}
{
- static const spa_feature_t redact_books_deps[] = {
- SPA_FEATURE_BOOKMARK_V2,
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_BOOKMARKS,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_REDACTION_BOOKMARKS,
- "com.delphix:redaction_bookmarks", "redaction_bookmarks",
- "Support for bookmarks which store redaction lists for zfs "
- "redacted send/recv.", 0, ZFEATURE_TYPE_BOOLEAN,
- redact_books_deps);
+ static const spa_feature_t redact_books_deps[] = {
+ SPA_FEATURE_BOOKMARK_V2,
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_BOOKMARKS,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_REDACTION_BOOKMARKS,
+ "com.delphix:redaction_bookmarks", "redaction_bookmarks",
+ "Support for bookmarks which store redaction lists for zfs "
+ "redacted send/recv.", 0, ZFEATURE_TYPE_BOOLEAN,
+ redact_books_deps, sfeatures);
}
{
- static const spa_feature_t redact_datasets_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_REDACTED_DATASETS,
- "com.delphix:redacted_datasets", "redacted_datasets", "Support for "
- "redacted datasets, produced by receiving a redacted zfs send "
- "stream.", ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_UINT64_ARRAY,
- redact_datasets_deps);
+ static const spa_feature_t redact_datasets_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_REDACTED_DATASETS,
+ "com.delphix:redacted_datasets", "redacted_datasets",
+ "Support for redacted datasets, produced by receiving "
+ "a redacted zfs send stream.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_UINT64_ARRAY,
+ redact_datasets_deps, sfeatures);
}
{
- static const spa_feature_t bookmark_written_deps[] = {
- SPA_FEATURE_BOOKMARK_V2,
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_BOOKMARKS,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_BOOKMARK_WRITTEN,
- "com.delphix:bookmark_written", "bookmark_written",
- "Additional accounting, enabling the written#<bookmark> property"
- "(space written since a bookmark), and estimates of send stream "
- "sizes for incrementals from bookmarks.",
- 0, ZFEATURE_TYPE_BOOLEAN, bookmark_written_deps);
+ static const spa_feature_t bookmark_written_deps[] = {
+ SPA_FEATURE_BOOKMARK_V2,
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_BOOKMARKS,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_BOOKMARK_WRITTEN,
+ "com.delphix:bookmark_written", "bookmark_written",
+ "Additional accounting, enabling the written#<bookmark> "
+ "property (space written since a bookmark), "
+ "and estimates of send stream sizes for incrementals from "
+ "bookmarks.",
+ 0, ZFEATURE_TYPE_BOOLEAN, bookmark_written_deps, sfeatures);
}
zfeature_register(SPA_FEATURE_DEVICE_REMOVAL,
"com.delphix:device_removal", "device_removal",
"Top-level vdevs can be removed, reducing logical pool size.",
- ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
{
- static const spa_feature_t obsolete_counts_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_DEVICE_REMOVAL,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_OBSOLETE_COUNTS,
- "com.delphix:obsolete_counts", "obsolete_counts",
- "Reduce memory used by removed devices when their blocks are "
- "freed or remapped.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
- obsolete_counts_deps);
+ static const spa_feature_t obsolete_counts_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_DEVICE_REMOVAL,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_OBSOLETE_COUNTS,
+ "com.delphix:obsolete_counts", "obsolete_counts",
+ "Reduce memory used by removed devices when their blocks "
+ "are freed or remapped.",
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN,
+ obsolete_counts_deps, sfeatures);
}
{
- static const spa_feature_t userobj_accounting_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
- "org.zfsonlinux:userobj_accounting", "userobj_accounting",
- "User/Group object accounting.",
- ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
- ZFEATURE_TYPE_BOOLEAN, userobj_accounting_deps);
+ static const spa_feature_t userobj_accounting_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
+ "org.zfsonlinux:userobj_accounting", "userobj_accounting",
+ "User/Group object accounting.",
+ ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
+ ZFEATURE_TYPE_BOOLEAN, userobj_accounting_deps, sfeatures);
}
{
- static const spa_feature_t bookmark_v2_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_BOOKMARKS,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_BOOKMARK_V2,
- "com.datto:bookmark_v2", "bookmark_v2",
- "Support for larger bookmarks",
- 0, ZFEATURE_TYPE_BOOLEAN, bookmark_v2_deps);
+ static const spa_feature_t bookmark_v2_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_BOOKMARKS,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_BOOKMARK_V2,
+ "com.datto:bookmark_v2", "bookmark_v2",
+ "Support for larger bookmarks",
+ 0, ZFEATURE_TYPE_BOOLEAN, bookmark_v2_deps, sfeatures);
}
{
- static const spa_feature_t encryption_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_BOOKMARK_V2,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_ENCRYPTION,
- "com.datto:encryption", "encryption",
- "Support for dataset level encryption",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
- encryption_deps);
+ static const spa_feature_t encryption_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_BOOKMARK_V2,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_ENCRYPTION,
+ "com.datto:encryption", "encryption",
+ "Support for dataset level encryption",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ encryption_deps, sfeatures);
}
{
- static const spa_feature_t project_quota_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_PROJECT_QUOTA,
- "org.zfsonlinux:project_quota", "project_quota",
- "space/object accounting based on project ID.",
- ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
- ZFEATURE_TYPE_BOOLEAN, project_quota_deps);
+ static const spa_feature_t project_quota_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_PROJECT_QUOTA,
+ "org.zfsonlinux:project_quota", "project_quota",
+ "space/object accounting based on project ID.",
+ ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
+ ZFEATURE_TYPE_BOOLEAN, project_quota_deps, sfeatures);
}
zfeature_register(SPA_FEATURE_ALLOCATION_CLASSES,
"org.zfsonlinux:allocation_classes", "allocation_classes",
"Support for separate allocation classes.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_RESILVER_DEFER,
"com.datto:resilver_defer", "resilver_defer",
"Support for deferring new resilvers when one is already running.",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
zfeature_register(SPA_FEATURE_DEVICE_REBUILD,
"org.openzfs:device_rebuild", "device_rebuild",
"Support for sequential mirror/dRAID device rebuilds",
- ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
+ sfeatures);
{
- static const spa_feature_t zstd_deps[] = {
- SPA_FEATURE_EXTENSIBLE_DATASET,
- SPA_FEATURE_NONE
- };
- zfeature_register(SPA_FEATURE_ZSTD_COMPRESS,
- "org.freebsd:zstd_compress", "zstd_compress",
- "zstd compression algorithm support.",
- ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, zstd_deps);
+ static const spa_feature_t zstd_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_ZSTD_COMPRESS,
+ "org.freebsd:zstd_compress", "zstd_compress",
+ "zstd compression algorithm support.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, zstd_deps,
+ sfeatures);
}
zfeature_register(SPA_FEATURE_DRAID,
"org.openzfs:draid", "draid", "Support for distributed spare RAID",
- ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL);
+ ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
+
+ zfs_mod_list_supported_free(sfeatures);
}
#if defined(_KERNEL)