xref: /freebsd/sys/contrib/openzfs/module/os/linux/zfs/zfs_sysfs.c (revision 657729a89dd578d8cfc70d6616f5c65a48a8b33a)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or https://opensource.org/licenses/CDDL-1.0.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2018, 2019 by Delphix. All rights reserved.
23  */
24 
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>
30 #include <sys/kmem.h>
31 #include <sys/fs/zfs.h>
32 #include <linux/kobject.h>
33 
34 #include "zfs_prop.h"
35 
36 #if !defined(_KERNEL)
37 #error kernel builds only
38 #endif
39 
40 /*
41  * ZFS Module sysfs support
42  *
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.
49  *
50  * The added top-level directories are:
51  * /sys/module/zfs
52  *		├── features.kernel
53  *		├── features.pool
54  *		├── properties.dataset
55  *		└── properties.pool
56  *
57  * The local interface for the zfs kobjects includes:
58  *	zfs_kobj_init()
59  *	zfs_kobj_add()
60  *	zfs_kobj_release()
61  *	zfs_kobj_add_attr()
62  *	zfs_kobj_fini()
63  */
64 
65 /*
66  * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs'
67  */
68 typedef struct zfs_mod_kobj zfs_mod_kobj_t;
69 struct zfs_mod_kobj {
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 */
79 };
80 
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))
85 
86 /*
87  * These are the top-level kobjects under '/sys/module/zfs/'
88  */
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;
94 
95 /*
96  * The show function is used to provide the content
97  * of an attribute into a PAGE_SIZE buffer.
98  */
99 typedef ssize_t	(*sysfs_show_func)(struct kobject *, struct attribute *,
100     char *);
101 
102 static void
103 zfs_kobj_fini(zfs_mod_kobj_t *zkobj)
104 {
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]);
110 	}
111 
112 	/* kobject_put() will call zfs_kobj_release() to release memory */
113 	kobject_del(&zkobj->zko_kobj);
114 	kobject_put(&zkobj->zko_kobj);
115 }
116 
117 static void
118 zfs_kobj_release(struct kobject *kobj)
119 {
120 	zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj);
121 
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;
127 	}
128 
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;
133 	}
134 
135 	if (zkobj->zko_child_count != 0) {
136 		ASSERT(zkobj->zko_children);
137 
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;
142 	}
143 
144 	zkobj->zko_attr_count = 0;
145 }
146 
147 #ifndef sysfs_attr_init
148 #define	sysfs_attr_init(attr) do {} while (0)
149 #endif
150 
151 static void
152 zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name)
153 {
154 	VERIFY3U(attr_num, <, zkobj->zko_attr_count);
155 	ASSERT(zkobj->zko_attr_list);
156 	ASSERT(zkobj->zko_default_group.attrs);
157 
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]);
163 }
164 
165 static int
166 zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
167     sysfs_show_func show_func)
168 {
169 	/*
170 	 * Initialize object's attributes. Count can be zero.
171 	 */
172 	if (attr_cnt > 0) {
173 		zkobj->zko_attr_list = kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt),
174 		    KM_SLEEP);
175 		if (zkobj->zko_attr_list == NULL)
176 			return (ENOMEM);
177 	}
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));
185 		}
186 		return (ENOMEM);
187 	}
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;
192 #else
193 	zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_group.attrs;
194 #endif
195 
196 	if (child_cnt > 0) {
197 		zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
198 		    KM_SLEEP);
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));
203 			}
204 			if (zkobj->zko_attr_list != NULL) {
205 				kmem_free(zkobj->zko_attr_list,
206 				    ATTR_TABLE_SIZE(attr_cnt));
207 			}
208 			return (ENOMEM);
209 		}
210 		zkobj->zko_child_count = child_cnt;
211 	}
212 
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;
216 
217 	return (0);
218 }
219 
220 static int
221 zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name)
222 {
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);
226 
227 	kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type);
228 	return (kobject_add(&zkobj->zko_kobj, parent, name));
229 }
230 
231 /*
232  * Each zfs property has these common attributes
233  */
234 static const char *const zprop_attrs[]  = {
235 	"type",
236 	"readonly",
237 	"setonce",
238 	"visible",
239 	"values",
240 	"default",
241 	"datasets"	/* zfs properties only */
242 };
243 
244 #define	ZFS_PROP_ATTR_COUNT	ARRAY_SIZE(zprop_attrs)
245 #define	ZPOOL_PROP_ATTR_COUNT	(ZFS_PROP_ATTR_COUNT - 1)
246 
247 static const char *const zprop_types[]  = {
248 	"number",
249 	"string",
250 	"index",
251 };
252 
253 typedef struct zfs_type_map {
254 	zfs_type_t	ztm_type;
255 	const char	*ztm_name;
256 } zfs_type_map_t;
257 
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"}
263 };
264 
265 /*
266  * Show the content for a zfs property attribute
267  */
268 static ssize_t
269 zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property,
270     char *buf, size_t buflen)
271 {
272 	const char *show_str;
273 	char number[32];
274 
275 	/* For dataset properties list the dataset types that apply */
276 	if (strcmp(attr_name, "datasets") == 0 &&
277 	    property->pd_types != ZFS_TYPE_POOL) {
278 		int len = 0;
279 
280 		for (int i = 0; i < ARRAY_SIZE(type_map); i++) {
281 			if (type_map[i].ztm_type & property->pd_types)  {
282 				len += kmem_scnprintf(buf + len, buflen - len,
283 				    "%s ", type_map[i].ztm_name);
284 			}
285 		}
286 		len += kmem_scnprintf(buf + len, buflen - len, "\n");
287 		return (len);
288 	}
289 
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);
305 			show_str = number;
306 			break;
307 		case PROP_TYPE_STRING:
308 			show_str = property->pd_strdefault ?
309 			    property->pd_strdefault : "";
310 			break;
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) {
315 				show_str = "";
316 			}
317 			break;
318 		default:
319 			return (0);
320 		}
321 	} else {
322 		return (0);
323 	}
324 
325 	return (snprintf(buf, buflen, "%s\n", show_str));
326 }
327 
328 static ssize_t
329 dataset_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
330 {
331 	zfs_prop_t prop = zfs_name_to_prop(kobject_name(kobj));
332 	zprop_desc_t *prop_tbl = zfs_prop_get_table();
333 	ssize_t len;
334 
335 	ASSERT3U(prop, <, ZFS_NUM_PROPS);
336 
337 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
338 
339 	return (len);
340 }
341 
342 static ssize_t
343 vdev_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
344 {
345 	vdev_prop_t prop = vdev_name_to_prop(kobject_name(kobj));
346 	zprop_desc_t *prop_tbl = vdev_prop_get_table();
347 	ssize_t len;
348 
349 	ASSERT3U(prop, <, VDEV_NUM_PROPS);
350 
351 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
352 
353 	return (len);
354 }
355 
356 static ssize_t
357 pool_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
358 {
359 	zpool_prop_t prop = zpool_name_to_prop(kobject_name(kobj));
360 	zprop_desc_t *prop_tbl = zpool_prop_get_table();
361 	ssize_t len;
362 
363 	ASSERT3U(prop, <, ZPOOL_NUM_PROPS);
364 
365 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
366 
367 	return (len);
368 }
369 
370 /*
371  * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
372  *
373  * This list is intended for kernel features that don't have a pool feature
374  * association or that extend existing user kernel interfaces.
375  *
376  * A user process can easily check if the running zfs kernel module
377  * supports the new feature.
378  */
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",
384 };
385 
386 #define	KERNEL_FEATURE_COUNT	ARRAY_SIZE(zfs_kernel_features)
387 
388 static ssize_t
389 kernel_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
390 {
391 	if (strcmp(attr->name, "supported") == 0)
392 		return (snprintf(buf, PAGE_SIZE, "yes\n"));
393 	return (0);
394 }
395 
396 static void
397 kernel_feature_to_kobj(zfs_mod_kobj_t *parent, int slot, const char *name)
398 {
399 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[slot];
400 
401 	ASSERT3U(slot, <, KERNEL_FEATURE_COUNT);
402 	ASSERT(name);
403 
404 	int err = zfs_kobj_init(zfs_kobj, 1, 0, kernel_feature_show);
405 	if (err)
406 		return;
407 
408 	zfs_kobj_add_attr(zfs_kobj, 0, "supported");
409 
410 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
411 	if (err)
412 		zfs_kobj_release(&zfs_kobj->zko_kobj);
413 }
414 
415 static int
416 zfs_kernel_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
417 {
418 	/*
419 	 * Create a parent kobject to host kernel features.
420 	 *
421 	 * '/sys/module/zfs/features.kernel'
422 	 */
423 	int err = zfs_kobj_init(zfs_kobj, 0, KERNEL_FEATURE_COUNT,
424 	    kernel_feature_show);
425 	if (err)
426 		return (err);
427 	err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_KERNEL_FEATURES);
428 	if (err) {
429 		zfs_kobj_release(&zfs_kobj->zko_kobj);
430 		return (err);
431 	}
432 
433 	/*
434 	 * Now create a kobject for each feature.
435 	 *
436 	 * '/sys/module/zfs/features.kernel/<feature>'
437 	 */
438 	for (int f = 0; f < KERNEL_FEATURE_COUNT; f++)
439 		kernel_feature_to_kobj(zfs_kobj, f, zfs_kernel_features[f]);
440 
441 	return (0);
442 }
443 
444 /*
445  * Each pool feature has these common attributes
446  */
447 static const char *const pool_feature_attrs[]  = {
448 	"description",
449 	"guid",
450 	"uname",
451 	"readonly_compatible",
452 	"required_for_mos",
453 	"activate_on_enable",
454 	"per_dataset"
455 };
456 
457 #define	ZPOOL_FEATURE_ATTR_COUNT	ARRAY_SIZE(pool_feature_attrs)
458 
459 /*
460  * Show the content for the given zfs pool feature attribute
461  */
462 static ssize_t
463 pool_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
464 {
465 	spa_feature_t fid;
466 
467 	if (zfeature_lookup_guid(kobject_name(kobj), &fid) != 0)
468 		return (0);
469 
470 	ASSERT3U(fid, <, SPA_FEATURES);
471 
472 	zfeature_flags_t flags = spa_feature_table[fid].fi_flags;
473 	const char *show_str = NULL;
474 
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";
489 	}
490 	if (show_str == NULL)
491 		return (0);
492 
493 	return (snprintf(buf, PAGE_SIZE, "%s\n", show_str));
494 }
495 
496 static void
497 pool_feature_to_kobj(zfs_mod_kobj_t *parent, spa_feature_t fid,
498     const char *name)
499 {
500 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[fid];
501 
502 	ASSERT3U(fid, <, SPA_FEATURES);
503 	ASSERT(name);
504 
505 	int err = zfs_kobj_init(zfs_kobj, ZPOOL_FEATURE_ATTR_COUNT, 0,
506 	    pool_feature_show);
507 	if (err)
508 		return;
509 
510 	for (int i = 0; i < ZPOOL_FEATURE_ATTR_COUNT; i++)
511 		zfs_kobj_add_attr(zfs_kobj, i, pool_feature_attrs[i]);
512 
513 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
514 	if (err)
515 		zfs_kobj_release(&zfs_kobj->zko_kobj);
516 }
517 
518 static int
519 zfs_pool_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
520 {
521 	/*
522 	 * Create a parent kobject to host pool features.
523 	 *
524 	 * '/sys/module/zfs/features.pool'
525 	 */
526 	int err = zfs_kobj_init(zfs_kobj, 0, SPA_FEATURES, pool_feature_show);
527 	if (err)
528 		return (err);
529 	err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_POOL_FEATURES);
530 	if (err) {
531 		zfs_kobj_release(&zfs_kobj->zko_kobj);
532 		return (err);
533 	}
534 
535 	/*
536 	 * Now create a kobject for each feature.
537 	 *
538 	 * '/sys/module/zfs/features.pool/<feature>'
539 	 */
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);
542 
543 	return (0);
544 }
545 
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;
550 	int		p2k_attr_count;
551 } prop_to_kobj_arg_t;
552 
553 static int
554 zprop_to_kobj(int prop, void *args)
555 {
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;
560 	int err;
561 
562 	ASSERT(name);
563 
564 	err = zfs_kobj_init(zfs_kobj, data->p2k_attr_count, 0,
565 	    data->p2k_show_func);
566 	if (err)
567 		return (ZPROP_CONT);
568 
569 	for (int i = 0; i < data->p2k_attr_count; i++)
570 		zfs_kobj_add_attr(zfs_kobj, i, zprop_attrs[i]);
571 
572 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
573 	if (err)
574 		zfs_kobj_release(&zfs_kobj->zko_kobj);
575 
576 	return (ZPROP_CONT);
577 }
578 
579 static int
580 zfs_sysfs_properties_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent,
581     zfs_type_t type)
582 {
583 	prop_to_kobj_arg_t context;
584 	const char *name;
585 	int err;
586 
587 	/*
588 	 * Create a parent kobject to host properties.
589 	 *
590 	 * '/sys/module/zfs/properties.<type>'
591 	 */
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,
599 		    pool_property_show);
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,
607 		    vdev_property_show);
608 	} else {
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);
616 	}
617 
618 	if (err)
619 		return (err);
620 
621 	err = zfs_kobj_add(zfs_kobj, parent, name);
622 	if (err) {
623 		zfs_kobj_release(&zfs_kobj->zko_kobj);
624 		return (err);
625 	}
626 
627 	/*
628 	 * Create a kobject for each property.
629 	 *
630 	 * '/sys/module/zfs/properties.<type>/<property>'
631 	 */
632 	(void) zprop_iter_common(zprop_to_kobj, &context, B_TRUE,
633 	    B_FALSE, type);
634 
635 	return (err);
636 }
637 
638 void
639 zfs_sysfs_init(void)
640 {
641 	struct kobject *parent;
642 #if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
643 	parent = kobject_create_and_add("zfs", fs_kobj);
644 #else
645 	parent = &(((struct module *)(THIS_MODULE))->mkobj).kobj;
646 #endif
647 	int err;
648 
649 	if (parent == NULL)
650 		return;
651 
652 	err = zfs_kernel_features_init(&kernel_features_kobj, parent);
653 	if (err)
654 		return;
655 
656 	err = zfs_pool_features_init(&pool_features_kobj, parent);
657 	if (err) {
658 		zfs_kobj_fini(&kernel_features_kobj);
659 		return;
660 	}
661 
662 	err = zfs_sysfs_properties_init(&pool_props_kobj, parent,
663 	    ZFS_TYPE_POOL);
664 	if (err) {
665 		zfs_kobj_fini(&kernel_features_kobj);
666 		zfs_kobj_fini(&pool_features_kobj);
667 		return;
668 	}
669 
670 	err = zfs_sysfs_properties_init(&vdev_props_kobj, parent,
671 	    ZFS_TYPE_VDEV);
672 	if (err) {
673 		zfs_kobj_fini(&kernel_features_kobj);
674 		zfs_kobj_fini(&pool_features_kobj);
675 		zfs_kobj_fini(&pool_props_kobj);
676 		return;
677 	}
678 
679 	err = zfs_sysfs_properties_init(&dataset_props_kobj, parent,
680 	    ZFS_TYPE_FILESYSTEM);
681 	if (err) {
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);
686 		return;
687 	}
688 }
689 
690 void
691 zfs_sysfs_fini(void)
692 {
693 	/*
694 	 * Remove top-level kobjects; each will remove any children kobjects
695 	 */
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);
701 }
702