1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * This file is part of UBIFS.
4 *
5 * Copyright (C) 2021 Cisco Systems
6 *
7 * Author: Stefan Schaeckeler
8 */
9
10
11#include <linux/fs.h>
12#include "ubifs.h"
13
14enum attr_id_t {
15 attr_errors_magic,
16 attr_errors_node,
17 attr_errors_crc,
18};
19
20struct ubifs_attr {
21 struct attribute attr;
22 enum attr_id_t attr_id;
23};
24
25#define UBIFS_ATTR(_name, _mode, _id) \
26static struct ubifs_attr ubifs_attr_##_name = { \
27 .attr = {.name = __stringify(_name), .mode = _mode }, \
28 .attr_id = attr_##_id, \
29}
30
31#define UBIFS_ATTR_FUNC(_name, _mode) UBIFS_ATTR(_name, _mode, _name)
32
33UBIFS_ATTR_FUNC(errors_magic, 0444);
34UBIFS_ATTR_FUNC(errors_crc, 0444);
35UBIFS_ATTR_FUNC(errors_node, 0444);
36
37#define ATTR_LIST(name) (&ubifs_attr_##name.attr)
38
39static struct attribute *ubifs_attrs[] = {
40 ATTR_LIST(errors_magic),
41 ATTR_LIST(errors_node),
42 ATTR_LIST(errors_crc),
43 NULL,
44};
45ATTRIBUTE_GROUPS(ubifs);
46
47static ssize_t ubifs_attr_show(struct kobject *kobj,
48 struct attribute *attr, char *buf)
49{
50 struct ubifs_info *sbi = container_of(kobj, struct ubifs_info,
51 kobj);
52
53 struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr);
54
55 switch (a->attr_id) {
56 case attr_errors_magic:
57 return sysfs_emit(buf, fmt: "%u\n", sbi->stats->magic_errors);
58 case attr_errors_node:
59 return sysfs_emit(buf, fmt: "%u\n", sbi->stats->node_errors);
60 case attr_errors_crc:
61 return sysfs_emit(buf, fmt: "%u\n", sbi->stats->crc_errors);
62 }
63 return 0;
64};
65
66static void ubifs_sb_release(struct kobject *kobj)
67{
68 struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj);
69
70 complete(&c->kobj_unregister);
71}
72
73static const struct sysfs_ops ubifs_attr_ops = {
74 .show = ubifs_attr_show,
75};
76
77static const struct kobj_type ubifs_sb_ktype = {
78 .default_groups = ubifs_groups,
79 .sysfs_ops = &ubifs_attr_ops,
80 .release = ubifs_sb_release,
81};
82
83static const struct kobj_type ubifs_ktype = {
84 .sysfs_ops = &ubifs_attr_ops,
85};
86
87static struct kset ubifs_kset = {
88 .kobj = {.ktype = &ubifs_ktype},
89};
90
91int ubifs_sysfs_register(struct ubifs_info *c)
92{
93 int ret, n;
94 char dfs_dir_name[UBIFS_DFS_DIR_LEN+1];
95
96 c->stats = kzalloc(size: sizeof(struct ubifs_stats_info), GFP_KERNEL);
97 if (!c->stats) {
98 ret = -ENOMEM;
99 goto out_last;
100 }
101 n = snprintf(buf: dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
102 c->vi.ubi_num, c->vi.vol_id);
103
104 if (n > UBIFS_DFS_DIR_LEN) {
105 /* The array size is too small */
106 ret = -EINVAL;
107 goto out_free;
108 }
109
110 c->kobj.kset = &ubifs_kset;
111 init_completion(x: &c->kobj_unregister);
112
113 ret = kobject_init_and_add(kobj: &c->kobj, ktype: &ubifs_sb_ktype, NULL,
114 fmt: "%s", dfs_dir_name);
115 if (ret)
116 goto out_put;
117
118 return 0;
119
120out_put:
121 kobject_put(kobj: &c->kobj);
122 wait_for_completion(&c->kobj_unregister);
123out_free:
124 kfree(objp: c->stats);
125out_last:
126 ubifs_err(c, fmt: "cannot create sysfs entry for ubifs%d_%d, error %d\n",
127 c->vi.ubi_num, c->vi.vol_id, ret);
128 return ret;
129}
130
131void ubifs_sysfs_unregister(struct ubifs_info *c)
132{
133 kobject_del(kobj: &c->kobj);
134 kobject_put(kobj: &c->kobj);
135 wait_for_completion(&c->kobj_unregister);
136
137 kfree(objp: c->stats);
138}
139
140int __init ubifs_sysfs_init(void)
141{
142 int ret;
143
144 kobject_set_name(kobj: &ubifs_kset.kobj, name: "ubifs");
145 ubifs_kset.kobj.parent = fs_kobj;
146 ret = kset_register(kset: &ubifs_kset);
147 if (ret)
148 kset_put(k: &ubifs_kset);
149
150 return ret;
151}
152
153void ubifs_sysfs_exit(void)
154{
155 kset_unregister(kset: &ubifs_kset);
156}
157

source code of linux/fs/ubifs/sysfs.c