]> git.proxmox.com Git - mirror_zfs.git/blame - module/zfs/zfs_sysfs.c
Fix ENXIO from spa_ld_verify_logs() in ztest
[mirror_zfs.git] / module / zfs / zfs_sysfs.c
CommitLineData
e8bcb693
DB
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 http://www.opensolaris.org/os/licensing.
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 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 */
68struct zfs_mod_kobj;
69typedef struct zfs_mod_kobj zfs_mod_kobj_t;
70
71struct zfs_mod_kobj {
72 struct kobject zko_kobj;
73 struct kobj_type zko_kobj_type;
74 struct sysfs_ops zko_sysfs_ops;
75 size_t zko_attr_count;
76 struct attribute *zko_attr_list; /* allocated */
77 struct attribute **zko_default_attrs; /* allocated */
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 */
90static zfs_mod_kobj_t kernel_features_kobj;
91static zfs_mod_kobj_t pool_features_kobj;
92static zfs_mod_kobj_t dataset_props_kobj;
93static 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 */
99typedef ssize_t (*sysfs_show_func)(struct kobject *, struct attribute *,
100 char *);
101
102static void
103zfs_kobj_fini(zfs_mod_kobj_t *zkobj)
104{
7a23c813 105 /* finalize any child kobjects */
e8bcb693
DB
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
117static void
118zfs_kobj_release(struct kobject *kobj)
119{
120 zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj);
121
7a23c813
BB
122 if (zkobj->zko_attr_list != NULL) {
123 ASSERT3S(zkobj->zko_attr_count, !=, 0);
e8bcb693
DB
124 kmem_free(zkobj->zko_attr_list,
125 ATTR_TABLE_SIZE(zkobj->zko_attr_count));
7a23c813
BB
126 zkobj->zko_attr_list = NULL;
127 }
128
129 if (zkobj->zko_default_attrs != NULL) {
e8bcb693
DB
130 kmem_free(zkobj->zko_default_attrs,
131 DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
e8bcb693
DB
132 zkobj->zko_default_attrs = NULL;
133 }
7a23c813 134
e8bcb693
DB
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 }
7a23c813
BB
143
144 zkobj->zko_attr_count = 0;
e8bcb693
DB
145}
146
147static void
148zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name)
149{
150 VERIFY3U(attr_num, <, zkobj->zko_attr_count);
151 ASSERT(zkobj->zko_attr_list);
152 ASSERT(zkobj->zko_default_attrs);
153
154 zkobj->zko_attr_list[attr_num].name = attr_name;
155 zkobj->zko_attr_list[attr_num].mode = 0444;
156 zkobj->zko_default_attrs[attr_num] = &zkobj->zko_attr_list[attr_num];
157}
158
159static int
160zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
161 sysfs_show_func show_func)
162{
163 /*
164 * Initialize object's attributes. Count can be zero.
165 */
166 if (attr_cnt > 0) {
167 zkobj->zko_attr_list = kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt),
168 KM_SLEEP);
169 if (zkobj->zko_attr_list == NULL)
170 return (ENOMEM);
171 }
172 /* this will always have at least one slot for NULL termination */
173 zkobj->zko_default_attrs = kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt),
174 KM_SLEEP);
175 if (zkobj->zko_default_attrs == NULL) {
7a23c813 176 if (zkobj->zko_attr_list != NULL) {
e8bcb693
DB
177 kmem_free(zkobj->zko_attr_list,
178 ATTR_TABLE_SIZE(attr_cnt));
179 }
180 return (ENOMEM);
181 }
182 zkobj->zko_attr_count = attr_cnt;
183 zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_attrs;
184
185 if (child_cnt > 0) {
186 zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
187 KM_SLEEP);
188 if (zkobj->zko_children == NULL) {
7a23c813
BB
189 if (zkobj->zko_default_attrs != NULL) {
190 kmem_free(zkobj->zko_default_attrs,
e8bcb693 191 DEFAULT_ATTR_SIZE(attr_cnt));
7a23c813
BB
192 }
193 if (zkobj->zko_attr_list != NULL) {
e8bcb693
DB
194 kmem_free(zkobj->zko_attr_list,
195 ATTR_TABLE_SIZE(attr_cnt));
196 }
197 return (ENOMEM);
198 }
199 zkobj->zko_child_count = child_cnt;
200 }
201
202 zkobj->zko_sysfs_ops.show = show_func;
203 zkobj->zko_kobj_type.sysfs_ops = &zkobj->zko_sysfs_ops;
204 zkobj->zko_kobj_type.release = zfs_kobj_release;
205
206 return (0);
207}
208
209static int
210zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name)
211{
212 /* zko_default_attrs must be NULL terminated */
213 ASSERT(zkobj->zko_default_attrs != NULL);
214 ASSERT(zkobj->zko_default_attrs[zkobj->zko_attr_count] == NULL);
215
216 kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type);
217 return (kobject_add(&zkobj->zko_kobj, parent, name));
218}
219
220/*
221 * Each zfs property has these common attributes
222 */
223static const char *zprop_attrs[] = {
224 "type",
225 "readonly",
226 "setonce",
227 "visible",
228 "values",
229 "default",
230 "datasets" /* zfs properties only */
231};
232
233#define ZFS_PROP_ATTR_COUNT ARRAY_SIZE(zprop_attrs)
234#define ZPOOL_PROP_ATTR_COUNT (ZFS_PROP_ATTR_COUNT - 1)
235
236static const char *zprop_types[] = {
237 "number",
238 "string",
239 "index",
240};
241
242typedef struct zfs_type_map {
243 zfs_type_t ztm_type;
244 const char *ztm_name;
245} zfs_type_map_t;
246
247static zfs_type_map_t type_map[] = {
248 {ZFS_TYPE_FILESYSTEM, "filesystem"},
249 {ZFS_TYPE_SNAPSHOT, "snapshot"},
250 {ZFS_TYPE_VOLUME, "volume"},
251 {ZFS_TYPE_BOOKMARK, "bookmark"}
252};
253
254/*
255 * Show the content for a zfs property attribute
256 */
257static ssize_t
258zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property,
259 char *buf, size_t buflen)
260{
261 const char *show_str;
262
263 /* For dataset properties list the dataset types that apply */
264 if (strcmp(attr_name, "datasets") == 0 &&
265 property->pd_types != ZFS_TYPE_POOL) {
266 int len = 0;
267
268 for (int i = 0; i < ARRAY_SIZE(type_map); i++) {
269 if (type_map[i].ztm_type & property->pd_types) {
270 len += snprintf(buf + len, buflen - len, "%s ",
271 type_map[i].ztm_name);
272 }
273 }
274 len += snprintf(buf + len, buflen - len, "\n");
275 return (len);
276 }
277
278 if (strcmp(attr_name, "type") == 0) {
279 show_str = zprop_types[property->pd_proptype];
280 } else if (strcmp(attr_name, "readonly") == 0) {
281 show_str = property->pd_attr == PROP_READONLY ? "1" : "0";
282 } else if (strcmp(attr_name, "setonce") == 0) {
283 show_str = property->pd_attr == PROP_ONETIME ? "1" : "0";
284 } else if (strcmp(attr_name, "visible") == 0) {
285 show_str = property->pd_visible ? "1" : "0";
286 } else if (strcmp(attr_name, "values") == 0) {
287 show_str = property->pd_values ? property->pd_values : "";
288 } else if (strcmp(attr_name, "default") == 0) {
289 char number[32];
290
291 switch (property->pd_proptype) {
292 case PROP_TYPE_NUMBER:
293 (void) snprintf(number, sizeof (number), "%llu",
294 (u_longlong_t)property->pd_numdefault);
295 show_str = number;
296 break;
297 case PROP_TYPE_STRING:
298 show_str = property->pd_strdefault ?
299 property->pd_strdefault : "";
300 break;
301 case PROP_TYPE_INDEX:
e7b677aa 302 if (zprop_index_to_string(property->pd_propnum,
e8bcb693 303 property->pd_numdefault, &show_str,
e7b677aa
DB
304 property->pd_types) != 0) {
305 show_str = "";
306 }
e8bcb693
DB
307 break;
308 default:
309 return (0);
310 }
311 } else {
312 return (0);
313 }
314
315 return (snprintf(buf, buflen, "%s\n", show_str));
316}
317
318static ssize_t
319dataset_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
320{
321 zfs_prop_t prop = zfs_name_to_prop(kobject_name(kobj));
322 zprop_desc_t *prop_tbl = zfs_prop_get_table();
323 ssize_t len;
324
325 ASSERT3U(prop, <, ZFS_NUM_PROPS);
326
327 len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
328
329 return (len);
330}
331
332static ssize_t
333pool_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
334{
335 zpool_prop_t prop = zpool_name_to_prop(kobject_name(kobj));
336 zprop_desc_t *prop_tbl = zpool_prop_get_table();
337 ssize_t len;
338
339 ASSERT3U(prop, <, ZPOOL_NUM_PROPS);
340
341 len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
342
343 return (len);
344}
345
346/*
347 * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
348 *
349 * This list is intended for kernel features that don't have a pool feature
350 * association or that extend existing user kernel interfaces.
351 *
352 * A user processes can easily check if the running zfs kernel module
353 * supports the new feature.
354 *
355 * For example, the initial channel_program feature was extended to support
356 * async calls (i.e. a sync flag). If this mechanism were in place at that
357 * time, we could have added a 'channel_program_async' to this list.
358 */
359static const char *zfs_features[] = {
360 /* --> Add new kernel features here (post ZoL 0.8.0) */
361};
362
363#define ZFS_FEATURE_COUNT ARRAY_SIZE(zfs_features)
364
365static ssize_t
366kernel_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
367{
368 return (snprintf(buf, PAGE_SIZE, "supported\n"));
369}
370
371static int
372zfs_kernel_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
373{
374 int err;
375
376 err = zfs_kobj_init(zfs_kobj, ZFS_FEATURE_COUNT, 0,
377 kernel_feature_show);
378 if (err)
379 return (err);
380
381 for (int f = 0; f < ZFS_FEATURE_COUNT; f++)
382 zfs_kobj_add_attr(zfs_kobj, f, zfs_features[f]);
383
384 err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_KERNEL_FEATURES);
385 if (err)
386 zfs_kobj_release(&zfs_kobj->zko_kobj);
387
388 return (err);
389}
390
391/*
392 * Each pool feature has these common attributes
393 */
394static const char *pool_feature_attrs[] = {
395 "description",
396 "guid",
397 "uname",
398 "readonly_compatible",
399 "required_for_mos",
400 "activate_on_enable",
401 "per_dataset"
402};
403
404#define ZPOOL_FEATURE_ATTR_COUNT ARRAY_SIZE(pool_feature_attrs)
405
406/*
407 * Show the content for the given zfs pool feature attribute
408 */
409static ssize_t
410pool_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
411{
412 spa_feature_t fid;
413
414 if (zfeature_lookup_guid(kobject_name(kobj), &fid) != 0)
415 return (0);
416
417 ASSERT3U(fid, <, SPA_FEATURES);
418
419 zfeature_flags_t flags = spa_feature_table[fid].fi_flags;
420 const char *show_str = NULL;
421
422 if (strcmp(attr->name, "description") == 0) {
423 show_str = spa_feature_table[fid].fi_desc;
424 } else if (strcmp(attr->name, "guid") == 0) {
425 show_str = spa_feature_table[fid].fi_guid;
426 } else if (strcmp(attr->name, "uname") == 0) {
427 show_str = spa_feature_table[fid].fi_uname;
428 } else if (strcmp(attr->name, "readonly_compatible") == 0) {
429 show_str = flags & ZFEATURE_FLAG_READONLY_COMPAT ? "1" : "0";
430 } else if (strcmp(attr->name, "required_for_mos") == 0) {
431 show_str = flags & ZFEATURE_FLAG_MOS ? "1" : "0";
432 } else if (strcmp(attr->name, "activate_on_enable") == 0) {
433 show_str = flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE ? "1" : "0";
434 } else if (strcmp(attr->name, "per_dataset") == 0) {
435 show_str = flags & ZFEATURE_FLAG_PER_DATASET ? "1" : "0";
436 }
437 if (show_str == NULL)
438 return (0);
439
440 return (snprintf(buf, PAGE_SIZE, "%s\n", show_str));
441}
442
443static void
444pool_feature_to_kobj(zfs_mod_kobj_t *parent, spa_feature_t fid,
445 const char *name)
446{
447 zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[fid];
448
449 ASSERT3U(fid, <, SPA_FEATURES);
450 ASSERT(name);
451
452 int err = zfs_kobj_init(zfs_kobj, ZPOOL_FEATURE_ATTR_COUNT, 0,
453 pool_feature_show);
454 if (err)
455 return;
456
457 for (int i = 0; i < ZPOOL_FEATURE_ATTR_COUNT; i++)
458 zfs_kobj_add_attr(zfs_kobj, i, pool_feature_attrs[i]);
459
460 err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
461 if (err)
462 zfs_kobj_release(&zfs_kobj->zko_kobj);
463}
464
465static int
466zfs_pool_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
467{
468 /*
469 * Create a parent kobject to host pool features.
470 *
471 * '/sys/module/zfs/features.pool'
472 */
473 int err = zfs_kobj_init(zfs_kobj, 0, SPA_FEATURES, pool_feature_show);
474 if (err)
475 return (err);
476 err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_POOL_FEATURES);
477 if (err) {
478 zfs_kobj_release(&zfs_kobj->zko_kobj);
479 return (err);
480 }
481
482 /*
483 * Now create a kobject for each feature.
484 *
485 * '/sys/module/zfs/features.pool/<feature>'
486 */
487 for (spa_feature_t i = 0; i < SPA_FEATURES; i++)
488 pool_feature_to_kobj(zfs_kobj, i, spa_feature_table[i].fi_guid);
489
490 return (0);
491}
492
493typedef struct prop_to_kobj_arg {
494 zprop_desc_t *p2k_table;
495 zfs_mod_kobj_t *p2k_parent;
496 sysfs_show_func p2k_show_func;
497 int p2k_attr_count;
498} prop_to_kobj_arg_t;
499
500static int
501zprop_to_kobj(int prop, void *args)
502{
503 prop_to_kobj_arg_t *data = args;
504 zfs_mod_kobj_t *parent = data->p2k_parent;
505 zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[prop];
506 const char *name = data->p2k_table[prop].pd_name;
507 int err;
508
509 ASSERT(name);
510
511 err = zfs_kobj_init(zfs_kobj, data->p2k_attr_count, 0,
512 data->p2k_show_func);
513 if (err)
514 return (ZPROP_CONT);
515
516 for (int i = 0; i < data->p2k_attr_count; i++)
517 zfs_kobj_add_attr(zfs_kobj, i, zprop_attrs[i]);
518
519 err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
520 if (err)
521 zfs_kobj_release(&zfs_kobj->zko_kobj);
522
523 return (ZPROP_CONT);
524}
525
526static int
527zfs_sysfs_properties_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent,
528 zfs_type_t type)
529{
530 prop_to_kobj_arg_t context;
531 const char *name;
532 int err;
533
534 /*
535 * Create a parent kobject to host properties.
536 *
537 * '/sys/module/zfs/properties.<type>'
538 */
539 if (type == ZFS_TYPE_POOL) {
540 name = ZFS_SYSFS_POOL_PROPERTIES;
541 context.p2k_table = zpool_prop_get_table();
542 context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
543 context.p2k_parent = zfs_kobj;
544 context.p2k_show_func = pool_property_show;
545 err = zfs_kobj_init(zfs_kobj, 0, ZPOOL_NUM_PROPS,
546 pool_property_show);
547 } else {
548 name = ZFS_SYSFS_DATASET_PROPERTIES;
549 context.p2k_table = zfs_prop_get_table();
550 context.p2k_attr_count = ZFS_PROP_ATTR_COUNT;
551 context.p2k_parent = zfs_kobj;
552 context.p2k_show_func = dataset_property_show;
553 err = zfs_kobj_init(zfs_kobj, 0, ZFS_NUM_PROPS,
554 dataset_property_show);
555 }
556
557 if (err)
558 return (err);
559
560 err = zfs_kobj_add(zfs_kobj, parent, name);
561 if (err) {
562 zfs_kobj_release(&zfs_kobj->zko_kobj);
563 return (err);
564 }
565
566 /*
567 * Create a kobject for each property.
568 *
569 * '/sys/module/zfs/properties.<type>/<property>'
570 */
571 (void) zprop_iter_common(zprop_to_kobj, &context, B_TRUE,
572 B_FALSE, type);
573
574 return (err);
575}
576
577void
578zfs_sysfs_init(void)
579{
73a5ec30
DB
580 struct kobject *parent;
581#if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
582 parent = kobject_create_and_add("zfs", fs_kobj);
583#else
584 parent = &(((struct module *)(THIS_MODULE))->mkobj).kobj;
585#endif
e8bcb693
DB
586 int err;
587
73a5ec30
DB
588 if (parent == NULL)
589 return;
e8bcb693
DB
590
591 err = zfs_kernel_features_init(&kernel_features_kobj, parent);
592 if (err)
593 return;
594
595 err = zfs_pool_features_init(&pool_features_kobj, parent);
596 if (err) {
597 zfs_kobj_fini(&kernel_features_kobj);
598 return;
599 }
600
601 err = zfs_sysfs_properties_init(&pool_props_kobj, parent,
602 ZFS_TYPE_POOL);
603 if (err) {
604 zfs_kobj_fini(&kernel_features_kobj);
605 zfs_kobj_fini(&pool_features_kobj);
606 return;
607 }
608
609 err = zfs_sysfs_properties_init(&dataset_props_kobj, parent,
610 ZFS_TYPE_FILESYSTEM);
611 if (err) {
612 zfs_kobj_fini(&kernel_features_kobj);
613 zfs_kobj_fini(&pool_features_kobj);
614 zfs_kobj_fini(&pool_props_kobj);
615 return;
616 }
617}
618
619void
620zfs_sysfs_fini(void)
621{
622 /*
623 * Remove top-level kobjects; each will remove any children kobjects
624 */
625 zfs_kobj_fini(&kernel_features_kobj);
626 zfs_kobj_fini(&pool_features_kobj);
627 zfs_kobj_fini(&dataset_props_kobj);
628 zfs_kobj_fini(&pool_props_kobj);
629}