aboutsummaryrefslogtreecommitdiffstats
path: root/module/zcommon/zfeature_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zcommon/zfeature_common.c')
-rw-r--r--module/zcommon/zfeature_common.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c
index f5c98933c..e2b0fd511 100644
--- a/module/zcommon/zfeature_common.c
+++ b/module/zcommon/zfeature_common.c
@@ -29,11 +29,13 @@
#ifndef _KERNEL
#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
#endif
#include <sys/debug.h>
#include <sys/fs/zfs.h>
#include <sys/inttypes.h>
#include <sys/types.h>
+#include <sys/zfs_sysfs.h>
#include "zfeature_common.h"
/*
@@ -101,10 +103,29 @@ zfeature_is_supported(const char *guid)
}
int
+zfeature_lookup_guid(const char *guid, spa_feature_t *res)
+{
+ for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
+ zfeature_info_t *feature = &spa_feature_table[i];
+ if (!feature->fi_zfs_mod_supported)
+ continue;
+ if (strcmp(guid, feature->fi_guid) == 0) {
+ if (res != NULL)
+ *res = i;
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+int
zfeature_lookup_name(const char *name, spa_feature_t *res)
{
for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
zfeature_info_t *feature = &spa_feature_table[i];
+ if (!feature->fi_zfs_mod_supported)
+ continue;
if (strcmp(name, feature->fi_uname) == 0) {
if (res != NULL)
*res = i;
@@ -137,6 +158,34 @@ deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
return (B_FALSE);
}
+static boolean_t
+zfs_mod_supported_feature(const char *name)
+{
+ /*
+ * The zfs module spa_feature_table[], whether in-kernel or in
+ * libzpool, always supports all the features. libzfs needs to
+ * query the running module, via sysfs, to determine which
+ * features are supported.
+ */
+#if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD)
+ return (B_TRUE);
+#else
+ struct stat64 statbuf;
+ char *path;
+ boolean_t supported = B_FALSE;
+ int len;
+
+ len = asprintf(&path, "%s/%s/%s", ZFS_SYSFS_DIR,
+ ZFS_SYSFS_POOL_FEATURES, name);
+
+ if (len > 0) {
+ supported = !!(stat64(path, &statbuf) == 0);
+ free(path);
+ }
+ return (supported);
+#endif
+}
+
static void
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
@@ -163,6 +212,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
feature->fi_desc = desc;
feature->fi_flags = flags;
feature->fi_depends = deps;
+ feature->fi_zfs_mod_supported = zfs_mod_supported_feature(guid);
}
void
@@ -361,6 +411,7 @@ zpool_feature_init(void)
}
#if defined(_KERNEL)
+EXPORT_SYMBOL(zfeature_lookup_guid);
EXPORT_SYMBOL(zfeature_lookup_name);
EXPORT_SYMBOL(zfeature_is_supported);
EXPORT_SYMBOL(zfeature_is_valid_guid);