diff --git a/configure.ac b/configure.ac index dbc063fd0..3e6dcf1c3 100644 --- a/configure.ac +++ b/configure.ac @@ -227,6 +227,7 @@ AC_CONFIG_FILES([ tests/zfs-tests/tests/functional/cli_root/zfs_set/Makefile tests/zfs-tests/tests/functional/cli_root/zfs_share/Makefile tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/Makefile + tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/Makefile tests/zfs-tests/tests/functional/cli_root/zfs_unload-key/Makefile tests/zfs-tests/tests/functional/cli_root/zfs_unmount/Makefile tests/zfs-tests/tests/functional/cli_root/zfs_unshare/Makefile diff --git a/include/sys/Makefile.am b/include/sys/Makefile.am index f246c111d..644ddaab3 100644 --- a/include/sys/Makefile.am +++ b/include/sys/Makefile.am @@ -119,6 +119,7 @@ COMMON_H = \ $(top_srcdir)/include/sys/zfs_rlock.h \ $(top_srcdir)/include/sys/zfs_sa.h \ $(top_srcdir)/include/sys/zfs_stat.h \ + $(top_srcdir)/include/sys/zfs_sysfs.h \ $(top_srcdir)/include/sys/zfs_vfsops.h \ $(top_srcdir)/include/sys/zfs_vnops.h \ $(top_srcdir)/include/sys/zfs_znode.h \ diff --git a/include/sys/zfs_sysfs.h b/include/sys/zfs_sysfs.h new file mode 100644 index 000000000..7c4a0304f --- /dev/null +++ b/include/sys/zfs_sysfs.h @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2018 by Delphix. All rights reserved. + */ + +#ifndef _SYS_ZFS_SYSFS_H +#define _SYS_ZFS_SYSFS_H + +#ifdef _KERNEL + +void zfs_sysfs_init(void); +void zfs_sysfs_fini(void); + +#else + +#define zfs_sysfs_init() +#define zfs_sysfs_fini() + +#endif + +#define ZFS_SYSFS_POOL_PROPERTIES "properties.pool" +#define ZFS_SYSFS_DATASET_PROPERTIES "properties.dataset" +#define ZFS_SYSFS_KERNEL_FEATURES "features.kernel" +#define ZFS_SYSFS_POOL_FEATURES "features.pool" + +#define ZFS_SYSFS_DIR "/sys/module/zfs" + +#endif /* _SYS_ZFS_SYSFS_H */ diff --git a/include/zfeature_common.h b/include/zfeature_common.h index c5aabce0e..8d31309e8 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -85,6 +85,7 @@ typedef struct zfeature_info { const char *fi_guid; /* On-disk feature identifier */ const char *fi_desc; /* Feature description */ zfeature_flags_t fi_flags; + boolean_t fi_zfs_mod_supported; /* supported by running zfs module */ /* array of dependencies, terminated by SPA_FEATURE_NONE */ const spa_feature_t *fi_depends; } zfeature_info_t; @@ -98,6 +99,7 @@ extern zfeature_info_t spa_feature_table[SPA_FEATURES]; extern boolean_t zfeature_is_valid_guid(const char *); extern boolean_t zfeature_is_supported(const char *); +extern int zfeature_lookup_guid(const char *, spa_feature_t *); extern int zfeature_lookup_name(const char *, spa_feature_t *); extern boolean_t zfeature_depends_on(spa_feature_t, spa_feature_t); diff --git a/include/zfs_prop.h b/include/zfs_prop.h index 60e08552a..89b6a2024 100644 --- a/include/zfs_prop.h +++ b/include/zfs_prop.h @@ -78,6 +78,7 @@ typedef struct { boolean_t pd_rightalign; /* column alignment for "zfs list" */ boolean_t pd_visible; /* do we list this property with the */ /* "zfs get" help message */ + boolean_t pd_zfs_mod_supported; /* supported by running zfs module */ const zprop_index_t *pd_table; /* for index properties, a table */ /* defining the possible values */ size_t pd_table_size; /* number of entries in pd_table[] */ diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index a19b34415..d18b582c6 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -1091,6 +1091,22 @@ libzfs_init(void) hdl->libzfs_prop_debug = B_TRUE; } + /* + * For testing, remove some settable properties and features + */ + if (libzfs_envvar_is_set("ZFS_SYSFS_PROP_SUPPORT_TEST")) { + zprop_desc_t *proptbl; + + proptbl = zpool_prop_get_table(); + proptbl[ZPOOL_PROP_COMMENT].pd_zfs_mod_supported = B_FALSE; + + proptbl = zfs_prop_get_table(); + proptbl[ZFS_PROP_DNODESIZE].pd_zfs_mod_supported = B_FALSE; + + zfeature_info_t *ftbl = spa_feature_table; + ftbl[SPA_FEATURE_LARGE_BLOCKS].fi_zfs_mod_supported = B_FALSE; + } + return (hdl); } diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 58e3b6eec..149706a27 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -12,6 +12,8 @@ AM_CFLAGS += $(NO_UNUSED_BUT_SET_VARIABLE) # Includes kernel code generate warnings for large stack frames AM_CFLAGS += $(FRAME_LARGER_THAN) +AM_CFLAGS += -DLIB_ZPOOL_BUILD + DEFAULT_INCLUDES += \ -I$(top_srcdir)/include \ -I$(top_srcdir)/lib/libspl/include 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 #include +#include #endif #include #include #include #include +#include #include "zfeature_common.h" /* @@ -100,11 +102,30 @@ zfeature_is_supported(const char *guid) return (B_FALSE); } +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); diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 28eb1255b..04bb33e5e 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -720,7 +720,8 @@ zfs_prop_readonly(zfs_prop_t prop) boolean_t zfs_prop_visible(zfs_prop_t prop) { - return (zfs_prop_table[prop].pd_visible); + return (zfs_prop_table[prop].pd_visible && + zfs_prop_table[prop].pd_zfs_mod_supported); } /* diff --git a/module/zcommon/zprop_common.c b/module/zcommon/zprop_common.c index 838988a4c..0ce2ee762 100644 --- a/module/zcommon/zprop_common.c +++ b/module/zcommon/zprop_common.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #endif static zprop_desc_t * @@ -68,6 +70,34 @@ zprop_get_numprops(zfs_type_t type) return (ZFS_NUM_PROPS); } +static boolean_t +zfs_mod_supported_prop(const char *name, zfs_type_t type) +{ +/* + * The zfs module spa_feature_table[], whether in-kernel or in libzpool, + * always supports all the properties. libzfs needs to query the running + * module, via sysfs, to determine which properties 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, + (type == ZFS_TYPE_POOL) ? ZFS_SYSFS_POOL_PROPERTIES : + ZFS_SYSFS_DATASET_PROPERTIES, name); + + if (len > 0) { + supported = !!(stat64(path, &statbuf) == 0); + free(path); + } + return (supported); +#endif +} + void zprop_register_impl(int prop, const char *name, zprop_type_t type, uint64_t numdefault, const char *strdefault, zprop_attr_t attr, @@ -94,6 +124,7 @@ zprop_register_impl(int prop, const char *name, zprop_type_t type, pd->pd_colname = colname; pd->pd_rightalign = rightalign; pd->pd_visible = visible; + pd->pd_zfs_mod_supported = zfs_mod_supported_prop(name, objset_types); pd->pd_table = idx_tbl; pd->pd_table_size = 0; while (idx_tbl && (idx_tbl++)->pi_name != NULL) @@ -193,6 +224,7 @@ zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, prop = ZPROP_CONT; for (i = 0; i < num_props; i++) { if ((order[i]->pd_visible || show_all) && + order[i]->pd_zfs_mod_supported && (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { prop = order[i]->pd_propnum; break; diff --git a/module/zfs/Makefile.in b/module/zfs/Makefile.in index 2c27cf65c..6fd24757c 100644 --- a/module/zfs/Makefile.in +++ b/module/zfs/Makefile.in @@ -120,6 +120,7 @@ $(MODULE)-objs += zfs_ratelimit.o $(MODULE)-objs += zfs_replay.o $(MODULE)-objs += zfs_rlock.o $(MODULE)-objs += zfs_sa.o +$(MODULE)-objs += zfs_sysfs.o $(MODULE)-objs += zfs_vfsops.o $(MODULE)-objs += zfs_vnops.o $(MODULE)-objs += zfs_znode.o diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 6a5846bfe..4ea9fa41a 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -187,6 +187,7 @@ #include #include #include +#include #include #include @@ -7083,6 +7084,7 @@ _init(void) zfs_init(); zfs_ioctl_init(); + zfs_sysfs_init(); if ((error = zfs_attach()) != 0) goto out; @@ -7102,6 +7104,7 @@ _init(void) return (0); out: + zfs_sysfs_fini(); zfs_fini(); spa_fini(); (void) zvol_fini(); @@ -7116,6 +7119,7 @@ static void __exit _fini(void) { zfs_detach(); + zfs_sysfs_fini(); zfs_fini(); spa_fini(); zvol_fini(); diff --git a/module/zfs/zfs_sysfs.c b/module/zfs/zfs_sysfs.c new file mode 100644 index 000000000..6bf2e23aa --- /dev/null +++ b/module/zfs/zfs_sysfs.c @@ -0,0 +1,617 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2018 by Delphix. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zfs_prop.h" + +#if !defined(_KERNEL) +#error kernel builds only +#endif + +/* + * ZFS Module sysfs support + * + * This extends our sysfs '/sys/module/zfs' entry to include feature + * and property attributes. The primary consumer of this information + * is user processes, like the zfs CLI, that need to know what the + * current loaded ZFS module supports. The libzfs binary will consult + * this information when instantiating the zfs|zpool property tables + * and the pool features table. + * + * The added top-level directories are: + * /sys/module/zfs + * ├── features.kernel + * ├── features.pool + * ├── properties.dataset + * └── properties.pool + * + * The local interface for the zfs kobjects includes: + * zfs_kobj_init() + * zfs_kobj_add() + * zfs_kobj_release() + * zfs_kobj_add_attr() + * zfs_kobj_fini() + */ + +/* + * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs' + */ +struct zfs_mod_kobj; +typedef struct zfs_mod_kobj zfs_mod_kobj_t; + +struct zfs_mod_kobj { + struct kobject zko_kobj; + struct kobj_type zko_kobj_type; + struct sysfs_ops zko_sysfs_ops; + size_t zko_attr_count; + struct attribute *zko_attr_list; /* allocated */ + struct attribute **zko_default_attrs; /* allocated */ + size_t zko_child_count; + zfs_mod_kobj_t *zko_children; /* allocated */ +}; + +#define ATTR_TABLE_SIZE(cnt) (sizeof (struct attribute) * (cnt)) +/* Note +1 for NULL terminator slot */ +#define DEFAULT_ATTR_SIZE(cnt) (sizeof (struct attribute *) * (cnt + 1)) +#define CHILD_TABLE_SIZE(cnt) (sizeof (zfs_mod_kobj_t) * (cnt)) + +/* + * These are the top-level kobjects under '/sys/module/zfs/' + */ +static zfs_mod_kobj_t kernel_features_kobj; +static zfs_mod_kobj_t pool_features_kobj; +static zfs_mod_kobj_t dataset_props_kobj; +static zfs_mod_kobj_t pool_props_kobj; + +/* + * The show function is used to provide the content + * of an attribute into a PAGE_SIZE buffer. + */ +typedef ssize_t (*sysfs_show_func)(struct kobject *, struct attribute *, + char *); + +static void +zfs_kobj_fini(zfs_mod_kobj_t *zkobj) +{ + /* finialize any child kobjects */ + if (zkobj->zko_child_count != 0) { + ASSERT(zkobj->zko_children); + for (int i = 0; i < zkobj->zko_child_count; i++) + zfs_kobj_fini(&zkobj->zko_children[i]); + } + + /* kobject_put() will call zfs_kobj_release() to release memory */ + kobject_del(&zkobj->zko_kobj); + kobject_put(&zkobj->zko_kobj); +} + +static void +zfs_kobj_release(struct kobject *kobj) +{ + zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj); + + if (zkobj->zko_attr_count != 0) { + ASSERT(zkobj->zko_attr_list); + ASSERT(zkobj->zko_default_attrs); + + kmem_free(zkobj->zko_attr_list, + ATTR_TABLE_SIZE(zkobj->zko_attr_count)); + kmem_free(zkobj->zko_default_attrs, + DEFAULT_ATTR_SIZE(zkobj->zko_attr_count)); + zkobj->zko_attr_count = 0; + zkobj->zko_attr_list = NULL; + zkobj->zko_default_attrs = NULL; + } + if (zkobj->zko_child_count != 0) { + ASSERT(zkobj->zko_children); + + kmem_free(zkobj->zko_children, + CHILD_TABLE_SIZE(zkobj->zko_child_count)); + zkobj->zko_child_count = 0; + zkobj->zko_children = NULL; + } +} + +static void +zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name) +{ + VERIFY3U(attr_num, <, zkobj->zko_attr_count); + ASSERT(zkobj->zko_attr_list); + ASSERT(zkobj->zko_default_attrs); + + zkobj->zko_attr_list[attr_num].name = attr_name; + zkobj->zko_attr_list[attr_num].mode = 0444; + zkobj->zko_default_attrs[attr_num] = &zkobj->zko_attr_list[attr_num]; +} + +static int +zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt, + sysfs_show_func show_func) +{ + /* + * Initialize object's attributes. Count can be zero. + */ + if (attr_cnt > 0) { + zkobj->zko_attr_list = kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt), + KM_SLEEP); + if (zkobj->zko_attr_list == NULL) + return (ENOMEM); + } + /* this will always have at least one slot for NULL termination */ + zkobj->zko_default_attrs = kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), + KM_SLEEP); + if (zkobj->zko_default_attrs == NULL) { + if (zkobj->zko_attr_list) { + kmem_free(zkobj->zko_attr_list, + ATTR_TABLE_SIZE(attr_cnt)); + } + return (ENOMEM); + } + zkobj->zko_attr_count = attr_cnt; + zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_attrs; + + if (child_cnt > 0) { + zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt), + KM_SLEEP); + if (zkobj->zko_children == NULL) { + if (attr_cnt > 0) { + kmem_free(zkobj->zko_attr_list, + DEFAULT_ATTR_SIZE(attr_cnt)); + kmem_free(zkobj->zko_attr_list, + ATTR_TABLE_SIZE(attr_cnt)); + } + return (ENOMEM); + } + zkobj->zko_child_count = child_cnt; + } + + zkobj->zko_sysfs_ops.show = show_func; + zkobj->zko_kobj_type.sysfs_ops = &zkobj->zko_sysfs_ops; + zkobj->zko_kobj_type.release = zfs_kobj_release; + + return (0); +} + +static int +zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name) +{ + /* zko_default_attrs must be NULL terminated */ + ASSERT(zkobj->zko_default_attrs != NULL); + ASSERT(zkobj->zko_default_attrs[zkobj->zko_attr_count] == NULL); + + kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type); + return (kobject_add(&zkobj->zko_kobj, parent, name)); +} + +/* + * Each zfs property has these common attributes + */ +static const char *zprop_attrs[] = { + "type", + "readonly", + "setonce", + "visible", + "values", + "default", + "datasets" /* zfs properties only */ +}; + +#define ZFS_PROP_ATTR_COUNT ARRAY_SIZE(zprop_attrs) +#define ZPOOL_PROP_ATTR_COUNT (ZFS_PROP_ATTR_COUNT - 1) + +static const char *zprop_types[] = { + "number", + "string", + "index", +}; + +typedef struct zfs_type_map { + zfs_type_t ztm_type; + const char *ztm_name; +} zfs_type_map_t; + +static zfs_type_map_t type_map[] = { + {ZFS_TYPE_FILESYSTEM, "filesystem"}, + {ZFS_TYPE_SNAPSHOT, "snapshot"}, + {ZFS_TYPE_VOLUME, "volume"}, + {ZFS_TYPE_BOOKMARK, "bookmark"} +}; + +/* + * Show the content for a zfs property attribute + */ +static ssize_t +zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property, + char *buf, size_t buflen) +{ + const char *show_str; + + /* For dataset properties list the dataset types that apply */ + if (strcmp(attr_name, "datasets") == 0 && + property->pd_types != ZFS_TYPE_POOL) { + int len = 0; + + for (int i = 0; i < ARRAY_SIZE(type_map); i++) { + if (type_map[i].ztm_type & property->pd_types) { + len += snprintf(buf + len, buflen - len, "%s ", + type_map[i].ztm_name); + } + } + len += snprintf(buf + len, buflen - len, "\n"); + return (len); + } + + if (strcmp(attr_name, "type") == 0) { + show_str = zprop_types[property->pd_proptype]; + } else if (strcmp(attr_name, "readonly") == 0) { + show_str = property->pd_attr == PROP_READONLY ? "1" : "0"; + } else if (strcmp(attr_name, "setonce") == 0) { + show_str = property->pd_attr == PROP_ONETIME ? "1" : "0"; + } else if (strcmp(attr_name, "visible") == 0) { + show_str = property->pd_visible ? "1" : "0"; + } else if (strcmp(attr_name, "values") == 0) { + show_str = property->pd_values ? property->pd_values : ""; + } else if (strcmp(attr_name, "default") == 0) { + char number[32]; + + switch (property->pd_proptype) { + case PROP_TYPE_NUMBER: + (void) snprintf(number, sizeof (number), "%llu", + (u_longlong_t)property->pd_numdefault); + show_str = number; + break; + case PROP_TYPE_STRING: + show_str = property->pd_strdefault ? + property->pd_strdefault : ""; + break; + case PROP_TYPE_INDEX: + (void) zprop_index_to_string(property->pd_propnum, + property->pd_numdefault, &show_str, + property->pd_types); + break; + default: + return (0); + } + } else { + return (0); + } + + return (snprintf(buf, buflen, "%s\n", show_str)); +} + +static ssize_t +dataset_property_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + zfs_prop_t prop = zfs_name_to_prop(kobject_name(kobj)); + zprop_desc_t *prop_tbl = zfs_prop_get_table(); + ssize_t len; + + ASSERT3U(prop, <, ZFS_NUM_PROPS); + + len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE); + + return (len); +} + +static ssize_t +pool_property_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + zpool_prop_t prop = zpool_name_to_prop(kobject_name(kobj)); + zprop_desc_t *prop_tbl = zpool_prop_get_table(); + ssize_t len; + + ASSERT3U(prop, <, ZPOOL_NUM_PROPS); + + len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE); + + return (len); +} + +/* + * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel' + * + * This list is intended for kernel features that don't have a pool feature + * association or that extend existing user kernel interfaces. + * + * A user processes can easily check if the running zfs kernel module + * supports the new feature. + * + * For example, the initial channel_program feature was extended to support + * async calls (i.e. a sync flag). If this mechanism were in place at that + * time, we could have added a 'channel_program_async' to this list. + */ +static const char *zfs_features[] = { + /* --> Add new kernel features here (post ZoL 0.8.0) */ +}; + +#define ZFS_FEATURE_COUNT ARRAY_SIZE(zfs_features) + +static ssize_t +kernel_feature_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return (snprintf(buf, PAGE_SIZE, "supported\n")); +} + +static int +zfs_kernel_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent) +{ + int err; + + err = zfs_kobj_init(zfs_kobj, ZFS_FEATURE_COUNT, 0, + kernel_feature_show); + if (err) + return (err); + + for (int f = 0; f < ZFS_FEATURE_COUNT; f++) + zfs_kobj_add_attr(zfs_kobj, f, zfs_features[f]); + + err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_KERNEL_FEATURES); + if (err) + zfs_kobj_release(&zfs_kobj->zko_kobj); + + return (err); +} + +/* + * Each pool feature has these common attributes + */ +static const char *pool_feature_attrs[] = { + "description", + "guid", + "uname", + "readonly_compatible", + "required_for_mos", + "activate_on_enable", + "per_dataset" +}; + +#define ZPOOL_FEATURE_ATTR_COUNT ARRAY_SIZE(pool_feature_attrs) + +/* + * Show the content for the given zfs pool feature attribute + */ +static ssize_t +pool_feature_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + spa_feature_t fid; + + if (zfeature_lookup_guid(kobject_name(kobj), &fid) != 0) + return (0); + + ASSERT3U(fid, <, SPA_FEATURES); + + zfeature_flags_t flags = spa_feature_table[fid].fi_flags; + const char *show_str = NULL; + + if (strcmp(attr->name, "description") == 0) { + show_str = spa_feature_table[fid].fi_desc; + } else if (strcmp(attr->name, "guid") == 0) { + show_str = spa_feature_table[fid].fi_guid; + } else if (strcmp(attr->name, "uname") == 0) { + show_str = spa_feature_table[fid].fi_uname; + } else if (strcmp(attr->name, "readonly_compatible") == 0) { + show_str = flags & ZFEATURE_FLAG_READONLY_COMPAT ? "1" : "0"; + } else if (strcmp(attr->name, "required_for_mos") == 0) { + show_str = flags & ZFEATURE_FLAG_MOS ? "1" : "0"; + } else if (strcmp(attr->name, "activate_on_enable") == 0) { + show_str = flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE ? "1" : "0"; + } else if (strcmp(attr->name, "per_dataset") == 0) { + show_str = flags & ZFEATURE_FLAG_PER_DATASET ? "1" : "0"; + } + if (show_str == NULL) + return (0); + + return (snprintf(buf, PAGE_SIZE, "%s\n", show_str)); +} + +static void +pool_feature_to_kobj(zfs_mod_kobj_t *parent, spa_feature_t fid, + const char *name) +{ + zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[fid]; + + ASSERT3U(fid, <, SPA_FEATURES); + ASSERT(name); + + int err = zfs_kobj_init(zfs_kobj, ZPOOL_FEATURE_ATTR_COUNT, 0, + pool_feature_show); + if (err) + return; + + for (int i = 0; i < ZPOOL_FEATURE_ATTR_COUNT; i++) + zfs_kobj_add_attr(zfs_kobj, i, pool_feature_attrs[i]); + + err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name); + if (err) + zfs_kobj_release(&zfs_kobj->zko_kobj); +} + +static int +zfs_pool_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent) +{ + /* + * Create a parent kobject to host pool features. + * + * '/sys/module/zfs/features.pool' + */ + int err = zfs_kobj_init(zfs_kobj, 0, SPA_FEATURES, pool_feature_show); + if (err) + return (err); + err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_POOL_FEATURES); + if (err) { + zfs_kobj_release(&zfs_kobj->zko_kobj); + return (err); + } + + /* + * Now create a kobject for each feature. + * + * '/sys/module/zfs/features.pool/' + */ + for (spa_feature_t i = 0; i < SPA_FEATURES; i++) + pool_feature_to_kobj(zfs_kobj, i, spa_feature_table[i].fi_guid); + + return (0); +} + +typedef struct prop_to_kobj_arg { + zprop_desc_t *p2k_table; + zfs_mod_kobj_t *p2k_parent; + sysfs_show_func p2k_show_func; + int p2k_attr_count; +} prop_to_kobj_arg_t; + +static int +zprop_to_kobj(int prop, void *args) +{ + prop_to_kobj_arg_t *data = args; + zfs_mod_kobj_t *parent = data->p2k_parent; + zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[prop]; + const char *name = data->p2k_table[prop].pd_name; + int err; + + ASSERT(name); + + err = zfs_kobj_init(zfs_kobj, data->p2k_attr_count, 0, + data->p2k_show_func); + if (err) + return (ZPROP_CONT); + + for (int i = 0; i < data->p2k_attr_count; i++) + zfs_kobj_add_attr(zfs_kobj, i, zprop_attrs[i]); + + err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name); + if (err) + zfs_kobj_release(&zfs_kobj->zko_kobj); + + return (ZPROP_CONT); +} + +static int +zfs_sysfs_properties_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent, + zfs_type_t type) +{ + prop_to_kobj_arg_t context; + const char *name; + int err; + + /* + * Create a parent kobject to host properties. + * + * '/sys/module/zfs/properties.' + */ + if (type == ZFS_TYPE_POOL) { + name = ZFS_SYSFS_POOL_PROPERTIES; + context.p2k_table = zpool_prop_get_table(); + context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT; + context.p2k_parent = zfs_kobj; + context.p2k_show_func = pool_property_show; + err = zfs_kobj_init(zfs_kobj, 0, ZPOOL_NUM_PROPS, + pool_property_show); + } else { + name = ZFS_SYSFS_DATASET_PROPERTIES; + context.p2k_table = zfs_prop_get_table(); + context.p2k_attr_count = ZFS_PROP_ATTR_COUNT; + context.p2k_parent = zfs_kobj; + context.p2k_show_func = dataset_property_show; + err = zfs_kobj_init(zfs_kobj, 0, ZFS_NUM_PROPS, + dataset_property_show); + } + + if (err) + return (err); + + err = zfs_kobj_add(zfs_kobj, parent, name); + if (err) { + zfs_kobj_release(&zfs_kobj->zko_kobj); + return (err); + } + + /* + * Create a kobject for each property. + * + * '/sys/module/zfs/properties./' + */ + (void) zprop_iter_common(zprop_to_kobj, &context, B_TRUE, + B_FALSE, type); + + return (err); +} + +void +zfs_sysfs_init(void) +{ + struct kobject *parent = + &(((struct module *)(THIS_MODULE))->mkobj).kobj; + int err; + + ASSERT(parent != NULL); + + err = zfs_kernel_features_init(&kernel_features_kobj, parent); + if (err) + return; + + err = zfs_pool_features_init(&pool_features_kobj, parent); + if (err) { + zfs_kobj_fini(&kernel_features_kobj); + return; + } + + err = zfs_sysfs_properties_init(&pool_props_kobj, parent, + ZFS_TYPE_POOL); + if (err) { + zfs_kobj_fini(&kernel_features_kobj); + zfs_kobj_fini(&pool_features_kobj); + return; + } + + err = zfs_sysfs_properties_init(&dataset_props_kobj, parent, + ZFS_TYPE_FILESYSTEM); + if (err) { + zfs_kobj_fini(&kernel_features_kobj); + zfs_kobj_fini(&pool_features_kobj); + zfs_kobj_fini(&pool_props_kobj); + return; + } +} + +void +zfs_sysfs_fini(void) +{ + /* + * Remove top-level kobjects; each will remove any children kobjects + */ + zfs_kobj_fini(&kernel_features_kobj); + zfs_kobj_fini(&pool_features_kobj); + zfs_kobj_fini(&dataset_props_kobj); + zfs_kobj_fini(&pool_props_kobj); +} diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 0a64e8cd5..cde8105f9 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -255,6 +255,12 @@ tests = ['zfs_snapshot_001_neg', 'zfs_snapshot_002_neg', 'zfs_snapshot_009_pos'] tags = ['functional', 'cli_root', 'zfs_snapshot'] +[tests/functional/cli_root/zfs_sysfs] +tests = ['zfeature_set_unsupported.ksh', 'zfs_get_unsupported', + 'zfs_set_unsupported', 'zfs_sysfs_live.ksh', 'zpool_get_unsupported', + 'zpool_set_unsupported'] +tags = ['functional', 'cli_root', 'zfs_sysfs'] + [tests/functional/cli_root/zfs_unload-key] tests = ['zfs_unload-key', 'zfs_unload-key_all', 'zfs_unload-key_recursive'] tags = ['functional', 'cli_root', 'zfs_unload-key'] diff --git a/tests/zfs-tests/tests/functional/cli_root/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/Makefile.am index aab49b168..7a765a160 100644 --- a/tests/zfs-tests/tests/functional/cli_root/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/Makefile.am @@ -28,6 +28,7 @@ SUBDIRS = \ zfs_set \ zfs_share \ zfs_snapshot \ + zfs_sysfs \ zfs_unload-key \ zfs_unmount \ zfs_unshare \ diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/Makefile.am new file mode 100644 index 000000000..6a83edf2a --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/Makefile.am @@ -0,0 +1,10 @@ +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_sysfs +dist_pkgdata_SCRIPTS = \ + setup.ksh \ + cleanup.ksh \ + zfeature_set_unsupported.ksh \ + zfs_get_unsupported.ksh \ + zfs_set_unsupported.ksh \ + zfs_sysfs_live.ksh \ + zpool_get_unsupported.ksh \ + zpool_set_unsupported.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/cleanup.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/cleanup.ksh new file mode 100755 index 000000000..79cd6e9f9 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/cleanup.ksh @@ -0,0 +1,30 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib + +default_cleanup diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/setup.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/setup.ksh new file mode 100755 index 000000000..969238599 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/setup.ksh @@ -0,0 +1,32 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib + +DISK=${DISKS%% *} + +default_container_volume_setup $DISK diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfeature_set_unsupported.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfeature_set_unsupported.ksh new file mode 100755 index 000000000..c9d242243 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfeature_set_unsupported.ksh @@ -0,0 +1,54 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# A feature not supported by the zfs module should fail in 'zpool set ' +# +# STRATEGY: +# 1. Run zpool set with env var 'ZFS_SYSFS_PROP_SUPPORT_TEST' +# 2. Verify that zpool set returns error +# + +verify_runnable "global" + +if ! is_linux ; then + log_unsupported "sysfs is linux-only" +fi + +claim="Features not supported by zfs module should fail in 'zpool set '" + +unsupported_feature="feature@large_blocks" +value="enabled" + +log_assert $claim + +log_mustnot eval "ZFS_SYSFS_PROP_SUPPORT_TEST=yes zpool set \ + ${unsupported_feature}=${value} $TESTPOOL/$TESTFS >/dev/null 2>&1" + +log_pass $claim diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_get_unsupported.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_get_unsupported.ksh new file mode 100755 index 000000000..59ed7e950 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_get_unsupported.ksh @@ -0,0 +1,53 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# A property not supported by the zfs module should fail in 'zfs get ' +# +# STRATEGY: +# 1. Run zfs get with the env variable 'ZFS_SYSFS_PROP_SUPPORT_TEST' +# 2. Verify that zfs get returns error +# + +verify_runnable "global" + +if ! is_linux ; then + log_unsupported "sysfs is linux-only" +fi + +claim="Properties not supported by zfs module should fail in 'zfs get '" + +unsupported_prop="dnodesize" + +log_assert $claim + +log_mustnot eval "ZFS_SYSFS_PROP_SUPPORT_TEST=yes zfs get ${unsupported_prop} \ + $TESTPOOL/$TESTFS >/dev/null 2>&1" + +log_pass $claim diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_set_unsupported.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_set_unsupported.ksh new file mode 100755 index 000000000..5a0b88a0b --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_set_unsupported.ksh @@ -0,0 +1,54 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# A property not supported by the zfs module should fail in 'zfs set ' +# +# STRATEGY: +# 1. Run zfs set with the env variable 'ZFS_SYSFS_PROP_SUPPORT_TEST' +# 2. Verify that zfs get returns error +# + +verify_runnable "global" + +if ! is_linux ; then + log_unsupported "sysfs is linux-only" +fi + +claim="Properties not supported by zfs module should fail in 'zfs set '" + +unsupported_prop="dnodesize" +value="any" + +log_assert $claim + +log_mustnot eval "ZFS_SYSFS_PROP_SUPPORT_TEST=yes zfs set \ + ${unsupported_prop}=${value} $TESTPOOL/$TESTFS >/dev/null 2>&1" + +log_pass $claim diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_sysfs_live.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_sysfs_live.ksh new file mode 100755 index 000000000..17ac8f8a1 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zfs_sysfs_live.ksh @@ -0,0 +1,57 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Test if the expected '/sys/module/zfs//' are present +# + +verify_runnable "global" + +if ! is_linux ; then + log_unsupported "sysfs is linux-only" +fi + +claim="Expected '/sys/module/zfs//' attributes are present" + +feature_attr="/sys/module/zfs/features.pool/org.open-zfs:large_blocks/guid" +pool_prop__attr="/sys/module/zfs/properties.pool/comment/values" +ds_prop__attr="/sys/module/zfs/properties.dataset/recordsize/values" + +log_assert $claim + +log_must cat $feature_attr +log_must cat $pool_prop__attr +log_must cat $ds_prop__attr + +# force a read of all the attributes for show func code coverage +log_must grep -R "[a-z]" /sys/module/zfs/features.* +log_must grep -R "[a-z]" /sys/module/zfs/properties.* +log_mustnot grep -RE "[^[:print:]]" /sys/module/zfs/properties.* + +log_pass $claim diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zpool_get_unsupported.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zpool_get_unsupported.ksh new file mode 100755 index 000000000..3ab1d941e --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zpool_get_unsupported.ksh @@ -0,0 +1,55 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# A property not supported by the zfs module should fail in 'zpool get ' +# +# STRATEGY: +# 1. Run zpool get with the env variable 'ZFS_SYSFS_PROP_SUPPORT_TEST' +# 2. Verify that zfs get returns error +# + +verify_runnable "global" + +if ! is_linux ; then + log_unsupported "sysfs is linux-only" +fi + +export ZFS_SYSFS_PROP_SUPPORT_TEST + +claim="Properties not supported by zfs module should fail in 'zpool get '" + +unsupported_prop="comment" + +log_assert $claim + +log_mustnot eval "ZFS_SYSFS_PROP_SUPPORT_TEST=yes zpool get \ + ${unsupported_prop} $TESTPOOL/$TESTFS >/dev/null 2>&1" + +log_pass $claim diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zpool_set_unsupported.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zpool_set_unsupported.ksh new file mode 100755 index 000000000..03eb2aea3 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_sysfs/zpool_set_unsupported.ksh @@ -0,0 +1,54 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# A property not supported by the zfs module should fail in 'zpool set ' +# +# STRATEGY: +# 1. Run zpool set with the env variable 'ZFS_SYSFS_PROP_SUPPORT_TEST' +# 2. Verify that zpool set returns error +# + +verify_runnable "global" + +if ! is_linux ; then + log_unsupported "sysfs is linux-only" +fi + +claim="Properties not supported by zfs module should fail in 'zpool set '" + +unsupported_prop="comment" +value="You Shall Not Pass" + +log_assert $claim + +log_mustnot eval "ZFS_SYSFS_PROP_SUPPORT_TEST=yes zpool set \ + ${unsupported_prop}=${value} $TESTPOOL/$TESTFS >/dev/null 2>&1" + +log_pass $claim