Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/erofs/sysfs.c
26278 views
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
#include "compress.h"
11
12
enum {
13
attr_feature,
14
attr_drop_caches,
15
attr_pointer_ui,
16
attr_pointer_bool,
17
attr_accel,
18
};
19
20
enum {
21
struct_erofs_sb_info,
22
struct_erofs_mount_opts,
23
};
24
25
struct erofs_attr {
26
struct attribute attr;
27
short attr_id;
28
int struct_type, offset;
29
};
30
31
#define EROFS_ATTR(_name, _mode, _id) \
32
static struct erofs_attr erofs_attr_##_name = { \
33
.attr = {.name = __stringify(_name), .mode = _mode }, \
34
.attr_id = attr_##_id, \
35
}
36
#define EROFS_ATTR_FUNC(_name, _mode) EROFS_ATTR(_name, _mode, _name)
37
#define EROFS_ATTR_FEATURE(_name) EROFS_ATTR(_name, 0444, feature)
38
39
#define EROFS_ATTR_OFFSET(_name, _mode, _id, _struct) \
40
static struct erofs_attr erofs_attr_##_name = { \
41
.attr = {.name = __stringify(_name), .mode = _mode }, \
42
.attr_id = attr_##_id, \
43
.struct_type = struct_##_struct, \
44
.offset = offsetof(struct _struct, _name),\
45
}
46
47
#define EROFS_ATTR_RW(_name, _id, _struct) \
48
EROFS_ATTR_OFFSET(_name, 0644, _id, _struct)
49
50
#define EROFS_RO_ATTR(_name, _id, _struct) \
51
EROFS_ATTR_OFFSET(_name, 0444, _id, _struct)
52
53
#define EROFS_ATTR_RW_UI(_name, _struct) \
54
EROFS_ATTR_RW(_name, pointer_ui, _struct)
55
56
#define EROFS_ATTR_RW_BOOL(_name, _struct) \
57
EROFS_ATTR_RW(_name, pointer_bool, _struct)
58
59
#define ATTR_LIST(name) (&erofs_attr_##name.attr)
60
61
#ifdef CONFIG_EROFS_FS_ZIP
62
EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts);
63
EROFS_ATTR_FUNC(drop_caches, 0200);
64
#endif
65
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
66
EROFS_ATTR_FUNC(accel, 0644);
67
#endif
68
EROFS_ATTR_RW_UI(dir_ra_bytes, erofs_sb_info);
69
70
static struct attribute *erofs_sb_attrs[] = {
71
#ifdef CONFIG_EROFS_FS_ZIP
72
ATTR_LIST(sync_decompress),
73
ATTR_LIST(drop_caches),
74
#endif
75
ATTR_LIST(dir_ra_bytes),
76
NULL,
77
};
78
ATTRIBUTE_GROUPS(erofs_sb);
79
80
static struct attribute *erofs_attrs[] = {
81
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
82
ATTR_LIST(accel),
83
#endif
84
NULL,
85
};
86
ATTRIBUTE_GROUPS(erofs);
87
88
/* Features this copy of erofs supports */
89
EROFS_ATTR_FEATURE(zero_padding);
90
EROFS_ATTR_FEATURE(compr_cfgs);
91
EROFS_ATTR_FEATURE(big_pcluster);
92
EROFS_ATTR_FEATURE(chunked_file);
93
EROFS_ATTR_FEATURE(device_table);
94
EROFS_ATTR_FEATURE(compr_head2);
95
EROFS_ATTR_FEATURE(sb_chksum);
96
EROFS_ATTR_FEATURE(ztailpacking);
97
EROFS_ATTR_FEATURE(fragments);
98
EROFS_ATTR_FEATURE(dedupe);
99
EROFS_ATTR_FEATURE(48bit);
100
EROFS_ATTR_FEATURE(metabox);
101
102
static struct attribute *erofs_feat_attrs[] = {
103
ATTR_LIST(zero_padding),
104
ATTR_LIST(compr_cfgs),
105
ATTR_LIST(big_pcluster),
106
ATTR_LIST(chunked_file),
107
ATTR_LIST(device_table),
108
ATTR_LIST(compr_head2),
109
ATTR_LIST(sb_chksum),
110
ATTR_LIST(ztailpacking),
111
ATTR_LIST(fragments),
112
ATTR_LIST(dedupe),
113
ATTR_LIST(48bit),
114
ATTR_LIST(metabox),
115
NULL,
116
};
117
ATTRIBUTE_GROUPS(erofs_feat);
118
119
static unsigned char *__struct_ptr(struct erofs_sb_info *sbi,
120
int struct_type, int offset)
121
{
122
if (struct_type == struct_erofs_sb_info)
123
return (unsigned char *)sbi + offset;
124
if (struct_type == struct_erofs_mount_opts)
125
return (unsigned char *)&sbi->opt + offset;
126
return NULL;
127
}
128
129
static ssize_t erofs_attr_show(struct kobject *kobj,
130
struct attribute *attr, char *buf)
131
{
132
struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
133
s_kobj);
134
struct erofs_attr *a = container_of(attr, struct erofs_attr, attr);
135
unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
136
137
switch (a->attr_id) {
138
case attr_feature:
139
return sysfs_emit(buf, "supported\n");
140
case attr_pointer_ui:
141
if (!ptr)
142
return 0;
143
return sysfs_emit(buf, "%u\n", *(unsigned int *)ptr);
144
case attr_pointer_bool:
145
if (!ptr)
146
return 0;
147
return sysfs_emit(buf, "%d\n", *(bool *)ptr);
148
case attr_accel:
149
return z_erofs_crypto_show_engines(buf, PAGE_SIZE, '\n');
150
}
151
return 0;
152
}
153
154
static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
155
const char *buf, size_t len)
156
{
157
struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
158
s_kobj);
159
struct erofs_attr *a = container_of(attr, struct erofs_attr, attr);
160
unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
161
unsigned long t;
162
int ret;
163
164
switch (a->attr_id) {
165
case attr_pointer_ui:
166
if (!ptr)
167
return 0;
168
ret = kstrtoul(skip_spaces(buf), 0, &t);
169
if (ret)
170
return ret;
171
if (t != (unsigned int)t)
172
return -ERANGE;
173
#ifdef CONFIG_EROFS_FS_ZIP
174
if (!strcmp(a->attr.name, "sync_decompress") &&
175
(t > EROFS_SYNC_DECOMPRESS_FORCE_OFF))
176
return -EINVAL;
177
#endif
178
*(unsigned int *)ptr = t;
179
return len;
180
case attr_pointer_bool:
181
if (!ptr)
182
return 0;
183
ret = kstrtoul(skip_spaces(buf), 0, &t);
184
if (ret)
185
return ret;
186
if (t != 0 && t != 1)
187
return -EINVAL;
188
*(bool *)ptr = !!t;
189
return len;
190
#ifdef CONFIG_EROFS_FS_ZIP
191
case attr_drop_caches:
192
ret = kstrtoul(skip_spaces(buf), 0, &t);
193
if (ret)
194
return ret;
195
if (t < 1 || t > 3)
196
return -EINVAL;
197
198
if (t & 2)
199
z_erofs_shrink_scan(sbi, ~0UL);
200
if (t & 1)
201
invalidate_mapping_pages(MNGD_MAPPING(sbi), 0, -1);
202
return len;
203
#endif
204
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
205
case attr_accel:
206
buf = skip_spaces(buf);
207
z_erofs_crypto_disable_all_engines();
208
while (*buf) {
209
t = strcspn(buf, "\n");
210
ret = z_erofs_crypto_enable_engine(buf, t);
211
if (ret < 0)
212
return ret;
213
buf += buf[t] != '\0' ? t + 1 : t;
214
}
215
return len;
216
#endif
217
}
218
return 0;
219
}
220
221
static void erofs_sb_release(struct kobject *kobj)
222
{
223
struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
224
s_kobj);
225
complete(&sbi->s_kobj_unregister);
226
}
227
228
static const struct sysfs_ops erofs_attr_ops = {
229
.show = erofs_attr_show,
230
.store = erofs_attr_store,
231
};
232
233
static const struct kobj_type erofs_sb_ktype = {
234
.default_groups = erofs_sb_groups,
235
.sysfs_ops = &erofs_attr_ops,
236
.release = erofs_sb_release,
237
};
238
239
static const struct kobj_type erofs_ktype = {
240
.default_groups = erofs_groups,
241
.sysfs_ops = &erofs_attr_ops,
242
};
243
244
static struct kset erofs_root = {
245
.kobj = {.ktype = &erofs_ktype},
246
};
247
248
static const struct kobj_type erofs_feat_ktype = {
249
.default_groups = erofs_feat_groups,
250
.sysfs_ops = &erofs_attr_ops,
251
};
252
253
static struct kobject erofs_feat = {
254
.kset = &erofs_root,
255
};
256
257
int erofs_register_sysfs(struct super_block *sb)
258
{
259
struct erofs_sb_info *sbi = EROFS_SB(sb);
260
int err;
261
262
sbi->s_kobj.kset = &erofs_root;
263
init_completion(&sbi->s_kobj_unregister);
264
err = kobject_init_and_add(&sbi->s_kobj, &erofs_sb_ktype, NULL, "%s",
265
sb->s_sysfs_name);
266
if (err) {
267
kobject_put(&sbi->s_kobj);
268
wait_for_completion(&sbi->s_kobj_unregister);
269
}
270
return err;
271
}
272
273
void erofs_unregister_sysfs(struct super_block *sb)
274
{
275
struct erofs_sb_info *sbi = EROFS_SB(sb);
276
277
if (sbi->s_kobj.state_in_sysfs) {
278
kobject_del(&sbi->s_kobj);
279
kobject_put(&sbi->s_kobj);
280
wait_for_completion(&sbi->s_kobj_unregister);
281
}
282
}
283
284
void erofs_exit_sysfs(void)
285
{
286
kobject_put(&erofs_feat);
287
kset_unregister(&erofs_root);
288
}
289
290
int __init erofs_init_sysfs(void)
291
{
292
int ret;
293
294
kobject_set_name(&erofs_root.kobj, "erofs");
295
erofs_root.kobj.parent = fs_kobj;
296
ret = kset_register(&erofs_root);
297
if (!ret) {
298
ret = kobject_init_and_add(&erofs_feat, &erofs_feat_ktype,
299
NULL, "features");
300
if (!ret)
301
return 0;
302
erofs_exit_sysfs();
303
}
304
return ret;
305
}
306
307