]>
Commit | Line | Data |
---|---|---|
2e3cbf42 SS |
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 | ||
14 | enum attr_id_t { | |
15 | attr_errors_magic, | |
16 | attr_errors_node, | |
17 | attr_errors_crc, | |
18 | }; | |
19 | ||
20 | struct ubifs_attr { | |
21 | struct attribute attr; | |
22 | enum attr_id_t attr_id; | |
23 | }; | |
24 | ||
25 | #define UBIFS_ATTR(_name, _mode, _id) \ | |
26 | static 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 | ||
33 | UBIFS_ATTR_FUNC(errors_magic, 0444); | |
34 | UBIFS_ATTR_FUNC(errors_crc, 0444); | |
35 | UBIFS_ATTR_FUNC(errors_node, 0444); | |
36 | ||
37 | #define ATTR_LIST(name) (&ubifs_attr_##name.attr) | |
38 | ||
39 | static struct attribute *ubifs_attrs[] = { | |
40 | ATTR_LIST(errors_magic), | |
41 | ATTR_LIST(errors_node), | |
42 | ATTR_LIST(errors_crc), | |
43 | NULL, | |
44 | }; | |
c6479f19 | 45 | ATTRIBUTE_GROUPS(ubifs); |
2e3cbf42 SS |
46 | |
47 | static 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, "%u\n", sbi->stats->magic_errors); | |
58 | case attr_errors_node: | |
59 | return sysfs_emit(buf, "%u\n", sbi->stats->node_errors); | |
60 | case attr_errors_crc: | |
61 | return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors); | |
62 | } | |
63 | return 0; | |
64 | }; | |
65 | ||
66 | static 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 | ||
73 | static const struct sysfs_ops ubifs_attr_ops = { | |
74 | .show = ubifs_attr_show, | |
75 | }; | |
76 | ||
22d74bc2 | 77 | static const struct kobj_type ubifs_sb_ktype = { |
c6479f19 | 78 | .default_groups = ubifs_groups, |
2e3cbf42 SS |
79 | .sysfs_ops = &ubifs_attr_ops, |
80 | .release = ubifs_sb_release, | |
81 | }; | |
82 | ||
22d74bc2 | 83 | static const struct kobj_type ubifs_ktype = { |
2e3cbf42 SS |
84 | .sysfs_ops = &ubifs_attr_ops, |
85 | }; | |
86 | ||
87 | static struct kset ubifs_kset = { | |
88 | .kobj = {.ktype = &ubifs_ktype}, | |
89 | }; | |
90 | ||
91 | int 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(sizeof(struct ubifs_stats_info), GFP_KERNEL); | |
97 | if (!c->stats) { | |
98 | ret = -ENOMEM; | |
99 | goto out_last; | |
100 | } | |
101 | n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, | |
102 | c->vi.ubi_num, c->vi.vol_id); | |
103 | ||
d3de970b | 104 | if (n > UBIFS_DFS_DIR_LEN) { |
2e3cbf42 SS |
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(&c->kobj_unregister); | |
112 | ||
113 | ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL, | |
114 | "%s", dfs_dir_name); | |
115 | if (ret) | |
116 | goto out_put; | |
117 | ||
118 | return 0; | |
119 | ||
120 | out_put: | |
121 | kobject_put(&c->kobj); | |
122 | wait_for_completion(&c->kobj_unregister); | |
123 | out_free: | |
124 | kfree(c->stats); | |
125 | out_last: | |
126 | ubifs_err(c, "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 | ||
131 | void ubifs_sysfs_unregister(struct ubifs_info *c) | |
132 | { | |
133 | kobject_del(&c->kobj); | |
134 | kobject_put(&c->kobj); | |
135 | wait_for_completion(&c->kobj_unregister); | |
136 | ||
137 | kfree(c->stats); | |
138 | } | |
139 | ||
140 | int __init ubifs_sysfs_init(void) | |
141 | { | |
142 | int ret; | |
143 | ||
144 | kobject_set_name(&ubifs_kset.kobj, "ubifs"); | |
145 | ubifs_kset.kobj.parent = fs_kobj; | |
146 | ret = kset_register(&ubifs_kset); | |
203a55f0 LS |
147 | if (ret) |
148 | kset_put(&ubifs_kset); | |
2e3cbf42 SS |
149 | |
150 | return ret; | |
151 | } | |
152 | ||
153 | void ubifs_sysfs_exit(void) | |
154 | { | |
155 | kset_unregister(&ubifs_kset); | |
156 | } |