• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C), 2008-2021, OPPO Mobile Comm Corp., Ltd.
4  *             https://www.oppo.com/
5  */
6 #include <linux/sysfs.h>
7 #include <linux/kobject.h>
8 
9 #include "internal.h"
10 
11 enum {
12 	attr_feature,
13 	attr_pointer_ui,
14 	attr_pointer_bool,
15 };
16 
17 enum {
18 	struct_erofs_sb_info,
19 };
20 
21 struct erofs_attr {
22 	struct attribute attr;
23 	short attr_id;
24 	int struct_type, offset;
25 };
26 
27 #define EROFS_ATTR(_name, _mode, _id)					\
28 static struct erofs_attr erofs_attr_##_name = {				\
29 	.attr = {.name = __stringify(_name), .mode = _mode },		\
30 	.attr_id = attr_##_id,						\
31 }
32 #define EROFS_ATTR_FUNC(_name, _mode)	EROFS_ATTR(_name, _mode, _name)
33 #define EROFS_ATTR_FEATURE(_name)	EROFS_ATTR(_name, 0444, feature)
34 
35 #define EROFS_ATTR_OFFSET(_name, _mode, _id, _struct)	\
36 static struct erofs_attr erofs_attr_##_name = {			\
37 	.attr = {.name = __stringify(_name), .mode = _mode },	\
38 	.attr_id = attr_##_id,					\
39 	.struct_type = struct_##_struct,			\
40 	.offset = offsetof(struct _struct, _name),\
41 }
42 
43 #define EROFS_ATTR_RW(_name, _id, _struct)	\
44 	EROFS_ATTR_OFFSET(_name, 0644, _id, _struct)
45 
46 #define EROFS_RO_ATTR(_name, _id, _struct)	\
47 	EROFS_ATTR_OFFSET(_name, 0444, _id, _struct)
48 
49 #define EROFS_ATTR_RW_UI(_name, _struct)	\
50 	EROFS_ATTR_RW(_name, pointer_ui, _struct)
51 
52 #define EROFS_ATTR_RW_BOOL(_name, _struct)	\
53 	EROFS_ATTR_RW(_name, pointer_bool, _struct)
54 
55 #define ATTR_LIST(name) (&erofs_attr_##name.attr)
56 
57 static struct attribute *erofs_attrs[] = {
58 	NULL,
59 };
60 ATTRIBUTE_GROUPS(erofs);
61 
62 /* Features this copy of erofs supports */
63 EROFS_ATTR_FEATURE(zero_padding);
64 EROFS_ATTR_FEATURE(compr_cfgs);
65 EROFS_ATTR_FEATURE(big_pcluster);
66 EROFS_ATTR_FEATURE(chunked_file);
67 EROFS_ATTR_FEATURE(device_table);
68 EROFS_ATTR_FEATURE(compr_head2);
69 EROFS_ATTR_FEATURE(sb_chksum);
70 
71 static struct attribute *erofs_feat_attrs[] = {
72 	ATTR_LIST(zero_padding),
73 	ATTR_LIST(compr_cfgs),
74 	ATTR_LIST(big_pcluster),
75 	ATTR_LIST(chunked_file),
76 	ATTR_LIST(device_table),
77 	ATTR_LIST(compr_head2),
78 	ATTR_LIST(sb_chksum),
79 	NULL,
80 };
81 ATTRIBUTE_GROUPS(erofs_feat);
82 
__struct_ptr(struct erofs_sb_info * sbi,int struct_type,int offset)83 static unsigned char *__struct_ptr(struct erofs_sb_info *sbi,
84 					  int struct_type, int offset)
85 {
86 	if (struct_type == struct_erofs_sb_info)
87 		return (unsigned char *)sbi + offset;
88 	return NULL;
89 }
90 
erofs_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)91 static ssize_t erofs_attr_show(struct kobject *kobj,
92 				struct attribute *attr, char *buf)
93 {
94 	struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
95 						s_kobj);
96 	struct erofs_attr *a = container_of(attr, struct erofs_attr, attr);
97 	unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
98 
99 	switch (a->attr_id) {
100 	case attr_feature:
101 		return sysfs_emit(buf, "supported\n");
102 	case attr_pointer_ui:
103 		if (!ptr)
104 			return 0;
105 		return sysfs_emit(buf, "%u\n", *(unsigned int *)ptr);
106 	case attr_pointer_bool:
107 		if (!ptr)
108 			return 0;
109 		return sysfs_emit(buf, "%d\n", *(bool *)ptr);
110 	}
111 	return 0;
112 }
113 
erofs_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t len)114 static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
115 						const char *buf, size_t len)
116 {
117 	struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
118 						s_kobj);
119 	struct erofs_attr *a = container_of(attr, struct erofs_attr, attr);
120 	unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
121 	unsigned long t;
122 	int ret;
123 
124 	switch (a->attr_id) {
125 	case attr_pointer_ui:
126 		if (!ptr)
127 			return 0;
128 		ret = kstrtoul(skip_spaces(buf), 0, &t);
129 		if (ret)
130 			return ret;
131 		if (t != (unsigned int)t)
132 			return -ERANGE;
133 		*(unsigned int *)ptr = t;
134 		return len;
135 	case attr_pointer_bool:
136 		if (!ptr)
137 			return 0;
138 		ret = kstrtoul(skip_spaces(buf), 0, &t);
139 		if (ret)
140 			return ret;
141 		if (t != 0 && t != 1)
142 			return -EINVAL;
143 		*(bool *)ptr = !!t;
144 		return len;
145 	}
146 	return 0;
147 }
148 
erofs_sb_release(struct kobject * kobj)149 static void erofs_sb_release(struct kobject *kobj)
150 {
151 	struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
152 						 s_kobj);
153 	complete(&sbi->s_kobj_unregister);
154 }
155 
156 static const struct sysfs_ops erofs_attr_ops = {
157 	.show	= erofs_attr_show,
158 	.store	= erofs_attr_store,
159 };
160 
161 static struct kobj_type erofs_sb_ktype = {
162 	.default_groups = erofs_groups,
163 	.sysfs_ops	= &erofs_attr_ops,
164 	.release	= erofs_sb_release,
165 };
166 
167 static struct kobj_type erofs_ktype = {
168 	.sysfs_ops	= &erofs_attr_ops,
169 };
170 
171 static struct kset erofs_root = {
172 	.kobj	= {.ktype = &erofs_ktype},
173 };
174 
175 static struct kobj_type erofs_feat_ktype = {
176 	.default_groups = erofs_feat_groups,
177 	.sysfs_ops	= &erofs_attr_ops,
178 };
179 
180 static struct kobject erofs_feat = {
181 	.kset	= &erofs_root,
182 };
183 
erofs_register_sysfs(struct super_block * sb)184 int erofs_register_sysfs(struct super_block *sb)
185 {
186 	struct erofs_sb_info *sbi = EROFS_SB(sb);
187 	int err;
188 
189 	sbi->s_kobj.kset = &erofs_root;
190 	init_completion(&sbi->s_kobj_unregister);
191 	err = kobject_init_and_add(&sbi->s_kobj, &erofs_sb_ktype, NULL,
192 				   "%s", sb->s_id);
193 	if (err)
194 		goto put_sb_kobj;
195 	return 0;
196 
197 put_sb_kobj:
198 	kobject_put(&sbi->s_kobj);
199 	wait_for_completion(&sbi->s_kobj_unregister);
200 	return err;
201 }
202 
erofs_unregister_sysfs(struct super_block * sb)203 void erofs_unregister_sysfs(struct super_block *sb)
204 {
205 	struct erofs_sb_info *sbi = EROFS_SB(sb);
206 
207 	if (sbi->s_kobj.state_in_sysfs) {
208 		kobject_del(&sbi->s_kobj);
209 		kobject_put(&sbi->s_kobj);
210 		wait_for_completion(&sbi->s_kobj_unregister);
211 	}
212 }
213 
erofs_init_sysfs(void)214 int __init erofs_init_sysfs(void)
215 {
216 	int ret;
217 
218 	kobject_set_name(&erofs_root.kobj, "erofs");
219 	erofs_root.kobj.parent = fs_kobj;
220 	ret = kset_register(&erofs_root);
221 	if (ret)
222 		goto root_err;
223 
224 	ret = kobject_init_and_add(&erofs_feat, &erofs_feat_ktype,
225 				   NULL, "features");
226 	if (ret)
227 		goto feat_err;
228 	return ret;
229 
230 feat_err:
231 	kobject_put(&erofs_feat);
232 	kset_unregister(&erofs_root);
233 root_err:
234 	return ret;
235 }
236 
erofs_exit_sysfs(void)237 void erofs_exit_sysfs(void)
238 {
239 	kobject_put(&erofs_feat);
240 	kset_unregister(&erofs_root);
241 }
242