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