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