4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2018, 2019 by Delphix. All rights reserved.
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/zfeature.h>
28 #include <sys/zfs_ioctl.h>
29 #include <sys/zfs_sysfs.h>
31 #include <sys/fs/zfs.h>
32 #include <linux/kobject.h>
37 #error kernel builds only
41 * ZFS Module sysfs support
43 * This extends our sysfs '/sys/module/zfs' entry to include feature
44 * and property attributes. The primary consumer of this information
45 * is user processes, like the zfs CLI, that need to know what the
46 * current loaded ZFS module supports. The libzfs binary will consult
47 * this information when instantiating the zfs|zpool property tables
48 * and the pool features table.
50 * The added top-level directories are:
54 * ├── properties.dataset
57 * The local interface for the zfs kobjects includes:
66 * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs'
68 typedef struct zfs_mod_kobj zfs_mod_kobj_t
;
70 struct kobject zko_kobj
;
71 struct kobj_type zko_kobj_type
;
72 struct sysfs_ops zko_sysfs_ops
;
73 size_t zko_attr_count
;
74 struct attribute
*zko_attr_list
; /* allocated */
75 struct attribute_group zko_default_group
; /* .attrs allocated */
76 const struct attribute_group
*zko_default_groups
[2];
77 size_t zko_child_count
;
78 zfs_mod_kobj_t
*zko_children
; /* allocated */
81 #define ATTR_TABLE_SIZE(cnt) (sizeof (struct attribute) * (cnt))
82 /* Note +1 for NULL terminator slot */
83 #define DEFAULT_ATTR_SIZE(cnt) (sizeof (struct attribute *) * (cnt + 1))
84 #define CHILD_TABLE_SIZE(cnt) (sizeof (zfs_mod_kobj_t) * (cnt))
87 * These are the top-level kobjects under '/sys/module/zfs/'
89 static zfs_mod_kobj_t kernel_features_kobj
;
90 static zfs_mod_kobj_t pool_features_kobj
;
91 static zfs_mod_kobj_t dataset_props_kobj
;
92 static zfs_mod_kobj_t vdev_props_kobj
;
93 static zfs_mod_kobj_t pool_props_kobj
;
96 * The show function is used to provide the content
97 * of an attribute into a PAGE_SIZE buffer.
99 typedef ssize_t (*sysfs_show_func
)(struct kobject
*, struct attribute
*,
103 zfs_kobj_fini(zfs_mod_kobj_t
*zkobj
)
105 /* finalize any child kobjects */
106 if (zkobj
->zko_child_count
!= 0) {
107 ASSERT(zkobj
->zko_children
);
108 for (int i
= 0; i
< zkobj
->zko_child_count
; i
++)
109 zfs_kobj_fini(&zkobj
->zko_children
[i
]);
112 /* kobject_put() will call zfs_kobj_release() to release memory */
113 kobject_del(&zkobj
->zko_kobj
);
114 kobject_put(&zkobj
->zko_kobj
);
118 zfs_kobj_release(struct kobject
*kobj
)
120 zfs_mod_kobj_t
*zkobj
= container_of(kobj
, zfs_mod_kobj_t
, zko_kobj
);
122 if (zkobj
->zko_attr_list
!= NULL
) {
123 ASSERT3S(zkobj
->zko_attr_count
, !=, 0);
124 kmem_free(zkobj
->zko_attr_list
,
125 ATTR_TABLE_SIZE(zkobj
->zko_attr_count
));
126 zkobj
->zko_attr_list
= NULL
;
129 if (zkobj
->zko_default_group
.attrs
!= NULL
) {
130 kmem_free(zkobj
->zko_default_group
.attrs
,
131 DEFAULT_ATTR_SIZE(zkobj
->zko_attr_count
));
132 zkobj
->zko_default_group
.attrs
= NULL
;
135 if (zkobj
->zko_child_count
!= 0) {
136 ASSERT(zkobj
->zko_children
);
138 kmem_free(zkobj
->zko_children
,
139 CHILD_TABLE_SIZE(zkobj
->zko_child_count
));
140 zkobj
->zko_child_count
= 0;
141 zkobj
->zko_children
= NULL
;
144 zkobj
->zko_attr_count
= 0;
147 #ifndef sysfs_attr_init
148 #define sysfs_attr_init(attr) do {} while (0)
152 zfs_kobj_add_attr(zfs_mod_kobj_t
*zkobj
, int attr_num
, const char *attr_name
)
154 VERIFY3U(attr_num
, <, zkobj
->zko_attr_count
);
155 ASSERT(zkobj
->zko_attr_list
);
156 ASSERT(zkobj
->zko_default_group
.attrs
);
158 zkobj
->zko_attr_list
[attr_num
].name
= attr_name
;
159 zkobj
->zko_attr_list
[attr_num
].mode
= 0444;
160 zkobj
->zko_default_group
.attrs
[attr_num
] =
161 &zkobj
->zko_attr_list
[attr_num
];
162 sysfs_attr_init(&zkobj
->zko_attr_list
[attr_num
]);
166 zfs_kobj_init(zfs_mod_kobj_t
*zkobj
, int attr_cnt
, int child_cnt
,
167 sysfs_show_func show_func
)
170 * Initialize object's attributes. Count can be zero.
173 zkobj
->zko_attr_list
= kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt
),
175 if (zkobj
->zko_attr_list
== NULL
)
178 /* this will always have at least one slot for NULL termination */
179 zkobj
->zko_default_group
.attrs
=
180 kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt
), KM_SLEEP
);
181 if (zkobj
->zko_default_group
.attrs
== NULL
) {
182 if (zkobj
->zko_attr_list
!= NULL
) {
183 kmem_free(zkobj
->zko_attr_list
,
184 ATTR_TABLE_SIZE(attr_cnt
));
188 zkobj
->zko_attr_count
= attr_cnt
;
189 zkobj
->zko_default_groups
[0] = &zkobj
->zko_default_group
;
190 #ifdef HAVE_SYSFS_DEFAULT_GROUPS
191 zkobj
->zko_kobj_type
.default_groups
= zkobj
->zko_default_groups
;
193 zkobj
->zko_kobj_type
.default_attrs
= zkobj
->zko_default_group
.attrs
;
197 zkobj
->zko_children
= kmem_zalloc(CHILD_TABLE_SIZE(child_cnt
),
199 if (zkobj
->zko_children
== NULL
) {
200 if (zkobj
->zko_default_group
.attrs
!= NULL
) {
201 kmem_free(zkobj
->zko_default_group
.attrs
,
202 DEFAULT_ATTR_SIZE(attr_cnt
));
204 if (zkobj
->zko_attr_list
!= NULL
) {
205 kmem_free(zkobj
->zko_attr_list
,
206 ATTR_TABLE_SIZE(attr_cnt
));
210 zkobj
->zko_child_count
= child_cnt
;
213 zkobj
->zko_sysfs_ops
.show
= show_func
;
214 zkobj
->zko_kobj_type
.sysfs_ops
= &zkobj
->zko_sysfs_ops
;
215 zkobj
->zko_kobj_type
.release
= zfs_kobj_release
;
221 zfs_kobj_add(zfs_mod_kobj_t
*zkobj
, struct kobject
*parent
, const char *name
)
223 /* zko_default_group.attrs must be NULL terminated */
224 ASSERT(zkobj
->zko_default_group
.attrs
!= NULL
);
225 ASSERT(zkobj
->zko_default_group
.attrs
[zkobj
->zko_attr_count
] == NULL
);
227 kobject_init(&zkobj
->zko_kobj
, &zkobj
->zko_kobj_type
);
228 return (kobject_add(&zkobj
->zko_kobj
, parent
, name
));
232 * Each zfs property has these common attributes
234 static const char *const zprop_attrs
[] = {
241 "datasets" /* zfs properties only */
244 #define ZFS_PROP_ATTR_COUNT ARRAY_SIZE(zprop_attrs)
245 #define ZPOOL_PROP_ATTR_COUNT (ZFS_PROP_ATTR_COUNT - 1)
247 static const char *const zprop_types
[] = {
253 typedef struct zfs_type_map
{
255 const char *ztm_name
;
258 static const zfs_type_map_t type_map
[] = {
259 {ZFS_TYPE_FILESYSTEM
, "filesystem"},
260 {ZFS_TYPE_SNAPSHOT
, "snapshot"},
261 {ZFS_TYPE_VOLUME
, "volume"},
262 {ZFS_TYPE_BOOKMARK
, "bookmark"}
266 * Show the content for a zfs property attribute
269 zprop_sysfs_show(const char *attr_name
, const zprop_desc_t
*property
,
270 char *buf
, size_t buflen
)
272 const char *show_str
;
275 /* For dataset properties list the dataset types that apply */
276 if (strcmp(attr_name
, "datasets") == 0 &&
277 property
->pd_types
!= ZFS_TYPE_POOL
) {
280 for (int i
= 0; i
< ARRAY_SIZE(type_map
); i
++) {
281 if (type_map
[i
].ztm_type
& property
->pd_types
) {
282 len
+= snprintf(buf
+ len
, buflen
- len
, "%s ",
283 type_map
[i
].ztm_name
);
286 len
+= snprintf(buf
+ len
, buflen
- len
, "\n");
290 if (strcmp(attr_name
, "type") == 0) {
291 show_str
= zprop_types
[property
->pd_proptype
];
292 } else if (strcmp(attr_name
, "readonly") == 0) {
293 show_str
= property
->pd_attr
== PROP_READONLY
? "1" : "0";
294 } else if (strcmp(attr_name
, "setonce") == 0) {
295 show_str
= property
->pd_attr
== PROP_ONETIME
? "1" : "0";
296 } else if (strcmp(attr_name
, "visible") == 0) {
297 show_str
= property
->pd_visible
? "1" : "0";
298 } else if (strcmp(attr_name
, "values") == 0) {
299 show_str
= property
->pd_values
? property
->pd_values
: "";
300 } else if (strcmp(attr_name
, "default") == 0) {
301 switch (property
->pd_proptype
) {
302 case PROP_TYPE_NUMBER
:
303 (void) snprintf(number
, sizeof (number
), "%llu",
304 (u_longlong_t
)property
->pd_numdefault
);
307 case PROP_TYPE_STRING
:
308 show_str
= property
->pd_strdefault
?
309 property
->pd_strdefault
: "";
311 case PROP_TYPE_INDEX
:
312 if (zprop_index_to_string(property
->pd_propnum
,
313 property
->pd_numdefault
, &show_str
,
314 property
->pd_types
) != 0) {
325 return (snprintf(buf
, buflen
, "%s\n", show_str
));
329 dataset_property_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
331 zfs_prop_t prop
= zfs_name_to_prop(kobject_name(kobj
));
332 zprop_desc_t
*prop_tbl
= zfs_prop_get_table();
335 ASSERT3U(prop
, <, ZFS_NUM_PROPS
);
337 len
= zprop_sysfs_show(attr
->name
, &prop_tbl
[prop
], buf
, PAGE_SIZE
);
343 vdev_property_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
345 vdev_prop_t prop
= vdev_name_to_prop(kobject_name(kobj
));
346 zprop_desc_t
*prop_tbl
= vdev_prop_get_table();
349 ASSERT3U(prop
, <, VDEV_NUM_PROPS
);
351 len
= zprop_sysfs_show(attr
->name
, &prop_tbl
[prop
], buf
, PAGE_SIZE
);
357 pool_property_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
359 zpool_prop_t prop
= zpool_name_to_prop(kobject_name(kobj
));
360 zprop_desc_t
*prop_tbl
= zpool_prop_get_table();
363 ASSERT3U(prop
, <, ZPOOL_NUM_PROPS
);
365 len
= zprop_sysfs_show(attr
->name
, &prop_tbl
[prop
], buf
, PAGE_SIZE
);
371 * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
373 * This list is intended for kernel features that don't have a pool feature
374 * association or that extend existing user kernel interfaces.
376 * A user process can easily check if the running zfs kernel module
377 * supports the new feature.
379 static const char *const zfs_kernel_features
[] = {
380 /* --> Add new kernel features here */
381 "com.delphix:vdev_initialize",
382 "org.zfsonlinux:vdev_trim",
383 "org.openzfs:l2arc_persistent",
386 #define KERNEL_FEATURE_COUNT ARRAY_SIZE(zfs_kernel_features)
389 kernel_feature_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
391 if (strcmp(attr
->name
, "supported") == 0)
392 return (snprintf(buf
, PAGE_SIZE
, "yes\n"));
397 kernel_feature_to_kobj(zfs_mod_kobj_t
*parent
, int slot
, const char *name
)
399 zfs_mod_kobj_t
*zfs_kobj
= &parent
->zko_children
[slot
];
401 ASSERT3U(slot
, <, KERNEL_FEATURE_COUNT
);
404 int err
= zfs_kobj_init(zfs_kobj
, 1, 0, kernel_feature_show
);
408 zfs_kobj_add_attr(zfs_kobj
, 0, "supported");
410 err
= zfs_kobj_add(zfs_kobj
, &parent
->zko_kobj
, name
);
412 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
416 zfs_kernel_features_init(zfs_mod_kobj_t
*zfs_kobj
, struct kobject
*parent
)
419 * Create a parent kobject to host kernel features.
421 * '/sys/module/zfs/features.kernel'
423 int err
= zfs_kobj_init(zfs_kobj
, 0, KERNEL_FEATURE_COUNT
,
424 kernel_feature_show
);
427 err
= zfs_kobj_add(zfs_kobj
, parent
, ZFS_SYSFS_KERNEL_FEATURES
);
429 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
434 * Now create a kobject for each feature.
436 * '/sys/module/zfs/features.kernel/<feature>'
438 for (int f
= 0; f
< KERNEL_FEATURE_COUNT
; f
++)
439 kernel_feature_to_kobj(zfs_kobj
, f
, zfs_kernel_features
[f
]);
445 * Each pool feature has these common attributes
447 static const char *const pool_feature_attrs
[] = {
451 "readonly_compatible",
453 "activate_on_enable",
457 #define ZPOOL_FEATURE_ATTR_COUNT ARRAY_SIZE(pool_feature_attrs)
460 * Show the content for the given zfs pool feature attribute
463 pool_feature_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
467 if (zfeature_lookup_guid(kobject_name(kobj
), &fid
) != 0)
470 ASSERT3U(fid
, <, SPA_FEATURES
);
472 zfeature_flags_t flags
= spa_feature_table
[fid
].fi_flags
;
473 const char *show_str
= NULL
;
475 if (strcmp(attr
->name
, "description") == 0) {
476 show_str
= spa_feature_table
[fid
].fi_desc
;
477 } else if (strcmp(attr
->name
, "guid") == 0) {
478 show_str
= spa_feature_table
[fid
].fi_guid
;
479 } else if (strcmp(attr
->name
, "uname") == 0) {
480 show_str
= spa_feature_table
[fid
].fi_uname
;
481 } else if (strcmp(attr
->name
, "readonly_compatible") == 0) {
482 show_str
= flags
& ZFEATURE_FLAG_READONLY_COMPAT
? "1" : "0";
483 } else if (strcmp(attr
->name
, "required_for_mos") == 0) {
484 show_str
= flags
& ZFEATURE_FLAG_MOS
? "1" : "0";
485 } else if (strcmp(attr
->name
, "activate_on_enable") == 0) {
486 show_str
= flags
& ZFEATURE_FLAG_ACTIVATE_ON_ENABLE
? "1" : "0";
487 } else if (strcmp(attr
->name
, "per_dataset") == 0) {
488 show_str
= flags
& ZFEATURE_FLAG_PER_DATASET
? "1" : "0";
490 if (show_str
== NULL
)
493 return (snprintf(buf
, PAGE_SIZE
, "%s\n", show_str
));
497 pool_feature_to_kobj(zfs_mod_kobj_t
*parent
, spa_feature_t fid
,
500 zfs_mod_kobj_t
*zfs_kobj
= &parent
->zko_children
[fid
];
502 ASSERT3U(fid
, <, SPA_FEATURES
);
505 int err
= zfs_kobj_init(zfs_kobj
, ZPOOL_FEATURE_ATTR_COUNT
, 0,
510 for (int i
= 0; i
< ZPOOL_FEATURE_ATTR_COUNT
; i
++)
511 zfs_kobj_add_attr(zfs_kobj
, i
, pool_feature_attrs
[i
]);
513 err
= zfs_kobj_add(zfs_kobj
, &parent
->zko_kobj
, name
);
515 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
519 zfs_pool_features_init(zfs_mod_kobj_t
*zfs_kobj
, struct kobject
*parent
)
522 * Create a parent kobject to host pool features.
524 * '/sys/module/zfs/features.pool'
526 int err
= zfs_kobj_init(zfs_kobj
, 0, SPA_FEATURES
, pool_feature_show
);
529 err
= zfs_kobj_add(zfs_kobj
, parent
, ZFS_SYSFS_POOL_FEATURES
);
531 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
536 * Now create a kobject for each feature.
538 * '/sys/module/zfs/features.pool/<feature>'
540 for (spa_feature_t i
= 0; i
< SPA_FEATURES
; i
++)
541 pool_feature_to_kobj(zfs_kobj
, i
, spa_feature_table
[i
].fi_guid
);
546 typedef struct prop_to_kobj_arg
{
547 zprop_desc_t
*p2k_table
;
548 zfs_mod_kobj_t
*p2k_parent
;
549 sysfs_show_func p2k_show_func
;
551 } prop_to_kobj_arg_t
;
554 zprop_to_kobj(int prop
, void *args
)
556 prop_to_kobj_arg_t
*data
= args
;
557 zfs_mod_kobj_t
*parent
= data
->p2k_parent
;
558 zfs_mod_kobj_t
*zfs_kobj
= &parent
->zko_children
[prop
];
559 const char *name
= data
->p2k_table
[prop
].pd_name
;
564 err
= zfs_kobj_init(zfs_kobj
, data
->p2k_attr_count
, 0,
565 data
->p2k_show_func
);
569 for (int i
= 0; i
< data
->p2k_attr_count
; i
++)
570 zfs_kobj_add_attr(zfs_kobj
, i
, zprop_attrs
[i
]);
572 err
= zfs_kobj_add(zfs_kobj
, &parent
->zko_kobj
, name
);
574 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
580 zfs_sysfs_properties_init(zfs_mod_kobj_t
*zfs_kobj
, struct kobject
*parent
,
583 prop_to_kobj_arg_t context
;
588 * Create a parent kobject to host properties.
590 * '/sys/module/zfs/properties.<type>'
592 if (type
== ZFS_TYPE_POOL
) {
593 name
= ZFS_SYSFS_POOL_PROPERTIES
;
594 context
.p2k_table
= zpool_prop_get_table();
595 context
.p2k_attr_count
= ZPOOL_PROP_ATTR_COUNT
;
596 context
.p2k_parent
= zfs_kobj
;
597 context
.p2k_show_func
= pool_property_show
;
598 err
= zfs_kobj_init(zfs_kobj
, 0, ZPOOL_NUM_PROPS
,
600 } else if (type
== ZFS_TYPE_VDEV
) {
601 name
= ZFS_SYSFS_VDEV_PROPERTIES
;
602 context
.p2k_table
= vdev_prop_get_table();
603 context
.p2k_attr_count
= ZPOOL_PROP_ATTR_COUNT
;
604 context
.p2k_parent
= zfs_kobj
;
605 context
.p2k_show_func
= vdev_property_show
;
606 err
= zfs_kobj_init(zfs_kobj
, 0, VDEV_NUM_PROPS
,
609 name
= ZFS_SYSFS_DATASET_PROPERTIES
;
610 context
.p2k_table
= zfs_prop_get_table();
611 context
.p2k_attr_count
= ZFS_PROP_ATTR_COUNT
;
612 context
.p2k_parent
= zfs_kobj
;
613 context
.p2k_show_func
= dataset_property_show
;
614 err
= zfs_kobj_init(zfs_kobj
, 0, ZFS_NUM_PROPS
,
615 dataset_property_show
);
621 err
= zfs_kobj_add(zfs_kobj
, parent
, name
);
623 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
628 * Create a kobject for each property.
630 * '/sys/module/zfs/properties.<type>/<property>'
632 (void) zprop_iter_common(zprop_to_kobj
, &context
, B_TRUE
,
641 struct kobject
*parent
;
642 #if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
643 parent
= kobject_create_and_add("zfs", fs_kobj
);
645 parent
= &(((struct module
*)(THIS_MODULE
))->mkobj
).kobj
;
652 err
= zfs_kernel_features_init(&kernel_features_kobj
, parent
);
656 err
= zfs_pool_features_init(&pool_features_kobj
, parent
);
658 zfs_kobj_fini(&kernel_features_kobj
);
662 err
= zfs_sysfs_properties_init(&pool_props_kobj
, parent
,
665 zfs_kobj_fini(&kernel_features_kobj
);
666 zfs_kobj_fini(&pool_features_kobj
);
670 err
= zfs_sysfs_properties_init(&vdev_props_kobj
, parent
,
673 zfs_kobj_fini(&kernel_features_kobj
);
674 zfs_kobj_fini(&pool_features_kobj
);
675 zfs_kobj_fini(&pool_props_kobj
);
679 err
= zfs_sysfs_properties_init(&dataset_props_kobj
, parent
,
680 ZFS_TYPE_FILESYSTEM
);
682 zfs_kobj_fini(&kernel_features_kobj
);
683 zfs_kobj_fini(&pool_features_kobj
);
684 zfs_kobj_fini(&pool_props_kobj
);
685 zfs_kobj_fini(&vdev_props_kobj
);
694 * Remove top-level kobjects; each will remove any children kobjects
696 zfs_kobj_fini(&kernel_features_kobj
);
697 zfs_kobj_fini(&pool_features_kobj
);
698 zfs_kobj_fini(&pool_props_kobj
);
699 zfs_kobj_fini(&vdev_props_kobj
);
700 zfs_kobj_fini(&dataset_props_kobj
);