blob: 7acc5a74e5fa7d7bd72c5ac1646c3cbc8ac8316c [file] [log] [blame]
Stefan Schaeckeler2e3cbf42021-10-09 21:22:39 -07001// 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};
45
46static ssize_t ubifs_attr_show(struct kobject *kobj,
47 struct attribute *attr, char *buf)
48{
49 struct ubifs_info *sbi = container_of(kobj, struct ubifs_info,
50 kobj);
51
52 struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr);
53
54 switch (a->attr_id) {
55 case attr_errors_magic:
56 return sysfs_emit(buf, "%u\n", sbi->stats->magic_errors);
57 case attr_errors_node:
58 return sysfs_emit(buf, "%u\n", sbi->stats->node_errors);
59 case attr_errors_crc:
60 return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors);
61 }
62 return 0;
63};
64
65static void ubifs_sb_release(struct kobject *kobj)
66{
67 struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj);
68
69 complete(&c->kobj_unregister);
70}
71
72static const struct sysfs_ops ubifs_attr_ops = {
73 .show = ubifs_attr_show,
74};
75
76static struct kobj_type ubifs_sb_ktype = {
77 .default_attrs = ubifs_attrs,
78 .sysfs_ops = &ubifs_attr_ops,
79 .release = ubifs_sb_release,
80};
81
82static struct kobj_type ubifs_ktype = {
83 .sysfs_ops = &ubifs_attr_ops,
84};
85
86static struct kset ubifs_kset = {
87 .kobj = {.ktype = &ubifs_ktype},
88};
89
90int ubifs_sysfs_register(struct ubifs_info *c)
91{
92 int ret, n;
93 char dfs_dir_name[UBIFS_DFS_DIR_LEN+1];
94
95 c->stats = kzalloc(sizeof(struct ubifs_stats_info), GFP_KERNEL);
96 if (!c->stats) {
97 ret = -ENOMEM;
98 goto out_last;
99 }
100 n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
101 c->vi.ubi_num, c->vi.vol_id);
102
Dan Carpenterd3de9702021-11-09 14:50:51 +0300103 if (n > UBIFS_DFS_DIR_LEN) {
Stefan Schaeckeler2e3cbf42021-10-09 21:22:39 -0700104 /* The array size is too small */
105 ret = -EINVAL;
106 goto out_free;
107 }
108
109 c->kobj.kset = &ubifs_kset;
110 init_completion(&c->kobj_unregister);
111
112 ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL,
113 "%s", dfs_dir_name);
114 if (ret)
115 goto out_put;
116
117 return 0;
118
119out_put:
120 kobject_put(&c->kobj);
121 wait_for_completion(&c->kobj_unregister);
122out_free:
123 kfree(c->stats);
124out_last:
125 ubifs_err(c, "cannot create sysfs entry for ubifs%d_%d, error %d\n",
126 c->vi.ubi_num, c->vi.vol_id, ret);
127 return ret;
128}
129
130void ubifs_sysfs_unregister(struct ubifs_info *c)
131{
132 kobject_del(&c->kobj);
133 kobject_put(&c->kobj);
134 wait_for_completion(&c->kobj_unregister);
135
136 kfree(c->stats);
137}
138
139int __init ubifs_sysfs_init(void)
140{
141 int ret;
142
143 kobject_set_name(&ubifs_kset.kobj, "ubifs");
144 ubifs_kset.kobj.parent = fs_kobj;
145 ret = kset_register(&ubifs_kset);
146
147 return ret;
148}
149
150void ubifs_sysfs_exit(void)
151{
152 kset_unregister(&ubifs_kset);
153}