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