0001
0002
0003
0004
0005
0006 #include <linux/sysfs.h>
0007 #include <linux/kobject.h>
0008
0009 #include "internal.h"
0010
0011 enum {
0012 attr_feature,
0013 attr_pointer_ui,
0014 attr_pointer_bool,
0015 };
0016
0017 enum {
0018 struct_erofs_sb_info,
0019 struct_erofs_mount_opts,
0020 };
0021
0022 struct erofs_attr {
0023 struct attribute attr;
0024 short attr_id;
0025 int struct_type, offset;
0026 };
0027
0028 #define EROFS_ATTR(_name, _mode, _id) \
0029 static struct erofs_attr erofs_attr_##_name = { \
0030 .attr = {.name = __stringify(_name), .mode = _mode }, \
0031 .attr_id = attr_##_id, \
0032 }
0033 #define EROFS_ATTR_FUNC(_name, _mode) EROFS_ATTR(_name, _mode, _name)
0034 #define EROFS_ATTR_FEATURE(_name) EROFS_ATTR(_name, 0444, feature)
0035
0036 #define EROFS_ATTR_OFFSET(_name, _mode, _id, _struct) \
0037 static struct erofs_attr erofs_attr_##_name = { \
0038 .attr = {.name = __stringify(_name), .mode = _mode }, \
0039 .attr_id = attr_##_id, \
0040 .struct_type = struct_##_struct, \
0041 .offset = offsetof(struct _struct, _name),\
0042 }
0043
0044 #define EROFS_ATTR_RW(_name, _id, _struct) \
0045 EROFS_ATTR_OFFSET(_name, 0644, _id, _struct)
0046
0047 #define EROFS_RO_ATTR(_name, _id, _struct) \
0048 EROFS_ATTR_OFFSET(_name, 0444, _id, _struct)
0049
0050 #define EROFS_ATTR_RW_UI(_name, _struct) \
0051 EROFS_ATTR_RW(_name, pointer_ui, _struct)
0052
0053 #define EROFS_ATTR_RW_BOOL(_name, _struct) \
0054 EROFS_ATTR_RW(_name, pointer_bool, _struct)
0055
0056 #define ATTR_LIST(name) (&erofs_attr_##name.attr)
0057
0058 #ifdef CONFIG_EROFS_FS_ZIP
0059 EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts);
0060 #endif
0061
0062 static struct attribute *erofs_attrs[] = {
0063 #ifdef CONFIG_EROFS_FS_ZIP
0064 ATTR_LIST(sync_decompress),
0065 #endif
0066 NULL,
0067 };
0068 ATTRIBUTE_GROUPS(erofs);
0069
0070
0071 EROFS_ATTR_FEATURE(zero_padding);
0072 EROFS_ATTR_FEATURE(compr_cfgs);
0073 EROFS_ATTR_FEATURE(big_pcluster);
0074 EROFS_ATTR_FEATURE(chunked_file);
0075 EROFS_ATTR_FEATURE(device_table);
0076 EROFS_ATTR_FEATURE(compr_head2);
0077 EROFS_ATTR_FEATURE(sb_chksum);
0078 EROFS_ATTR_FEATURE(ztailpacking);
0079
0080 static struct attribute *erofs_feat_attrs[] = {
0081 ATTR_LIST(zero_padding),
0082 ATTR_LIST(compr_cfgs),
0083 ATTR_LIST(big_pcluster),
0084 ATTR_LIST(chunked_file),
0085 ATTR_LIST(device_table),
0086 ATTR_LIST(compr_head2),
0087 ATTR_LIST(sb_chksum),
0088 ATTR_LIST(ztailpacking),
0089 NULL,
0090 };
0091 ATTRIBUTE_GROUPS(erofs_feat);
0092
0093 static unsigned char *__struct_ptr(struct erofs_sb_info *sbi,
0094 int struct_type, int offset)
0095 {
0096 if (struct_type == struct_erofs_sb_info)
0097 return (unsigned char *)sbi + offset;
0098 if (struct_type == struct_erofs_mount_opts)
0099 return (unsigned char *)&sbi->opt + offset;
0100 return NULL;
0101 }
0102
0103 static ssize_t erofs_attr_show(struct kobject *kobj,
0104 struct attribute *attr, char *buf)
0105 {
0106 struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
0107 s_kobj);
0108 struct erofs_attr *a = container_of(attr, struct erofs_attr, attr);
0109 unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
0110
0111 switch (a->attr_id) {
0112 case attr_feature:
0113 return sysfs_emit(buf, "supported\n");
0114 case attr_pointer_ui:
0115 if (!ptr)
0116 return 0;
0117 return sysfs_emit(buf, "%u\n", *(unsigned int *)ptr);
0118 case attr_pointer_bool:
0119 if (!ptr)
0120 return 0;
0121 return sysfs_emit(buf, "%d\n", *(bool *)ptr);
0122 }
0123 return 0;
0124 }
0125
0126 static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
0127 const char *buf, size_t len)
0128 {
0129 struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
0130 s_kobj);
0131 struct erofs_attr *a = container_of(attr, struct erofs_attr, attr);
0132 unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
0133 unsigned long t;
0134 int ret;
0135
0136 switch (a->attr_id) {
0137 case attr_pointer_ui:
0138 if (!ptr)
0139 return 0;
0140 ret = kstrtoul(skip_spaces(buf), 0, &t);
0141 if (ret)
0142 return ret;
0143 if (t != (unsigned int)t)
0144 return -ERANGE;
0145 #ifdef CONFIG_EROFS_FS_ZIP
0146 if (!strcmp(a->attr.name, "sync_decompress") &&
0147 (t > EROFS_SYNC_DECOMPRESS_FORCE_OFF))
0148 return -EINVAL;
0149 #endif
0150 *(unsigned int *)ptr = t;
0151 return len;
0152 case attr_pointer_bool:
0153 if (!ptr)
0154 return 0;
0155 ret = kstrtoul(skip_spaces(buf), 0, &t);
0156 if (ret)
0157 return ret;
0158 if (t != 0 && t != 1)
0159 return -EINVAL;
0160 *(bool *)ptr = !!t;
0161 return len;
0162 }
0163 return 0;
0164 }
0165
0166 static void erofs_sb_release(struct kobject *kobj)
0167 {
0168 struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
0169 s_kobj);
0170 complete(&sbi->s_kobj_unregister);
0171 }
0172
0173 static const struct sysfs_ops erofs_attr_ops = {
0174 .show = erofs_attr_show,
0175 .store = erofs_attr_store,
0176 };
0177
0178 static struct kobj_type erofs_sb_ktype = {
0179 .default_groups = erofs_groups,
0180 .sysfs_ops = &erofs_attr_ops,
0181 .release = erofs_sb_release,
0182 };
0183
0184 static struct kobj_type erofs_ktype = {
0185 .sysfs_ops = &erofs_attr_ops,
0186 };
0187
0188 static struct kset erofs_root = {
0189 .kobj = {.ktype = &erofs_ktype},
0190 };
0191
0192 static struct kobj_type erofs_feat_ktype = {
0193 .default_groups = erofs_feat_groups,
0194 .sysfs_ops = &erofs_attr_ops,
0195 };
0196
0197 static struct kobject erofs_feat = {
0198 .kset = &erofs_root,
0199 };
0200
0201 int erofs_register_sysfs(struct super_block *sb)
0202 {
0203 struct erofs_sb_info *sbi = EROFS_SB(sb);
0204 int err;
0205
0206 sbi->s_kobj.kset = &erofs_root;
0207 init_completion(&sbi->s_kobj_unregister);
0208 err = kobject_init_and_add(&sbi->s_kobj, &erofs_sb_ktype, NULL, "%s",
0209 erofs_is_fscache_mode(sb) ? sbi->opt.fsid : sb->s_id);
0210 if (err)
0211 goto put_sb_kobj;
0212 return 0;
0213
0214 put_sb_kobj:
0215 kobject_put(&sbi->s_kobj);
0216 wait_for_completion(&sbi->s_kobj_unregister);
0217 return err;
0218 }
0219
0220 void erofs_unregister_sysfs(struct super_block *sb)
0221 {
0222 struct erofs_sb_info *sbi = EROFS_SB(sb);
0223
0224 if (sbi->s_kobj.state_in_sysfs) {
0225 kobject_del(&sbi->s_kobj);
0226 kobject_put(&sbi->s_kobj);
0227 wait_for_completion(&sbi->s_kobj_unregister);
0228 }
0229 }
0230
0231 int __init erofs_init_sysfs(void)
0232 {
0233 int ret;
0234
0235 kobject_set_name(&erofs_root.kobj, "erofs");
0236 erofs_root.kobj.parent = fs_kobj;
0237 ret = kset_register(&erofs_root);
0238 if (ret)
0239 goto root_err;
0240
0241 ret = kobject_init_and_add(&erofs_feat, &erofs_feat_ktype,
0242 NULL, "features");
0243 if (ret)
0244 goto feat_err;
0245 return ret;
0246
0247 feat_err:
0248 kobject_put(&erofs_feat);
0249 kset_unregister(&erofs_root);
0250 root_err:
0251 return ret;
0252 }
0253
0254 void erofs_exit_sysfs(void)
0255 {
0256 kobject_put(&erofs_feat);
0257 kset_unregister(&erofs_root);
0258 }