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 ATTRIBUTE_GROUPS(ubifs); 46 47 static ssize_t ubifs_attr_show(struct kobject *kobj, 48 struct attribute *attr, char *buf) 49 { 50 struct ubifs_info *sbi = container_of(kobj, struct ubifs_info, 51 kobj); 52 53 struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr); 54 55 switch (a->attr_id) { 56 case attr_errors_magic: 57 return sysfs_emit(buf, "%u\n", sbi->stats->magic_errors); 58 case attr_errors_node: 59 return sysfs_emit(buf, "%u\n", sbi->stats->node_errors); 60 case attr_errors_crc: 61 return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors); 62 } 63 return 0; 64 }; 65 66 static void ubifs_sb_release(struct kobject *kobj) 67 { 68 struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj); 69 70 complete(&c->kobj_unregister); 71 } 72 73 static const struct sysfs_ops ubifs_attr_ops = { 74 .show = ubifs_attr_show, 75 }; 76 77 static struct kobj_type ubifs_sb_ktype = { 78 .default_groups = ubifs_groups, 79 .sysfs_ops = &ubifs_attr_ops, 80 .release = ubifs_sb_release, 81 }; 82 83 static struct kobj_type ubifs_ktype = { 84 .sysfs_ops = &ubifs_attr_ops, 85 }; 86 87 static struct kset ubifs_kset = { 88 .kobj = {.ktype = &ubifs_ktype}, 89 }; 90 91 int ubifs_sysfs_register(struct ubifs_info *c) 92 { 93 int ret, n; 94 char dfs_dir_name[UBIFS_DFS_DIR_LEN+1]; 95 96 c->stats = kzalloc(sizeof(struct ubifs_stats_info), GFP_KERNEL); 97 if (!c->stats) { 98 ret = -ENOMEM; 99 goto out_last; 100 } 101 n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, 102 c->vi.ubi_num, c->vi.vol_id); 103 104 if (n > UBIFS_DFS_DIR_LEN) { 105 /* The array size is too small */ 106 ret = -EINVAL; 107 goto out_free; 108 } 109 110 c->kobj.kset = &ubifs_kset; 111 init_completion(&c->kobj_unregister); 112 113 ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL, 114 "%s", dfs_dir_name); 115 if (ret) 116 goto out_put; 117 118 return 0; 119 120 out_put: 121 kobject_put(&c->kobj); 122 wait_for_completion(&c->kobj_unregister); 123 out_free: 124 kfree(c->stats); 125 out_last: 126 ubifs_err(c, "cannot create sysfs entry for ubifs%d_%d, error %d\n", 127 c->vi.ubi_num, c->vi.vol_id, ret); 128 return ret; 129 } 130 131 void ubifs_sysfs_unregister(struct ubifs_info *c) 132 { 133 kobject_del(&c->kobj); 134 kobject_put(&c->kobj); 135 wait_for_completion(&c->kobj_unregister); 136 137 kfree(c->stats); 138 } 139 140 int __init ubifs_sysfs_init(void) 141 { 142 int ret; 143 144 kobject_set_name(&ubifs_kset.kobj, "ubifs"); 145 ubifs_kset.kobj.parent = fs_kobj; 146 ret = kset_register(&ubifs_kset); 147 148 return ret; 149 } 150 151 void ubifs_sysfs_exit(void) 152 { 153 kset_unregister(&ubifs_kset); 154 } 155