Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C), 2008-2021, OPPO Mobile Comm Corp., Ltd.
0004  *             https://www.oppo.com/
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 /* Features this copy of erofs supports */
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 }