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'
69 typedef struct zfs_mod_kobj zfs_mod_kobj_t
;
72 struct kobject zko_kobj
;
73 struct kobj_type zko_kobj_type
;
74 struct sysfs_ops zko_sysfs_ops
;
75 size_t zko_attr_count
;
76 struct attribute
*zko_attr_list
; /* allocated */
77 struct attribute
**zko_default_attrs
; /* allocated */
78 size_t zko_child_count
;
79 zfs_mod_kobj_t
*zko_children
; /* allocated */
82 #define ATTR_TABLE_SIZE(cnt) (sizeof (struct attribute) * (cnt))
83 /* Note +1 for NULL terminator slot */
84 #define DEFAULT_ATTR_SIZE(cnt) (sizeof (struct attribute *) * (cnt + 1))
85 #define CHILD_TABLE_SIZE(cnt) (sizeof (zfs_mod_kobj_t) * (cnt))
88 * These are the top-level kobjects under '/sys/module/zfs/'
90 static zfs_mod_kobj_t kernel_features_kobj
;
91 static zfs_mod_kobj_t pool_features_kobj
;
92 static zfs_mod_kobj_t dataset_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_attrs
!= NULL
) {
130 kmem_free(zkobj
->zko_default_attrs
,
131 DEFAULT_ATTR_SIZE(zkobj
->zko_attr_count
));
132 zkobj
->zko_default_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;
148 zfs_kobj_add_attr(zfs_mod_kobj_t
*zkobj
, int attr_num
, const char *attr_name
)
150 VERIFY3U(attr_num
, <, zkobj
->zko_attr_count
);
151 ASSERT(zkobj
->zko_attr_list
);
152 ASSERT(zkobj
->zko_default_attrs
);
154 zkobj
->zko_attr_list
[attr_num
].name
= attr_name
;
155 zkobj
->zko_attr_list
[attr_num
].mode
= 0444;
156 zkobj
->zko_default_attrs
[attr_num
] = &zkobj
->zko_attr_list
[attr_num
];
160 zfs_kobj_init(zfs_mod_kobj_t
*zkobj
, int attr_cnt
, int child_cnt
,
161 sysfs_show_func show_func
)
164 * Initialize object's attributes. Count can be zero.
167 zkobj
->zko_attr_list
= kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt
),
169 if (zkobj
->zko_attr_list
== NULL
)
172 /* this will always have at least one slot for NULL termination */
173 zkobj
->zko_default_attrs
= kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt
),
175 if (zkobj
->zko_default_attrs
== NULL
) {
176 if (zkobj
->zko_attr_list
!= NULL
) {
177 kmem_free(zkobj
->zko_attr_list
,
178 ATTR_TABLE_SIZE(attr_cnt
));
182 zkobj
->zko_attr_count
= attr_cnt
;
183 zkobj
->zko_kobj_type
.default_attrs
= zkobj
->zko_default_attrs
;
186 zkobj
->zko_children
= kmem_zalloc(CHILD_TABLE_SIZE(child_cnt
),
188 if (zkobj
->zko_children
== NULL
) {
189 if (zkobj
->zko_default_attrs
!= NULL
) {
190 kmem_free(zkobj
->zko_default_attrs
,
191 DEFAULT_ATTR_SIZE(attr_cnt
));
193 if (zkobj
->zko_attr_list
!= NULL
) {
194 kmem_free(zkobj
->zko_attr_list
,
195 ATTR_TABLE_SIZE(attr_cnt
));
199 zkobj
->zko_child_count
= child_cnt
;
202 zkobj
->zko_sysfs_ops
.show
= show_func
;
203 zkobj
->zko_kobj_type
.sysfs_ops
= &zkobj
->zko_sysfs_ops
;
204 zkobj
->zko_kobj_type
.release
= zfs_kobj_release
;
210 zfs_kobj_add(zfs_mod_kobj_t
*zkobj
, struct kobject
*parent
, const char *name
)
212 /* zko_default_attrs must be NULL terminated */
213 ASSERT(zkobj
->zko_default_attrs
!= NULL
);
214 ASSERT(zkobj
->zko_default_attrs
[zkobj
->zko_attr_count
] == NULL
);
216 kobject_init(&zkobj
->zko_kobj
, &zkobj
->zko_kobj_type
);
217 return (kobject_add(&zkobj
->zko_kobj
, parent
, name
));
221 * Each zfs property has these common attributes
223 static const char *zprop_attrs
[] = {
230 "datasets" /* zfs properties only */
233 #define ZFS_PROP_ATTR_COUNT ARRAY_SIZE(zprop_attrs)
234 #define ZPOOL_PROP_ATTR_COUNT (ZFS_PROP_ATTR_COUNT - 1)
236 static const char *zprop_types
[] = {
242 typedef struct zfs_type_map
{
244 const char *ztm_name
;
247 static zfs_type_map_t type_map
[] = {
248 {ZFS_TYPE_FILESYSTEM
, "filesystem"},
249 {ZFS_TYPE_SNAPSHOT
, "snapshot"},
250 {ZFS_TYPE_VOLUME
, "volume"},
251 {ZFS_TYPE_BOOKMARK
, "bookmark"}
255 * Show the content for a zfs property attribute
258 zprop_sysfs_show(const char *attr_name
, const zprop_desc_t
*property
,
259 char *buf
, size_t buflen
)
261 const char *show_str
;
263 /* For dataset properties list the dataset types that apply */
264 if (strcmp(attr_name
, "datasets") == 0 &&
265 property
->pd_types
!= ZFS_TYPE_POOL
) {
268 for (int i
= 0; i
< ARRAY_SIZE(type_map
); i
++) {
269 if (type_map
[i
].ztm_type
& property
->pd_types
) {
270 len
+= snprintf(buf
+ len
, buflen
- len
, "%s ",
271 type_map
[i
].ztm_name
);
274 len
+= snprintf(buf
+ len
, buflen
- len
, "\n");
278 if (strcmp(attr_name
, "type") == 0) {
279 show_str
= zprop_types
[property
->pd_proptype
];
280 } else if (strcmp(attr_name
, "readonly") == 0) {
281 show_str
= property
->pd_attr
== PROP_READONLY
? "1" : "0";
282 } else if (strcmp(attr_name
, "setonce") == 0) {
283 show_str
= property
->pd_attr
== PROP_ONETIME
? "1" : "0";
284 } else if (strcmp(attr_name
, "visible") == 0) {
285 show_str
= property
->pd_visible
? "1" : "0";
286 } else if (strcmp(attr_name
, "values") == 0) {
287 show_str
= property
->pd_values
? property
->pd_values
: "";
288 } else if (strcmp(attr_name
, "default") == 0) {
291 switch (property
->pd_proptype
) {
292 case PROP_TYPE_NUMBER
:
293 (void) snprintf(number
, sizeof (number
), "%llu",
294 (u_longlong_t
)property
->pd_numdefault
);
297 case PROP_TYPE_STRING
:
298 show_str
= property
->pd_strdefault
?
299 property
->pd_strdefault
: "";
301 case PROP_TYPE_INDEX
:
302 if (zprop_index_to_string(property
->pd_propnum
,
303 property
->pd_numdefault
, &show_str
,
304 property
->pd_types
) != 0) {
315 return (snprintf(buf
, buflen
, "%s\n", show_str
));
319 dataset_property_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
321 zfs_prop_t prop
= zfs_name_to_prop(kobject_name(kobj
));
322 zprop_desc_t
*prop_tbl
= zfs_prop_get_table();
325 ASSERT3U(prop
, <, ZFS_NUM_PROPS
);
327 len
= zprop_sysfs_show(attr
->name
, &prop_tbl
[prop
], buf
, PAGE_SIZE
);
333 pool_property_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
335 zpool_prop_t prop
= zpool_name_to_prop(kobject_name(kobj
));
336 zprop_desc_t
*prop_tbl
= zpool_prop_get_table();
339 ASSERT3U(prop
, <, ZPOOL_NUM_PROPS
);
341 len
= zprop_sysfs_show(attr
->name
, &prop_tbl
[prop
], buf
, PAGE_SIZE
);
347 * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
349 * This list is intended for kernel features that don't have a pool feature
350 * association or that extend existing user kernel interfaces.
352 * A user processes can easily check if the running zfs kernel module
353 * supports the new feature.
355 static const char *zfs_kernel_features
[] = {
356 /* --> Add new kernel features here */
357 "com.delphix:vdev_initialize",
358 "org.zfsonlinux:vdev_trim",
361 #define KERNEL_FEATURE_COUNT ARRAY_SIZE(zfs_kernel_features)
364 kernel_feature_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
366 if (strcmp(attr
->name
, "supported") == 0)
367 return (snprintf(buf
, PAGE_SIZE
, "yes\n"));
372 kernel_feature_to_kobj(zfs_mod_kobj_t
*parent
, int slot
, const char *name
)
374 zfs_mod_kobj_t
*zfs_kobj
= &parent
->zko_children
[slot
];
376 ASSERT3U(slot
, <, KERNEL_FEATURE_COUNT
);
379 int err
= zfs_kobj_init(zfs_kobj
, 1, 0, kernel_feature_show
);
383 zfs_kobj_add_attr(zfs_kobj
, 0, "supported");
385 err
= zfs_kobj_add(zfs_kobj
, &parent
->zko_kobj
, name
);
387 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
391 zfs_kernel_features_init(zfs_mod_kobj_t
*zfs_kobj
, struct kobject
*parent
)
394 * Create a parent kobject to host kernel features.
396 * '/sys/module/zfs/features.kernel'
398 int err
= zfs_kobj_init(zfs_kobj
, 0, KERNEL_FEATURE_COUNT
,
399 kernel_feature_show
);
402 err
= zfs_kobj_add(zfs_kobj
, parent
, ZFS_SYSFS_KERNEL_FEATURES
);
404 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
409 * Now create a kobject for each feature.
411 * '/sys/module/zfs/features.kernel/<feature>'
413 for (int f
= 0; f
< KERNEL_FEATURE_COUNT
; f
++)
414 kernel_feature_to_kobj(zfs_kobj
, f
, zfs_kernel_features
[f
]);
420 * Each pool feature has these common attributes
422 static const char *pool_feature_attrs
[] = {
426 "readonly_compatible",
428 "activate_on_enable",
432 #define ZPOOL_FEATURE_ATTR_COUNT ARRAY_SIZE(pool_feature_attrs)
435 * Show the content for the given zfs pool feature attribute
438 pool_feature_show(struct kobject
*kobj
, struct attribute
*attr
, char *buf
)
442 if (zfeature_lookup_guid(kobject_name(kobj
), &fid
) != 0)
445 ASSERT3U(fid
, <, SPA_FEATURES
);
447 zfeature_flags_t flags
= spa_feature_table
[fid
].fi_flags
;
448 const char *show_str
= NULL
;
450 if (strcmp(attr
->name
, "description") == 0) {
451 show_str
= spa_feature_table
[fid
].fi_desc
;
452 } else if (strcmp(attr
->name
, "guid") == 0) {
453 show_str
= spa_feature_table
[fid
].fi_guid
;
454 } else if (strcmp(attr
->name
, "uname") == 0) {
455 show_str
= spa_feature_table
[fid
].fi_uname
;
456 } else if (strcmp(attr
->name
, "readonly_compatible") == 0) {
457 show_str
= flags
& ZFEATURE_FLAG_READONLY_COMPAT
? "1" : "0";
458 } else if (strcmp(attr
->name
, "required_for_mos") == 0) {
459 show_str
= flags
& ZFEATURE_FLAG_MOS
? "1" : "0";
460 } else if (strcmp(attr
->name
, "activate_on_enable") == 0) {
461 show_str
= flags
& ZFEATURE_FLAG_ACTIVATE_ON_ENABLE
? "1" : "0";
462 } else if (strcmp(attr
->name
, "per_dataset") == 0) {
463 show_str
= flags
& ZFEATURE_FLAG_PER_DATASET
? "1" : "0";
465 if (show_str
== NULL
)
468 return (snprintf(buf
, PAGE_SIZE
, "%s\n", show_str
));
472 pool_feature_to_kobj(zfs_mod_kobj_t
*parent
, spa_feature_t fid
,
475 zfs_mod_kobj_t
*zfs_kobj
= &parent
->zko_children
[fid
];
477 ASSERT3U(fid
, <, SPA_FEATURES
);
480 int err
= zfs_kobj_init(zfs_kobj
, ZPOOL_FEATURE_ATTR_COUNT
, 0,
485 for (int i
= 0; i
< ZPOOL_FEATURE_ATTR_COUNT
; i
++)
486 zfs_kobj_add_attr(zfs_kobj
, i
, pool_feature_attrs
[i
]);
488 err
= zfs_kobj_add(zfs_kobj
, &parent
->zko_kobj
, name
);
490 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
494 zfs_pool_features_init(zfs_mod_kobj_t
*zfs_kobj
, struct kobject
*parent
)
497 * Create a parent kobject to host pool features.
499 * '/sys/module/zfs/features.pool'
501 int err
= zfs_kobj_init(zfs_kobj
, 0, SPA_FEATURES
, pool_feature_show
);
504 err
= zfs_kobj_add(zfs_kobj
, parent
, ZFS_SYSFS_POOL_FEATURES
);
506 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
511 * Now create a kobject for each feature.
513 * '/sys/module/zfs/features.pool/<feature>'
515 for (spa_feature_t i
= 0; i
< SPA_FEATURES
; i
++)
516 pool_feature_to_kobj(zfs_kobj
, i
, spa_feature_table
[i
].fi_guid
);
521 typedef struct prop_to_kobj_arg
{
522 zprop_desc_t
*p2k_table
;
523 zfs_mod_kobj_t
*p2k_parent
;
524 sysfs_show_func p2k_show_func
;
526 } prop_to_kobj_arg_t
;
529 zprop_to_kobj(int prop
, void *args
)
531 prop_to_kobj_arg_t
*data
= args
;
532 zfs_mod_kobj_t
*parent
= data
->p2k_parent
;
533 zfs_mod_kobj_t
*zfs_kobj
= &parent
->zko_children
[prop
];
534 const char *name
= data
->p2k_table
[prop
].pd_name
;
539 err
= zfs_kobj_init(zfs_kobj
, data
->p2k_attr_count
, 0,
540 data
->p2k_show_func
);
544 for (int i
= 0; i
< data
->p2k_attr_count
; i
++)
545 zfs_kobj_add_attr(zfs_kobj
, i
, zprop_attrs
[i
]);
547 err
= zfs_kobj_add(zfs_kobj
, &parent
->zko_kobj
, name
);
549 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
555 zfs_sysfs_properties_init(zfs_mod_kobj_t
*zfs_kobj
, struct kobject
*parent
,
558 prop_to_kobj_arg_t context
;
563 * Create a parent kobject to host properties.
565 * '/sys/module/zfs/properties.<type>'
567 if (type
== ZFS_TYPE_POOL
) {
568 name
= ZFS_SYSFS_POOL_PROPERTIES
;
569 context
.p2k_table
= zpool_prop_get_table();
570 context
.p2k_attr_count
= ZPOOL_PROP_ATTR_COUNT
;
571 context
.p2k_parent
= zfs_kobj
;
572 context
.p2k_show_func
= pool_property_show
;
573 err
= zfs_kobj_init(zfs_kobj
, 0, ZPOOL_NUM_PROPS
,
576 name
= ZFS_SYSFS_DATASET_PROPERTIES
;
577 context
.p2k_table
= zfs_prop_get_table();
578 context
.p2k_attr_count
= ZFS_PROP_ATTR_COUNT
;
579 context
.p2k_parent
= zfs_kobj
;
580 context
.p2k_show_func
= dataset_property_show
;
581 err
= zfs_kobj_init(zfs_kobj
, 0, ZFS_NUM_PROPS
,
582 dataset_property_show
);
588 err
= zfs_kobj_add(zfs_kobj
, parent
, name
);
590 zfs_kobj_release(&zfs_kobj
->zko_kobj
);
595 * Create a kobject for each property.
597 * '/sys/module/zfs/properties.<type>/<property>'
599 (void) zprop_iter_common(zprop_to_kobj
, &context
, B_TRUE
,
608 struct kobject
*parent
;
609 #if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
610 parent
= kobject_create_and_add("zfs", fs_kobj
);
612 parent
= &(((struct module
*)(THIS_MODULE
))->mkobj
).kobj
;
619 err
= zfs_kernel_features_init(&kernel_features_kobj
, parent
);
623 err
= zfs_pool_features_init(&pool_features_kobj
, parent
);
625 zfs_kobj_fini(&kernel_features_kobj
);
629 err
= zfs_sysfs_properties_init(&pool_props_kobj
, parent
,
632 zfs_kobj_fini(&kernel_features_kobj
);
633 zfs_kobj_fini(&pool_features_kobj
);
637 err
= zfs_sysfs_properties_init(&dataset_props_kobj
, parent
,
638 ZFS_TYPE_FILESYSTEM
);
640 zfs_kobj_fini(&kernel_features_kobj
);
641 zfs_kobj_fini(&pool_features_kobj
);
642 zfs_kobj_fini(&pool_props_kobj
);
651 * Remove top-level kobjects; each will remove any children kobjects
653 zfs_kobj_fini(&kernel_features_kobj
);
654 zfs_kobj_fini(&pool_features_kobj
);
655 zfs_kobj_fini(&dataset_props_kobj
);
656 zfs_kobj_fini(&pool_props_kobj
);