Merge branches 'fixes' and 'misc' into for-linus
[platform/kernel/linux-starfive.git] / fs / ubifs / sysfs.c
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 };
45
46 static 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
65 static 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
72 static const struct sysfs_ops ubifs_attr_ops = {
73         .show   = ubifs_attr_show,
74 };
75
76 static struct kobj_type ubifs_sb_ktype = {
77         .default_attrs  = ubifs_attrs,
78         .sysfs_ops      = &ubifs_attr_ops,
79         .release        = ubifs_sb_release,
80 };
81
82 static struct kobj_type ubifs_ktype = {
83         .sysfs_ops      = &ubifs_attr_ops,
84 };
85
86 static struct kset ubifs_kset = {
87         .kobj   = {.ktype = &ubifs_ktype},
88 };
89
90 int 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
103         if (n > UBIFS_DFS_DIR_LEN) {
104                 /* 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
119 out_put:
120         kobject_put(&c->kobj);
121         wait_for_completion(&c->kobj_unregister);
122 out_free:
123         kfree(c->stats);
124 out_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
130 void 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
139 int __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
150 void ubifs_sysfs_exit(void)
151 {
152         kset_unregister(&ubifs_kset);
153 }