xref: /openbmc/linux/fs/ubifs/sysfs.c (revision 0545810f)
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 ATTRIBUTE_GROUPS(ubifs);
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 
77 static 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 
83 static const struct kobj_type ubifs_ktype = {
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 
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(&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);
147 	if (ret)
148 		kset_put(&ubifs_kset);
149 
150 	return ret;
151 }
152 
153 void ubifs_sysfs_exit(void)
154 {
155 	kset_unregister(&ubifs_kset);
156 }
157