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
zfs_kobj_fini(zfs_mod_kobj_t * zkobj)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 	/*
114 	 * Special case note:
115 	 *
116 	 * We have to check for 'zkobj->zko_kobj.name != NULL' as
117 	 * a workaround for #16249 which was added to zfs-2.2.4
118 	 * and fixed (with this change) in zfs-2.2.5.
119 	 */
120 	if (zkobj->zko_kobj.name != NULL) {
121 		kobject_del(&zkobj->zko_kobj);
122 		kobject_put(&zkobj->zko_kobj);
123 	}
124 }
125 
126 static void
zfs_kobj_release(struct kobject * kobj)127 zfs_kobj_release(struct kobject *kobj)
128 {
129 	zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj);
130 
131 	if (zkobj->zko_attr_list != NULL) {
132 		ASSERT3S(zkobj->zko_attr_count, !=, 0);
133 		kmem_free(zkobj->zko_attr_list,
134 		    ATTR_TABLE_SIZE(zkobj->zko_attr_count));
135 		zkobj->zko_attr_list = NULL;
136 	}
137 
138 	if (zkobj->zko_default_group.attrs != NULL) {
139 		kmem_free(zkobj->zko_default_group.attrs,
140 		    DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
141 		zkobj->zko_default_group.attrs = NULL;
142 	}
143 
144 	if (zkobj->zko_child_count != 0) {
145 		ASSERT(zkobj->zko_children);
146 
147 		kmem_free(zkobj->zko_children,
148 		    CHILD_TABLE_SIZE(zkobj->zko_child_count));
149 		zkobj->zko_child_count = 0;
150 		zkobj->zko_children = NULL;
151 	}
152 
153 	zkobj->zko_attr_count = 0;
154 }
155 
156 #ifndef sysfs_attr_init
157 #define	sysfs_attr_init(attr) do {} while (0)
158 #endif
159 
160 static void
zfs_kobj_add_attr(zfs_mod_kobj_t * zkobj,int attr_num,const char * attr_name)161 zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name)
162 {
163 	VERIFY3U(attr_num, <, zkobj->zko_attr_count);
164 	ASSERT(zkobj->zko_attr_list);
165 	ASSERT(zkobj->zko_default_group.attrs);
166 
167 	zkobj->zko_attr_list[attr_num].name = attr_name;
168 	zkobj->zko_attr_list[attr_num].mode = 0444;
169 	zkobj->zko_default_group.attrs[attr_num] =
170 	    &zkobj->zko_attr_list[attr_num];
171 	sysfs_attr_init(&zkobj->zko_attr_list[attr_num]);
172 }
173 
174 static int
zfs_kobj_init(zfs_mod_kobj_t * zkobj,int attr_cnt,int child_cnt,sysfs_show_func show_func)175 zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
176     sysfs_show_func show_func)
177 {
178 	/*
179 	 * Initialize object's attributes. Count can be zero.
180 	 */
181 	if (attr_cnt > 0) {
182 		zkobj->zko_attr_list = kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt),
183 		    KM_SLEEP);
184 		if (zkobj->zko_attr_list == NULL)
185 			return (ENOMEM);
186 	}
187 	/* this will always have at least one slot for NULL termination */
188 	zkobj->zko_default_group.attrs =
189 	    kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), KM_SLEEP);
190 	if (zkobj->zko_default_group.attrs == NULL) {
191 		if (zkobj->zko_attr_list != NULL) {
192 			kmem_free(zkobj->zko_attr_list,
193 			    ATTR_TABLE_SIZE(attr_cnt));
194 		}
195 		return (ENOMEM);
196 	}
197 	zkobj->zko_attr_count = attr_cnt;
198 	zkobj->zko_default_groups[0] = &zkobj->zko_default_group;
199 #ifdef HAVE_SYSFS_DEFAULT_GROUPS
200 	zkobj->zko_kobj_type.default_groups = zkobj->zko_default_groups;
201 #else
202 	zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_group.attrs;
203 #endif
204 
205 	if (child_cnt > 0) {
206 		zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
207 		    KM_SLEEP);
208 		if (zkobj->zko_children == NULL) {
209 			if (zkobj->zko_default_group.attrs != NULL) {
210 				kmem_free(zkobj->zko_default_group.attrs,
211 				    DEFAULT_ATTR_SIZE(attr_cnt));
212 			}
213 			if (zkobj->zko_attr_list != NULL) {
214 				kmem_free(zkobj->zko_attr_list,
215 				    ATTR_TABLE_SIZE(attr_cnt));
216 			}
217 			return (ENOMEM);
218 		}
219 		zkobj->zko_child_count = child_cnt;
220 	}
221 
222 	zkobj->zko_sysfs_ops.show = show_func;
223 	zkobj->zko_kobj_type.sysfs_ops = &zkobj->zko_sysfs_ops;
224 	zkobj->zko_kobj_type.release = zfs_kobj_release;
225 
226 	return (0);
227 }
228 
229 static int
zfs_kobj_add(zfs_mod_kobj_t * zkobj,struct kobject * parent,const char * name)230 zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name)
231 {
232 	/* zko_default_group.attrs must be NULL terminated */
233 	ASSERT(zkobj->zko_default_group.attrs != NULL);
234 	ASSERT(zkobj->zko_default_group.attrs[zkobj->zko_attr_count] == NULL);
235 
236 	kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type);
237 	return (kobject_add(&zkobj->zko_kobj, parent, name));
238 }
239 
240 /*
241  * Each zfs property has these common attributes
242  */
243 static const char *const zprop_attrs[]  = {
244 	"type",
245 	"readonly",
246 	"setonce",
247 	"visible",
248 	"values",
249 	"default",
250 	"datasets"	/* zfs properties only */
251 };
252 
253 #define	ZFS_PROP_ATTR_COUNT	ARRAY_SIZE(zprop_attrs)
254 #define	ZPOOL_PROP_ATTR_COUNT	(ZFS_PROP_ATTR_COUNT - 1)
255 
256 static const char *const zprop_types[]  = {
257 	"number",
258 	"string",
259 	"index",
260 };
261 
262 typedef struct zfs_type_map {
263 	zfs_type_t	ztm_type;
264 	const char	*ztm_name;
265 } zfs_type_map_t;
266 
267 static const zfs_type_map_t type_map[] = {
268 	{ZFS_TYPE_FILESYSTEM,	"filesystem"},
269 	{ZFS_TYPE_SNAPSHOT,	"snapshot"},
270 	{ZFS_TYPE_VOLUME,	"volume"},
271 	{ZFS_TYPE_BOOKMARK,	"bookmark"}
272 };
273 
274 /*
275  * Show the content for a zfs property attribute
276  */
277 static ssize_t
zprop_sysfs_show(const char * attr_name,const zprop_desc_t * property,char * buf,size_t buflen)278 zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property,
279     char *buf, size_t buflen)
280 {
281 	const char *show_str;
282 	char number[32];
283 
284 	/* For dataset properties list the dataset types that apply */
285 	if (strcmp(attr_name, "datasets") == 0 &&
286 	    property->pd_types != ZFS_TYPE_POOL) {
287 		int len = 0;
288 
289 		for (int i = 0; i < ARRAY_SIZE(type_map); i++) {
290 			if (type_map[i].ztm_type & property->pd_types)  {
291 				len += kmem_scnprintf(buf + len, buflen - len,
292 				    "%s ", type_map[i].ztm_name);
293 			}
294 		}
295 		len += kmem_scnprintf(buf + len, buflen - len, "\n");
296 		return (len);
297 	}
298 
299 	if (strcmp(attr_name, "type") == 0) {
300 		show_str = zprop_types[property->pd_proptype];
301 	} else if (strcmp(attr_name, "readonly") == 0) {
302 		show_str = property->pd_attr == PROP_READONLY ? "1" : "0";
303 	} else if (strcmp(attr_name, "setonce") == 0) {
304 		show_str = property->pd_attr == PROP_ONETIME ? "1" : "0";
305 	} else if (strcmp(attr_name, "visible") == 0) {
306 		show_str = property->pd_visible ? "1" : "0";
307 	} else if (strcmp(attr_name, "values") == 0) {
308 		show_str = property->pd_values ? property->pd_values : "";
309 	} else if (strcmp(attr_name, "default") == 0) {
310 		switch (property->pd_proptype) {
311 		case PROP_TYPE_NUMBER:
312 			(void) snprintf(number, sizeof (number), "%llu",
313 			    (u_longlong_t)property->pd_numdefault);
314 			show_str = number;
315 			break;
316 		case PROP_TYPE_STRING:
317 			show_str = property->pd_strdefault ?
318 			    property->pd_strdefault : "";
319 			break;
320 		case PROP_TYPE_INDEX:
321 			if (zprop_index_to_string(property->pd_propnum,
322 			    property->pd_numdefault, &show_str,
323 			    property->pd_types) != 0) {
324 				show_str = "";
325 			}
326 			break;
327 		default:
328 			return (0);
329 		}
330 	} else {
331 		return (0);
332 	}
333 
334 	return (snprintf(buf, buflen, "%s\n", show_str));
335 }
336 
337 static ssize_t
dataset_property_show(struct kobject * kobj,struct attribute * attr,char * buf)338 dataset_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
339 {
340 	zfs_prop_t prop = zfs_name_to_prop(kobject_name(kobj));
341 	zprop_desc_t *prop_tbl = zfs_prop_get_table();
342 	ssize_t len;
343 
344 	ASSERT3U(prop, <, ZFS_NUM_PROPS);
345 
346 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
347 
348 	return (len);
349 }
350 
351 static ssize_t
vdev_property_show(struct kobject * kobj,struct attribute * attr,char * buf)352 vdev_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
353 {
354 	vdev_prop_t prop = vdev_name_to_prop(kobject_name(kobj));
355 	zprop_desc_t *prop_tbl = vdev_prop_get_table();
356 	ssize_t len;
357 
358 	ASSERT3U(prop, <, VDEV_NUM_PROPS);
359 
360 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
361 
362 	return (len);
363 }
364 
365 static ssize_t
pool_property_show(struct kobject * kobj,struct attribute * attr,char * buf)366 pool_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
367 {
368 	zpool_prop_t prop = zpool_name_to_prop(kobject_name(kobj));
369 	zprop_desc_t *prop_tbl = zpool_prop_get_table();
370 	ssize_t len;
371 
372 	ASSERT3U(prop, <, ZPOOL_NUM_PROPS);
373 
374 	len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
375 
376 	return (len);
377 }
378 
379 /*
380  * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
381  *
382  * This list is intended for kernel features that don't have a pool feature
383  * association or that extend existing user kernel interfaces.
384  *
385  * A user process can easily check if the running zfs kernel module
386  * supports the new feature.
387  */
388 static const char *const zfs_kernel_features[] = {
389 	/* --> Add new kernel features here */
390 	"com.delphix:vdev_initialize",
391 	"org.zfsonlinux:vdev_trim",
392 	"org.openzfs:l2arc_persistent",
393 };
394 
395 #define	KERNEL_FEATURE_COUNT	ARRAY_SIZE(zfs_kernel_features)
396 
397 static ssize_t
kernel_feature_show(struct kobject * kobj,struct attribute * attr,char * buf)398 kernel_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
399 {
400 	if (strcmp(attr->name, "supported") == 0)
401 		return (snprintf(buf, PAGE_SIZE, "yes\n"));
402 	return (0);
403 }
404 
405 static void
kernel_feature_to_kobj(zfs_mod_kobj_t * parent,int slot,const char * name)406 kernel_feature_to_kobj(zfs_mod_kobj_t *parent, int slot, const char *name)
407 {
408 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[slot];
409 
410 	ASSERT3U(slot, <, KERNEL_FEATURE_COUNT);
411 	ASSERT(name);
412 
413 	int err = zfs_kobj_init(zfs_kobj, 1, 0, kernel_feature_show);
414 	if (err)
415 		return;
416 
417 	zfs_kobj_add_attr(zfs_kobj, 0, "supported");
418 
419 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
420 	if (err)
421 		zfs_kobj_release(&zfs_kobj->zko_kobj);
422 }
423 
424 static int
zfs_kernel_features_init(zfs_mod_kobj_t * zfs_kobj,struct kobject * parent)425 zfs_kernel_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
426 {
427 	/*
428 	 * Create a parent kobject to host kernel features.
429 	 *
430 	 * '/sys/module/zfs/features.kernel'
431 	 */
432 	int err = zfs_kobj_init(zfs_kobj, 0, KERNEL_FEATURE_COUNT,
433 	    kernel_feature_show);
434 	if (err)
435 		return (err);
436 	err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_KERNEL_FEATURES);
437 	if (err) {
438 		zfs_kobj_release(&zfs_kobj->zko_kobj);
439 		return (err);
440 	}
441 
442 	/*
443 	 * Now create a kobject for each feature.
444 	 *
445 	 * '/sys/module/zfs/features.kernel/<feature>'
446 	 */
447 	for (int f = 0; f < KERNEL_FEATURE_COUNT; f++)
448 		kernel_feature_to_kobj(zfs_kobj, f, zfs_kernel_features[f]);
449 
450 	return (0);
451 }
452 
453 /*
454  * Each pool feature has these common attributes
455  */
456 static const char *const pool_feature_attrs[]  = {
457 	"description",
458 	"guid",
459 	"uname",
460 	"readonly_compatible",
461 	"required_for_mos",
462 	"activate_on_enable",
463 	"per_dataset"
464 };
465 
466 #define	ZPOOL_FEATURE_ATTR_COUNT	ARRAY_SIZE(pool_feature_attrs)
467 
468 /*
469  * Show the content for the given zfs pool feature attribute
470  */
471 static ssize_t
pool_feature_show(struct kobject * kobj,struct attribute * attr,char * buf)472 pool_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
473 {
474 	spa_feature_t fid;
475 
476 	if (zfeature_lookup_guid(kobject_name(kobj), &fid) != 0)
477 		return (0);
478 
479 	ASSERT3U(fid, <, SPA_FEATURES);
480 
481 	zfeature_flags_t flags = spa_feature_table[fid].fi_flags;
482 	const char *show_str = NULL;
483 
484 	if (strcmp(attr->name, "description") == 0) {
485 		show_str = spa_feature_table[fid].fi_desc;
486 	} else if (strcmp(attr->name, "guid") == 0) {
487 		show_str = spa_feature_table[fid].fi_guid;
488 	} else if (strcmp(attr->name, "uname") == 0) {
489 		show_str = spa_feature_table[fid].fi_uname;
490 	} else if (strcmp(attr->name, "readonly_compatible") == 0) {
491 		show_str = flags & ZFEATURE_FLAG_READONLY_COMPAT ? "1" : "0";
492 	} else if (strcmp(attr->name, "required_for_mos") == 0) {
493 		show_str = flags & ZFEATURE_FLAG_MOS ? "1" : "0";
494 	} else if (strcmp(attr->name, "activate_on_enable") == 0) {
495 		show_str = flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE ? "1" : "0";
496 	} else if (strcmp(attr->name, "per_dataset") == 0) {
497 		show_str = flags & ZFEATURE_FLAG_PER_DATASET ? "1" : "0";
498 	}
499 	if (show_str == NULL)
500 		return (0);
501 
502 	return (snprintf(buf, PAGE_SIZE, "%s\n", show_str));
503 }
504 
505 static void
pool_feature_to_kobj(zfs_mod_kobj_t * parent,spa_feature_t fid,const char * name)506 pool_feature_to_kobj(zfs_mod_kobj_t *parent, spa_feature_t fid,
507     const char *name)
508 {
509 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[fid];
510 
511 	ASSERT3U(fid, <, SPA_FEATURES);
512 	ASSERT(name);
513 
514 	int err = zfs_kobj_init(zfs_kobj, ZPOOL_FEATURE_ATTR_COUNT, 0,
515 	    pool_feature_show);
516 	if (err)
517 		return;
518 
519 	for (int i = 0; i < ZPOOL_FEATURE_ATTR_COUNT; i++)
520 		zfs_kobj_add_attr(zfs_kobj, i, pool_feature_attrs[i]);
521 
522 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
523 	if (err)
524 		zfs_kobj_release(&zfs_kobj->zko_kobj);
525 }
526 
527 static int
zfs_pool_features_init(zfs_mod_kobj_t * zfs_kobj,struct kobject * parent)528 zfs_pool_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
529 {
530 	/*
531 	 * Create a parent kobject to host pool features.
532 	 *
533 	 * '/sys/module/zfs/features.pool'
534 	 */
535 	int err = zfs_kobj_init(zfs_kobj, 0, SPA_FEATURES, pool_feature_show);
536 	if (err)
537 		return (err);
538 	err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_POOL_FEATURES);
539 	if (err) {
540 		zfs_kobj_release(&zfs_kobj->zko_kobj);
541 		return (err);
542 	}
543 
544 	/*
545 	 * Now create a kobject for each feature.
546 	 *
547 	 * '/sys/module/zfs/features.pool/<feature>'
548 	 */
549 	for (spa_feature_t i = 0; i < SPA_FEATURES; i++)
550 		pool_feature_to_kobj(zfs_kobj, i, spa_feature_table[i].fi_guid);
551 
552 	return (0);
553 }
554 
555 typedef struct prop_to_kobj_arg {
556 	zprop_desc_t	*p2k_table;
557 	zfs_mod_kobj_t	*p2k_parent;
558 	sysfs_show_func	p2k_show_func;
559 	int		p2k_attr_count;
560 } prop_to_kobj_arg_t;
561 
562 static int
zprop_to_kobj(int prop,void * args)563 zprop_to_kobj(int prop, void *args)
564 {
565 	prop_to_kobj_arg_t *data = args;
566 	zfs_mod_kobj_t *parent = data->p2k_parent;
567 	zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[prop];
568 	const char *name = data->p2k_table[prop].pd_name;
569 	int err;
570 
571 	ASSERT(name);
572 
573 	err = zfs_kobj_init(zfs_kobj, data->p2k_attr_count, 0,
574 	    data->p2k_show_func);
575 	if (err)
576 		return (ZPROP_CONT);
577 
578 	for (int i = 0; i < data->p2k_attr_count; i++)
579 		zfs_kobj_add_attr(zfs_kobj, i, zprop_attrs[i]);
580 
581 	err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
582 	if (err)
583 		zfs_kobj_release(&zfs_kobj->zko_kobj);
584 
585 	return (ZPROP_CONT);
586 }
587 
588 static int
zfs_sysfs_properties_init(zfs_mod_kobj_t * zfs_kobj,struct kobject * parent,zfs_type_t type)589 zfs_sysfs_properties_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent,
590     zfs_type_t type)
591 {
592 	prop_to_kobj_arg_t context;
593 	const char *name;
594 	int err;
595 
596 	/*
597 	 * Create a parent kobject to host properties.
598 	 *
599 	 * '/sys/module/zfs/properties.<type>'
600 	 */
601 	if (type == ZFS_TYPE_POOL) {
602 		name = ZFS_SYSFS_POOL_PROPERTIES;
603 		context.p2k_table = zpool_prop_get_table();
604 		context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
605 		context.p2k_parent = zfs_kobj;
606 		context.p2k_show_func = pool_property_show;
607 		err = zfs_kobj_init(zfs_kobj, 0, ZPOOL_NUM_PROPS,
608 		    pool_property_show);
609 	} else if (type == ZFS_TYPE_VDEV) {
610 		name = ZFS_SYSFS_VDEV_PROPERTIES;
611 		context.p2k_table = vdev_prop_get_table();
612 		context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
613 		context.p2k_parent = zfs_kobj;
614 		context.p2k_show_func = vdev_property_show;
615 		err = zfs_kobj_init(zfs_kobj, 0, VDEV_NUM_PROPS,
616 		    vdev_property_show);
617 	} else {
618 		name = ZFS_SYSFS_DATASET_PROPERTIES;
619 		context.p2k_table = zfs_prop_get_table();
620 		context.p2k_attr_count = ZFS_PROP_ATTR_COUNT;
621 		context.p2k_parent = zfs_kobj;
622 		context.p2k_show_func = dataset_property_show;
623 		err = zfs_kobj_init(zfs_kobj, 0, ZFS_NUM_PROPS,
624 		    dataset_property_show);
625 	}
626 
627 	if (err)
628 		return (err);
629 
630 	err = zfs_kobj_add(zfs_kobj, parent, name);
631 	if (err) {
632 		zfs_kobj_release(&zfs_kobj->zko_kobj);
633 		return (err);
634 	}
635 
636 	/*
637 	 * Create a kobject for each property.
638 	 *
639 	 * '/sys/module/zfs/properties.<type>/<property>'
640 	 */
641 	(void) zprop_iter_common(zprop_to_kobj, &context, B_TRUE,
642 	    B_FALSE, type);
643 
644 	return (err);
645 }
646 
647 void
zfs_sysfs_init(void)648 zfs_sysfs_init(void)
649 {
650 	struct kobject *parent;
651 #if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
652 	parent = kobject_create_and_add("zfs", fs_kobj);
653 #else
654 	parent = &(((struct module *)(THIS_MODULE))->mkobj).kobj;
655 #endif
656 	int err;
657 
658 	if (parent == NULL)
659 		return;
660 
661 	err = zfs_kernel_features_init(&kernel_features_kobj, parent);
662 	if (err)
663 		return;
664 
665 	err = zfs_pool_features_init(&pool_features_kobj, parent);
666 	if (err) {
667 		zfs_kobj_fini(&kernel_features_kobj);
668 		return;
669 	}
670 
671 	err = zfs_sysfs_properties_init(&pool_props_kobj, parent,
672 	    ZFS_TYPE_POOL);
673 	if (err) {
674 		zfs_kobj_fini(&kernel_features_kobj);
675 		zfs_kobj_fini(&pool_features_kobj);
676 		return;
677 	}
678 
679 	err = zfs_sysfs_properties_init(&vdev_props_kobj, parent,
680 	    ZFS_TYPE_VDEV);
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 		return;
686 	}
687 
688 	err = zfs_sysfs_properties_init(&dataset_props_kobj, parent,
689 	    ZFS_TYPE_FILESYSTEM);
690 	if (err) {
691 		zfs_kobj_fini(&kernel_features_kobj);
692 		zfs_kobj_fini(&pool_features_kobj);
693 		zfs_kobj_fini(&pool_props_kobj);
694 		zfs_kobj_fini(&vdev_props_kobj);
695 		return;
696 	}
697 }
698 
699 void
zfs_sysfs_fini(void)700 zfs_sysfs_fini(void)
701 {
702 	/*
703 	 * Remove top-level kobjects; each will remove any children kobjects
704 	 */
705 	zfs_kobj_fini(&kernel_features_kobj);
706 	zfs_kobj_fini(&pool_features_kobj);
707 	zfs_kobj_fini(&pool_props_kobj);
708 	zfs_kobj_fini(&vdev_props_kobj);
709 	zfs_kobj_fini(&dataset_props_kobj);
710 }
711