sysfs.c (3270B)
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 14enum attr_id_t { 15 attr_errors_magic, 16 attr_errors_node, 17 attr_errors_crc, 18}; 19 20struct ubifs_attr { 21 struct attribute attr; 22 enum attr_id_t attr_id; 23}; 24 25#define UBIFS_ATTR(_name, _mode, _id) \ 26static 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 33UBIFS_ATTR_FUNC(errors_magic, 0444); 34UBIFS_ATTR_FUNC(errors_crc, 0444); 35UBIFS_ATTR_FUNC(errors_node, 0444); 36 37#define ATTR_LIST(name) (&ubifs_attr_##name.attr) 38 39static struct attribute *ubifs_attrs[] = { 40 ATTR_LIST(errors_magic), 41 ATTR_LIST(errors_node), 42 ATTR_LIST(errors_crc), 43 NULL, 44}; 45ATTRIBUTE_GROUPS(ubifs); 46 47static 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 66static 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 73static const struct sysfs_ops ubifs_attr_ops = { 74 .show = ubifs_attr_show, 75}; 76 77static struct kobj_type ubifs_sb_ktype = { 78 .default_groups = ubifs_groups, 79 .sysfs_ops = &ubifs_attr_ops, 80 .release = ubifs_sb_release, 81}; 82 83static struct kobj_type ubifs_ktype = { 84 .sysfs_ops = &ubifs_attr_ops, 85}; 86 87static struct kset ubifs_kset = { 88 .kobj = {.ktype = &ubifs_ktype}, 89}; 90 91int 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 120out_put: 121 kobject_put(&c->kobj); 122 wait_for_completion(&c->kobj_unregister); 123out_free: 124 kfree(c->stats); 125out_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 131void 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 140int __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 151void ubifs_sysfs_exit(void) 152{ 153 kset_unregister(&ubifs_kset); 154}