xref: /freebsd/sys/contrib/openzfs/module/os/linux/zfs/zfs_sysfs.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 /*
13  * Copyright (c) 2018, 2019 by Delphix. All rights reserved.
14  */
15 
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/zfeature.h>
19 #include <sys/zfs_ioctl.h>
20 #include <sys/zfs_sysfs.h>
21 #include <sys/kmem.h>
22 #include <sys/fs/zfs.h>
23 #include <linux/kobject.h>
24 
25 #include "zfs_prop.h"
26 
27 #if !defined(_KERNEL)
28 #error kernel builds only
29 #endif
30 
31 /*
32  * ZFS Module sysfs support
33  *
34  * This extends our sysfs '/sys/module/zfs' entry to include feature
35  * and property attributes. The primary consumer of this information
36  * is user processes, like the zfs CLI, that need to know what the
37  * current loaded ZFS module supports. The libzfs binary will consult
38  * this information when instantiating the zfs|zpool property tables
39  * and the pool features table.
40  *
41  * The added top-level directories are:
42  * /sys/module/zfs
43  *		├── features.kernel
44  *		├── features.pool
45  *		├── properties.dataset
46  *		└── properties.pool
47  *
48  * The local interface for the zfs kobjects includes:
49  *	zfs_kobj_init()
50  *	zfs_kobj_add()
51  *	zfs_kobj_release()
52  *	zfs_kobj_add_attr()
53  *	zfs_kobj_fini()
54  */
55 
56 /*
57  * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs'
58  */
59 typedef struct zfs_mod_kobj zfs_mod_kobj_t;
60 struct zfs_mod_kobj {
61 	struct kobject		zko_kobj;
62 	struct kobj_type	zko_kobj_type;
63 	struct sysfs_ops	zko_sysfs_ops;
64 	size_t			zko_attr_count;
65 	struct attribute	*zko_attr_list;		/* allocated */
66 	struct attribute_group	zko_default_group;	/* .attrs allocated */
67 	const struct attribute_group	*zko_default_groups[2];
68 	size_t			zko_child_count;
69 	zfs_mod_kobj_t		*zko_children;		/* allocated */
70 };
71 
72 #define	ATTR_TABLE_SIZE(cnt)	(sizeof (struct attribute) * (cnt))
73 /* Note +1 for NULL terminator slot */
74 #define	DEFAULT_ATTR_SIZE(cnt)	(sizeof (struct attribute *) * (cnt + 1))
75 #define	CHILD_TABLE_SIZE(cnt)	(sizeof (zfs_mod_kobj_t) * (cnt))
76 
77 /*
78  * These are the top-level kobjects under '/sys/module/zfs/'
79  */
80 static zfs_mod_kobj_t kernel_features_kobj;
81 static zfs_mod_kobj_t pool_features_kobj;
82 static zfs_mod_kobj_t dataset_props_kobj;
83 static zfs_mod_kobj_t vdev_props_kobj;
84 static zfs_mod_kobj_t pool_props_kobj;
85 
86 /*
87  * The show function is used to provide the content
88  * of an attribute into a PAGE_SIZE buffer.
89  */
90 typedef ssize_t	(*sysfs_show_func)(struct kobject *, struct attribute *,
91     char *);
92 
93 static void
zfs_kobj_fini(zfs_mod_kobj_t * zkobj)94 zfs_kobj_fini(zfs_mod_kobj_t *zkobj)
95 {
96 	/* finalize any child kobjects */
97 	if (zkobj->zko_child_count != 0) {
98 		ASSERT(zkobj->zko_children);
99 		for (int i = 0; i < zkobj->zko_child_count; i++)
100 			zfs_kobj_fini(&zkobj->zko_children[i]);
101 	}
102 
103 	/* kobject_put() will call zfs_kobj_release() to release memory */
104 	kobject_del(&zkobj->zko_kobj);
105 	kobject_put(&zkobj->zko_kobj);
106 }
107 
108 static void
zfs_kobj_release(struct kobject * kobj)109 zfs_kobj_release(struct kobject *kobj)
110 {
111 	zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj);
112 
113 	if (zkobj->zko_attr_list != NULL) {
114 		ASSERT3S(zkobj->zko_attr_count, !=, 0);
115 		kmem_free(zkobj->zko_attr_list,
116 		    ATTR_TABLE_SIZE(zkobj->zko_attr_count));
117 		zkobj->zko_attr_list = NULL;
118 	}
119 
120 	if (zkobj->zko_default_group.attrs != NULL) {
121 		kmem_free(zkobj->zko_default_group.attrs,
122 		    DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
123 		zkobj->zko_default_group.attrs = NULL;
124 	}
125 
126 	if (zkobj->zko_child_count != 0) {
127 		ASSERT(zkobj->zko_children);
128 
129 		kmem_free(zkobj->zko_children,
130 		    CHILD_TABLE_SIZE(zkobj->zko_child_count));
131 		zkobj->zko_child_count = 0;
132 		zkobj->zko_children = NULL;
133 	}
134 
135 	zkobj->zko_attr_count = 0;
136 }
137 
138 #ifndef sysfs_attr_init
139 #define	sysfs_attr_init(attr) do {} while (0)
140 #endif
141 
142 static void
zfs_kobj_add_attr(zfs_mod_kobj_t * zkobj,int attr_num,const char * attr_name)143 zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name)
144 {
145 	VERIFY3U(attr_num, <, zkobj->zko_attr_count);
146 	ASSERT(zkobj->zko_attr_list);
147 	ASSERT(zkobj->zko_default_group.attrs);
148 
149 	zkobj->zko_attr_list[attr_num].name = attr_name;
150 	zkobj->zko_attr_list[attr_num].mode = 0444;
151 	zkobj->zko_default_group.attrs[attr_num] =
152 	    &zkobj->zko_attr_list[attr_num];
153 	sysfs_attr_init(&zkobj->zko_attr_list[attr_num]);
154 }
155 
156 static int
zfs_kobj_init(zfs_mod_kobj_t * zkobj,int attr_cnt,int child_cnt,sysfs_show_func show_func)157 zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
158     sysfs_show_func show_func)
159 {
160 	/*
161 	 * Initialize object's attributes. Count can be zero.
162 	 */
163 	if (attr_cnt > 0) {
164 		zkobj->zko_attr_list = kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt),
165 		    KM_SLEEP);
166 		if (zkobj->zko_attr_list == NULL)
167 			return (ENOMEM);
168 	}
169 	/* this will always have at least one slot for NULL termination */
170 	zkobj->zko_default_group.attrs =
171 	    kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), KM_SLEEP);
172 	if (zkobj->zko_default_group.attrs == NULL) {
173 		if (zkobj->zko_attr_list != NULL) {
174 			kmem_free(zkobj->zko_attr_list,
175 			    ATTR_TABLE_SIZE(attr_cnt));
176 		}
177 		return (ENOMEM);
178 	}
179 	zkobj->zko_attr_count = attr_cnt;
180 	zkobj->zko_default_groups[0] = &zkobj->zko_default_group;
181 #ifdef HAVE_SYSFS_DEFAULT_GROUPS
182 	zkobj->zko_kobj_type.default_groups = zkobj->zko_default_groups;
183 #else
184 	zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_group.attrs;
185 #endif
186 
187 	if (child_cnt > 0) {
188 		zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
189 		    KM_SLEEP);
190 		if (zkobj->zko_children == NULL) {
191 			if (zkobj->zko_default_group.attrs != NULL) {
192 				kmem_free(zkobj->zko_default_group.attrs,
193 				    DEFAULT_ATTR_SIZE(attr_cnt));
194 			}
195 			if (zkobj->zko_attr_list != NULL) {
196 				kmem_free(zkobj->zko_attr_list,
197 				    ATTR_TABLE_SIZE(attr_cnt));
198 			}
199 			return (ENOMEM);
200 		}
201 		zkobj->zko_child_count = child_cnt;
202 	}
203 
204 	zkobj->zko_sysfs_ops.show = show_func;
205 	zkobj->zko_kobj_type.sysfs_ops = &zkobj->zko_sysfs_ops;
206 	zkobj->zko_kobj_type.release = zfs_kobj_release;
207 
208 	return (0);
209 }
210 
211 static int
zfs_kobj_add(zfs_mod_kobj_t * zkobj,struct kobject * parent,const char * name)212 zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name)
213 {
214 	/* zko_default_group.attrs must be NULL terminated */
215 	ASSERT(zkobj->zko_default_group.attrs != NULL);
216 	ASSERT0P(zkobj->zko_default_group.attrs[zkobj->zko_attr_count]);
217 
218 	kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type);
219 	return (kobject_add(&zkobj->zko_kobj, parent, name));
220 }
221 
222 /*
223  * Each zfs property has these common attributes
224  */
225 static const char *const zprop_attrs[]  = {
226 	"type",
227 	"readonly",
228 	"setonce",
229 	"visible",
230 	"values",
231 	"default",
232 	"datasets"	/* zfs properties only */
233 };
234 
235 #define	ZFS_PROP_ATTR_COUNT	ARRAY_SIZE(zprop_attrs)
236 #define	ZPOOL_PROP_ATTR_COUNT	(ZFS_PROP_ATTR_COUNT - 1)
237 
238 static const char *const zprop_types[]  = {
239 	"number",
240 	"string",
241 	"index",
242 };
243 
244 typedef struct zfs_type_map {
245 	zfs_type_t	ztm_type;
246 	const char	*ztm_name;
247 } zfs_type_map_t;
248 
249 static const zfs_type_map_t type_map[] = {
250 	{ZFS_TYPE_FILESYSTEM,	"filesystem"},
251 	{ZFS_TYPE_SNAPSHOT,	"snapshot"},
252 	{ZFS_TYPE_VOLUME,	"volume"},
253 	{ZFS_TYPE_BOOKMARK,	"bookmark"}
254 };
255 
256 /*
257  * Show the content for a zfs property attribute
258  */
259 static ssize_t
zprop_sysfs_show(const char * attr_name,const zprop_desc_t * property,char * buf,size_t buflen)260 zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property,
261     char *buf, size_t buflen)
262 {
263 	const char *show_str;
264 	char number[32];
265 
266 	/* For dataset properties list the dataset types that apply */
267 	if (strcmp(attr_name, "datasets") == 0 &&
268 	    property->pd_types != ZFS_TYPE_POOL) {
269 		int len = 0;
270 
271 		for (int i = 0; i < ARRAY_SIZE(type_map); i++) {
272 			if (type_map[i].ztm_type & property->pd_types)  {
273 				len += kmem_scnprintf(buf + len, buflen - len,
274 				    "%s ", type_map[i].ztm_name);
275 			}
276 		}
277 		len += kmem_scnprintf(buf + len, buflen - len, "\n");
278 		return (len);
279 	}
280 
281 	if (strcmp(attr_name, "type") == 0) {
282 		show_str = zprop_types[property->pd_proptype];
283 	} else if (strcmp(attr_name, "readonly") == 0) {
284 		show_str = property->pd_attr == PROP_READONLY ? "1" : "0";
285 	} else if (strcmp(attr_name, "setonce") == 0) {
286 		show_str = property->pd_attr == PROP_ONETIME ? "1" : "0";
287 	} else if (strcmp(attr_name, "visible") == 0) {
288 		show_str = property->pd_visible ? "1" : "0";
289 	} else if (strcmp(attr_name, "values") == 0) {
290 		show_str = property->pd_values ? property->pd_values : "";
291 	} else if (strcmp(attr_name, "default") == 0) {
292 		switch (property->pd_proptype) {
293 		case PROP_TYPE_NUMBER:
294 			(void) snprintf(number, sizeof (number), "%llu",
295 			    (u_longlong_t)property->pd_numdefault);
296 			show_str = number;
297 			break;
298 		case PROP_TYPE_STRING:
299 			show_str = property->pd_strdefault ?
300 			    property->pd_strdefault : "";
301 			break;
302 		case PROP_TYPE_INDEX:
303 			if (zprop_index_to_string(property->pd_propnum,
304 			    property->pd_numdefault, &show_str,
305 			    property->pd_types) != 0) {
306 				show_str = "";
307 			}
308 			break;
309 		default:
310 			return (0);
311 		}
312 	} else {
313 		return (0);
314 	}
315 
316 	return (snprintf(buf, buflen, "%s\n", show_str));
317 }
318 
319 static ssize_t
dataset_property_show(struct kobject * kobj,struct attribute * attr,char * buf)320 dataset_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
321 {
322 	zfs_prop_t prop = zfs_name_to_prop(kobject_name(kobj));
323 	zprop_desc_t *prop_tbl = zfs_prop_get_table();
324 	ssize_t len;
325 
326 	ASSERT3U(prop, <, ZFS_NUM_PROPS);
327 
328 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
329 
330 	return (len);
331 }
332 
333 static ssize_t
vdev_property_show(struct kobject * kobj,struct attribute * attr,char * buf)334 vdev_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
335 {
336 	vdev_prop_t prop = vdev_name_to_prop(kobject_name(kobj));
337 	zprop_desc_t *prop_tbl = vdev_prop_get_table();
338 	ssize_t len;
339 
340 	ASSERT3U(prop, <, VDEV_NUM_PROPS);
341 
342 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
343 
344 	return (len);
345 }
346 
347 static ssize_t
pool_property_show(struct kobject * kobj,struct attribute * attr,char * buf)348 pool_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
349 {
350 	zpool_prop_t prop = zpool_name_to_prop(kobject_name(kobj));
351 	zprop_desc_t *prop_tbl = zpool_prop_get_table();
352 	ssize_t len;
353 
354 	ASSERT3U(prop, <, ZPOOL_NUM_PROPS);
355 
356 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
357 
358 	return (len);
359 }
360 
361 /*
362  * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
363  *
364  * This list is intended for kernel features that don't have a pool feature
365  * association or that extend existing user kernel interfaces.
366  *
367  * A user process can easily check if the running zfs kernel module
368  * supports the new feature.
369  */
370 static const char *const zfs_kernel_features[] = {
371 	/* --> Add new kernel features here */
372 	"com.delphix:vdev_initialize",
373 	"org.zfsonlinux:vdev_trim",
374 	"org.openzfs:l2arc_persistent",
375 };
376 
377 #define	KERNEL_FEATURE_COUNT	ARRAY_SIZE(zfs_kernel_features)
378 
379 static ssize_t
kernel_feature_show(struct kobject * kobj,struct attribute * attr,char * buf)380 kernel_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
381 {
382 	if (strcmp(attr->name, "supported") == 0)
383 		return (snprintf(buf, PAGE_SIZE, "yes\n"));
384 	return (0);
385 }
386 
387 static void
kernel_feature_to_kobj(zfs_mod_kobj_t * parent,int slot,const char * name)388 kernel_feature_to_kobj(zfs_mod_kobj_t *parent, int slot, const char *name)
389 {
390 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[slot];
391 
392 	ASSERT3U(slot, <, KERNEL_FEATURE_COUNT);
393 	ASSERT(name);
394 
395 	int err = zfs_kobj_init(zfs_kobj, 1, 0, kernel_feature_show);
396 	if (err)
397 		return;
398 
399 	zfs_kobj_add_attr(zfs_kobj, 0, "supported");
400 
401 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
402 	if (err)
403 		zfs_kobj_release(&zfs_kobj->zko_kobj);
404 }
405 
406 static int
zfs_kernel_features_init(zfs_mod_kobj_t * zfs_kobj,struct kobject * parent)407 zfs_kernel_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
408 {
409 	/*
410 	 * Create a parent kobject to host kernel features.
411 	 *
412 	 * '/sys/module/zfs/features.kernel'
413 	 */
414 	int err = zfs_kobj_init(zfs_kobj, 0, KERNEL_FEATURE_COUNT,
415 	    kernel_feature_show);
416 	if (err)
417 		return (err);
418 	err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_KERNEL_FEATURES);
419 	if (err) {
420 		zfs_kobj_release(&zfs_kobj->zko_kobj);
421 		return (err);
422 	}
423 
424 	/*
425 	 * Now create a kobject for each feature.
426 	 *
427 	 * '/sys/module/zfs/features.kernel/<feature>'
428 	 */
429 	for (int f = 0; f < KERNEL_FEATURE_COUNT; f++)
430 		kernel_feature_to_kobj(zfs_kobj, f, zfs_kernel_features[f]);
431 
432 	return (0);
433 }
434 
435 /*
436  * Each pool feature has these common attributes
437  */
438 static const char *const pool_feature_attrs[]  = {
439 	"description",
440 	"guid",
441 	"uname",
442 	"readonly_compatible",
443 	"required_for_mos",
444 	"activate_on_enable",
445 	"per_dataset"
446 };
447 
448 #define	ZPOOL_FEATURE_ATTR_COUNT	ARRAY_SIZE(pool_feature_attrs)
449 
450 /*
451  * Show the content for the given zfs pool feature attribute
452  */
453 static ssize_t
pool_feature_show(struct kobject * kobj,struct attribute * attr,char * buf)454 pool_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
455 {
456 	spa_feature_t fid;
457 
458 	if (zfeature_lookup_guid(kobject_name(kobj), &fid) != 0)
459 		return (0);
460 
461 	ASSERT3U(fid, <, SPA_FEATURES);
462 
463 	zfeature_flags_t flags = spa_feature_table[fid].fi_flags;
464 	const char *show_str = NULL;
465 
466 	if (strcmp(attr->name, "description") == 0) {
467 		show_str = spa_feature_table[fid].fi_desc;
468 	} else if (strcmp(attr->name, "guid") == 0) {
469 		show_str = spa_feature_table[fid].fi_guid;
470 	} else if (strcmp(attr->name, "uname") == 0) {
471 		show_str = spa_feature_table[fid].fi_uname;
472 	} else if (strcmp(attr->name, "readonly_compatible") == 0) {
473 		show_str = flags & ZFEATURE_FLAG_READONLY_COMPAT ? "1" : "0";
474 	} else if (strcmp(attr->name, "required_for_mos") == 0) {
475 		show_str = flags & ZFEATURE_FLAG_MOS ? "1" : "0";
476 	} else if (strcmp(attr->name, "activate_on_enable") == 0) {
477 		show_str = flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE ? "1" : "0";
478 	} else if (strcmp(attr->name, "per_dataset") == 0) {
479 		show_str = flags & ZFEATURE_FLAG_PER_DATASET ? "1" : "0";
480 	}
481 	if (show_str == NULL)
482 		return (0);
483 
484 	return (snprintf(buf, PAGE_SIZE, "%s\n", show_str));
485 }
486 
487 static void
pool_feature_to_kobj(zfs_mod_kobj_t * parent,spa_feature_t fid,const char * name)488 pool_feature_to_kobj(zfs_mod_kobj_t *parent, spa_feature_t fid,
489     const char *name)
490 {
491 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[fid];
492 
493 	ASSERT3U(fid, <, SPA_FEATURES);
494 	ASSERT(name);
495 
496 	int err = zfs_kobj_init(zfs_kobj, ZPOOL_FEATURE_ATTR_COUNT, 0,
497 	    pool_feature_show);
498 	if (err)
499 		return;
500 
501 	for (int i = 0; i < ZPOOL_FEATURE_ATTR_COUNT; i++)
502 		zfs_kobj_add_attr(zfs_kobj, i, pool_feature_attrs[i]);
503 
504 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
505 	if (err)
506 		zfs_kobj_release(&zfs_kobj->zko_kobj);
507 }
508 
509 static int
zfs_pool_features_init(zfs_mod_kobj_t * zfs_kobj,struct kobject * parent)510 zfs_pool_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
511 {
512 	/*
513 	 * Create a parent kobject to host pool features.
514 	 *
515 	 * '/sys/module/zfs/features.pool'
516 	 */
517 	int err = zfs_kobj_init(zfs_kobj, 0, SPA_FEATURES, pool_feature_show);
518 	if (err)
519 		return (err);
520 	err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_POOL_FEATURES);
521 	if (err) {
522 		zfs_kobj_release(&zfs_kobj->zko_kobj);
523 		return (err);
524 	}
525 
526 	/*
527 	 * Now create a kobject for each feature.
528 	 *
529 	 * '/sys/module/zfs/features.pool/<feature>'
530 	 */
531 	for (spa_feature_t i = 0; i < SPA_FEATURES; i++)
532 		pool_feature_to_kobj(zfs_kobj, i, spa_feature_table[i].fi_guid);
533 
534 	return (0);
535 }
536 
537 typedef struct prop_to_kobj_arg {
538 	zprop_desc_t	*p2k_table;
539 	zfs_mod_kobj_t	*p2k_parent;
540 	sysfs_show_func	p2k_show_func;
541 	int		p2k_attr_count;
542 } prop_to_kobj_arg_t;
543 
544 static int
zprop_to_kobj(int prop,void * args)545 zprop_to_kobj(int prop, void *args)
546 {
547 	prop_to_kobj_arg_t *data = args;
548 	zfs_mod_kobj_t *parent = data->p2k_parent;
549 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[prop];
550 	const char *name = data->p2k_table[prop].pd_name;
551 	int err;
552 
553 	ASSERT(name);
554 
555 	err = zfs_kobj_init(zfs_kobj, data->p2k_attr_count, 0,
556 	    data->p2k_show_func);
557 	if (err)
558 		return (ZPROP_CONT);
559 
560 	for (int i = 0; i < data->p2k_attr_count; i++)
561 		zfs_kobj_add_attr(zfs_kobj, i, zprop_attrs[i]);
562 
563 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
564 	if (err)
565 		zfs_kobj_release(&zfs_kobj->zko_kobj);
566 
567 	return (ZPROP_CONT);
568 }
569 
570 static int
zfs_sysfs_properties_init(zfs_mod_kobj_t * zfs_kobj,struct kobject * parent,zfs_type_t type)571 zfs_sysfs_properties_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent,
572     zfs_type_t type)
573 {
574 	prop_to_kobj_arg_t context;
575 	const char *name;
576 	int err;
577 
578 	/*
579 	 * Create a parent kobject to host properties.
580 	 *
581 	 * '/sys/module/zfs/properties.<type>'
582 	 */
583 	if (type == ZFS_TYPE_POOL) {
584 		name = ZFS_SYSFS_POOL_PROPERTIES;
585 		context.p2k_table = zpool_prop_get_table();
586 		context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
587 		context.p2k_parent = zfs_kobj;
588 		context.p2k_show_func = pool_property_show;
589 		err = zfs_kobj_init(zfs_kobj, 0, ZPOOL_NUM_PROPS,
590 		    pool_property_show);
591 	} else if (type == ZFS_TYPE_VDEV) {
592 		name = ZFS_SYSFS_VDEV_PROPERTIES;
593 		context.p2k_table = vdev_prop_get_table();
594 		context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
595 		context.p2k_parent = zfs_kobj;
596 		context.p2k_show_func = vdev_property_show;
597 		err = zfs_kobj_init(zfs_kobj, 0, VDEV_NUM_PROPS,
598 		    vdev_property_show);
599 	} else {
600 		name = ZFS_SYSFS_DATASET_PROPERTIES;
601 		context.p2k_table = zfs_prop_get_table();
602 		context.p2k_attr_count = ZFS_PROP_ATTR_COUNT;
603 		context.p2k_parent = zfs_kobj;
604 		context.p2k_show_func = dataset_property_show;
605 		err = zfs_kobj_init(zfs_kobj, 0, ZFS_NUM_PROPS,
606 		    dataset_property_show);
607 	}
608 
609 	if (err)
610 		return (err);
611 
612 	err = zfs_kobj_add(zfs_kobj, parent, name);
613 	if (err) {
614 		zfs_kobj_release(&zfs_kobj->zko_kobj);
615 		return (err);
616 	}
617 
618 	/*
619 	 * Create a kobject for each property.
620 	 *
621 	 * '/sys/module/zfs/properties.<type>/<property>'
622 	 */
623 	(void) zprop_iter_common(zprop_to_kobj, &context, B_TRUE,
624 	    B_FALSE, type);
625 
626 	return (err);
627 }
628 
629 void
zfs_sysfs_init(void)630 zfs_sysfs_init(void)
631 {
632 	struct kobject *parent;
633 #if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
634 	parent = kobject_create_and_add("zfs", fs_kobj);
635 #else
636 	parent = &(((struct module *)(THIS_MODULE))->mkobj).kobj;
637 #endif
638 	int err;
639 
640 	if (parent == NULL)
641 		return;
642 
643 	err = zfs_kernel_features_init(&kernel_features_kobj, parent);
644 	if (err)
645 		return;
646 
647 	err = zfs_pool_features_init(&pool_features_kobj, parent);
648 	if (err) {
649 		zfs_kobj_fini(&kernel_features_kobj);
650 		return;
651 	}
652 
653 	err = zfs_sysfs_properties_init(&pool_props_kobj, parent,
654 	    ZFS_TYPE_POOL);
655 	if (err) {
656 		zfs_kobj_fini(&kernel_features_kobj);
657 		zfs_kobj_fini(&pool_features_kobj);
658 		return;
659 	}
660 
661 	err = zfs_sysfs_properties_init(&vdev_props_kobj, parent,
662 	    ZFS_TYPE_VDEV);
663 	if (err) {
664 		zfs_kobj_fini(&kernel_features_kobj);
665 		zfs_kobj_fini(&pool_features_kobj);
666 		zfs_kobj_fini(&pool_props_kobj);
667 		return;
668 	}
669 
670 	err = zfs_sysfs_properties_init(&dataset_props_kobj, parent,
671 	    ZFS_TYPE_FILESYSTEM);
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 		zfs_kobj_fini(&vdev_props_kobj);
677 		return;
678 	}
679 }
680 
681 void
zfs_sysfs_fini(void)682 zfs_sysfs_fini(void)
683 {
684 	/*
685 	 * Remove top-level kobjects; each will remove any children kobjects
686 	 */
687 	zfs_kobj_fini(&kernel_features_kobj);
688 	zfs_kobj_fini(&pool_features_kobj);
689 	zfs_kobj_fini(&pool_props_kobj);
690 	zfs_kobj_fini(&vdev_props_kobj);
691 	zfs_kobj_fini(&dataset_props_kobj);
692 }
693