xref: /openbmc/linux/fs/ubifs/sysfs.c (revision 61263b3a)
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 }
154