12e3cbf42SStefan Schaeckeler // SPDX-License-Identifier: GPL-2.0-only 22e3cbf42SStefan Schaeckeler /* 32e3cbf42SStefan Schaeckeler * This file is part of UBIFS. 42e3cbf42SStefan Schaeckeler * 52e3cbf42SStefan Schaeckeler * Copyright (C) 2021 Cisco Systems 62e3cbf42SStefan Schaeckeler * 72e3cbf42SStefan Schaeckeler * Author: Stefan Schaeckeler 82e3cbf42SStefan Schaeckeler */ 92e3cbf42SStefan Schaeckeler 102e3cbf42SStefan Schaeckeler 112e3cbf42SStefan Schaeckeler #include <linux/fs.h> 122e3cbf42SStefan Schaeckeler #include "ubifs.h" 132e3cbf42SStefan Schaeckeler 142e3cbf42SStefan Schaeckeler enum attr_id_t { 152e3cbf42SStefan Schaeckeler attr_errors_magic, 162e3cbf42SStefan Schaeckeler attr_errors_node, 172e3cbf42SStefan Schaeckeler attr_errors_crc, 182e3cbf42SStefan Schaeckeler }; 192e3cbf42SStefan Schaeckeler 202e3cbf42SStefan Schaeckeler struct ubifs_attr { 212e3cbf42SStefan Schaeckeler struct attribute attr; 222e3cbf42SStefan Schaeckeler enum attr_id_t attr_id; 232e3cbf42SStefan Schaeckeler }; 242e3cbf42SStefan Schaeckeler 252e3cbf42SStefan Schaeckeler #define UBIFS_ATTR(_name, _mode, _id) \ 262e3cbf42SStefan Schaeckeler static struct ubifs_attr ubifs_attr_##_name = { \ 272e3cbf42SStefan Schaeckeler .attr = {.name = __stringify(_name), .mode = _mode }, \ 282e3cbf42SStefan Schaeckeler .attr_id = attr_##_id, \ 292e3cbf42SStefan Schaeckeler } 302e3cbf42SStefan Schaeckeler 312e3cbf42SStefan Schaeckeler #define UBIFS_ATTR_FUNC(_name, _mode) UBIFS_ATTR(_name, _mode, _name) 322e3cbf42SStefan Schaeckeler 332e3cbf42SStefan Schaeckeler UBIFS_ATTR_FUNC(errors_magic, 0444); 342e3cbf42SStefan Schaeckeler UBIFS_ATTR_FUNC(errors_crc, 0444); 352e3cbf42SStefan Schaeckeler UBIFS_ATTR_FUNC(errors_node, 0444); 362e3cbf42SStefan Schaeckeler 372e3cbf42SStefan Schaeckeler #define ATTR_LIST(name) (&ubifs_attr_##name.attr) 382e3cbf42SStefan Schaeckeler 392e3cbf42SStefan Schaeckeler static struct attribute *ubifs_attrs[] = { 402e3cbf42SStefan Schaeckeler ATTR_LIST(errors_magic), 412e3cbf42SStefan Schaeckeler ATTR_LIST(errors_node), 422e3cbf42SStefan Schaeckeler ATTR_LIST(errors_crc), 432e3cbf42SStefan Schaeckeler NULL, 442e3cbf42SStefan Schaeckeler }; 45*c6479f19SGreg Kroah-Hartman ATTRIBUTE_GROUPS(ubifs); 462e3cbf42SStefan Schaeckeler 472e3cbf42SStefan Schaeckeler static ssize_t ubifs_attr_show(struct kobject *kobj, 482e3cbf42SStefan Schaeckeler struct attribute *attr, char *buf) 492e3cbf42SStefan Schaeckeler { 502e3cbf42SStefan Schaeckeler struct ubifs_info *sbi = container_of(kobj, struct ubifs_info, 512e3cbf42SStefan Schaeckeler kobj); 522e3cbf42SStefan Schaeckeler 532e3cbf42SStefan Schaeckeler struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr); 542e3cbf42SStefan Schaeckeler 552e3cbf42SStefan Schaeckeler switch (a->attr_id) { 562e3cbf42SStefan Schaeckeler case attr_errors_magic: 572e3cbf42SStefan Schaeckeler return sysfs_emit(buf, "%u\n", sbi->stats->magic_errors); 582e3cbf42SStefan Schaeckeler case attr_errors_node: 592e3cbf42SStefan Schaeckeler return sysfs_emit(buf, "%u\n", sbi->stats->node_errors); 602e3cbf42SStefan Schaeckeler case attr_errors_crc: 612e3cbf42SStefan Schaeckeler return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors); 622e3cbf42SStefan Schaeckeler } 632e3cbf42SStefan Schaeckeler return 0; 642e3cbf42SStefan Schaeckeler }; 652e3cbf42SStefan Schaeckeler 662e3cbf42SStefan Schaeckeler static void ubifs_sb_release(struct kobject *kobj) 672e3cbf42SStefan Schaeckeler { 682e3cbf42SStefan Schaeckeler struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj); 692e3cbf42SStefan Schaeckeler 702e3cbf42SStefan Schaeckeler complete(&c->kobj_unregister); 712e3cbf42SStefan Schaeckeler } 722e3cbf42SStefan Schaeckeler 732e3cbf42SStefan Schaeckeler static const struct sysfs_ops ubifs_attr_ops = { 742e3cbf42SStefan Schaeckeler .show = ubifs_attr_show, 752e3cbf42SStefan Schaeckeler }; 762e3cbf42SStefan Schaeckeler 772e3cbf42SStefan Schaeckeler static struct kobj_type ubifs_sb_ktype = { 78*c6479f19SGreg Kroah-Hartman .default_groups = ubifs_groups, 792e3cbf42SStefan Schaeckeler .sysfs_ops = &ubifs_attr_ops, 802e3cbf42SStefan Schaeckeler .release = ubifs_sb_release, 812e3cbf42SStefan Schaeckeler }; 822e3cbf42SStefan Schaeckeler 832e3cbf42SStefan Schaeckeler static struct kobj_type ubifs_ktype = { 842e3cbf42SStefan Schaeckeler .sysfs_ops = &ubifs_attr_ops, 852e3cbf42SStefan Schaeckeler }; 862e3cbf42SStefan Schaeckeler 872e3cbf42SStefan Schaeckeler static struct kset ubifs_kset = { 882e3cbf42SStefan Schaeckeler .kobj = {.ktype = &ubifs_ktype}, 892e3cbf42SStefan Schaeckeler }; 902e3cbf42SStefan Schaeckeler 912e3cbf42SStefan Schaeckeler int ubifs_sysfs_register(struct ubifs_info *c) 922e3cbf42SStefan Schaeckeler { 932e3cbf42SStefan Schaeckeler int ret, n; 942e3cbf42SStefan Schaeckeler char dfs_dir_name[UBIFS_DFS_DIR_LEN+1]; 952e3cbf42SStefan Schaeckeler 962e3cbf42SStefan Schaeckeler c->stats = kzalloc(sizeof(struct ubifs_stats_info), GFP_KERNEL); 972e3cbf42SStefan Schaeckeler if (!c->stats) { 982e3cbf42SStefan Schaeckeler ret = -ENOMEM; 992e3cbf42SStefan Schaeckeler goto out_last; 1002e3cbf42SStefan Schaeckeler } 1012e3cbf42SStefan Schaeckeler n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, 1022e3cbf42SStefan Schaeckeler c->vi.ubi_num, c->vi.vol_id); 1032e3cbf42SStefan Schaeckeler 104d3de970bSDan Carpenter if (n > UBIFS_DFS_DIR_LEN) { 1052e3cbf42SStefan Schaeckeler /* The array size is too small */ 1062e3cbf42SStefan Schaeckeler ret = -EINVAL; 1072e3cbf42SStefan Schaeckeler goto out_free; 1082e3cbf42SStefan Schaeckeler } 1092e3cbf42SStefan Schaeckeler 1102e3cbf42SStefan Schaeckeler c->kobj.kset = &ubifs_kset; 1112e3cbf42SStefan Schaeckeler init_completion(&c->kobj_unregister); 1122e3cbf42SStefan Schaeckeler 1132e3cbf42SStefan Schaeckeler ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL, 1142e3cbf42SStefan Schaeckeler "%s", dfs_dir_name); 1152e3cbf42SStefan Schaeckeler if (ret) 1162e3cbf42SStefan Schaeckeler goto out_put; 1172e3cbf42SStefan Schaeckeler 1182e3cbf42SStefan Schaeckeler return 0; 1192e3cbf42SStefan Schaeckeler 1202e3cbf42SStefan Schaeckeler out_put: 1212e3cbf42SStefan Schaeckeler kobject_put(&c->kobj); 1222e3cbf42SStefan Schaeckeler wait_for_completion(&c->kobj_unregister); 1232e3cbf42SStefan Schaeckeler out_free: 1242e3cbf42SStefan Schaeckeler kfree(c->stats); 1252e3cbf42SStefan Schaeckeler out_last: 1262e3cbf42SStefan Schaeckeler ubifs_err(c, "cannot create sysfs entry for ubifs%d_%d, error %d\n", 1272e3cbf42SStefan Schaeckeler c->vi.ubi_num, c->vi.vol_id, ret); 1282e3cbf42SStefan Schaeckeler return ret; 1292e3cbf42SStefan Schaeckeler } 1302e3cbf42SStefan Schaeckeler 1312e3cbf42SStefan Schaeckeler void ubifs_sysfs_unregister(struct ubifs_info *c) 1322e3cbf42SStefan Schaeckeler { 1332e3cbf42SStefan Schaeckeler kobject_del(&c->kobj); 1342e3cbf42SStefan Schaeckeler kobject_put(&c->kobj); 1352e3cbf42SStefan Schaeckeler wait_for_completion(&c->kobj_unregister); 1362e3cbf42SStefan Schaeckeler 1372e3cbf42SStefan Schaeckeler kfree(c->stats); 1382e3cbf42SStefan Schaeckeler } 1392e3cbf42SStefan Schaeckeler 1402e3cbf42SStefan Schaeckeler int __init ubifs_sysfs_init(void) 1412e3cbf42SStefan Schaeckeler { 1422e3cbf42SStefan Schaeckeler int ret; 1432e3cbf42SStefan Schaeckeler 1442e3cbf42SStefan Schaeckeler kobject_set_name(&ubifs_kset.kobj, "ubifs"); 1452e3cbf42SStefan Schaeckeler ubifs_kset.kobj.parent = fs_kobj; 1462e3cbf42SStefan Schaeckeler ret = kset_register(&ubifs_kset); 1472e3cbf42SStefan Schaeckeler 1482e3cbf42SStefan Schaeckeler return ret; 1492e3cbf42SStefan Schaeckeler } 1502e3cbf42SStefan Schaeckeler 1512e3cbf42SStefan Schaeckeler void ubifs_sysfs_exit(void) 1522e3cbf42SStefan Schaeckeler { 1532e3cbf42SStefan Schaeckeler kset_unregister(&ubifs_kset); 1542e3cbf42SStefan Schaeckeler } 155