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 }; 452e3cbf42SStefan Schaeckeler 462e3cbf42SStefan Schaeckeler static ssize_t ubifs_attr_show(struct kobject *kobj, 472e3cbf42SStefan Schaeckeler struct attribute *attr, char *buf) 482e3cbf42SStefan Schaeckeler { 492e3cbf42SStefan Schaeckeler struct ubifs_info *sbi = container_of(kobj, struct ubifs_info, 502e3cbf42SStefan Schaeckeler kobj); 512e3cbf42SStefan Schaeckeler 522e3cbf42SStefan Schaeckeler struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr); 532e3cbf42SStefan Schaeckeler 542e3cbf42SStefan Schaeckeler switch (a->attr_id) { 552e3cbf42SStefan Schaeckeler case attr_errors_magic: 562e3cbf42SStefan Schaeckeler return sysfs_emit(buf, "%u\n", sbi->stats->magic_errors); 572e3cbf42SStefan Schaeckeler case attr_errors_node: 582e3cbf42SStefan Schaeckeler return sysfs_emit(buf, "%u\n", sbi->stats->node_errors); 592e3cbf42SStefan Schaeckeler case attr_errors_crc: 602e3cbf42SStefan Schaeckeler return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors); 612e3cbf42SStefan Schaeckeler } 622e3cbf42SStefan Schaeckeler return 0; 632e3cbf42SStefan Schaeckeler }; 642e3cbf42SStefan Schaeckeler 652e3cbf42SStefan Schaeckeler static void ubifs_sb_release(struct kobject *kobj) 662e3cbf42SStefan Schaeckeler { 672e3cbf42SStefan Schaeckeler struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj); 682e3cbf42SStefan Schaeckeler 692e3cbf42SStefan Schaeckeler complete(&c->kobj_unregister); 702e3cbf42SStefan Schaeckeler } 712e3cbf42SStefan Schaeckeler 722e3cbf42SStefan Schaeckeler static const struct sysfs_ops ubifs_attr_ops = { 732e3cbf42SStefan Schaeckeler .show = ubifs_attr_show, 742e3cbf42SStefan Schaeckeler }; 752e3cbf42SStefan Schaeckeler 762e3cbf42SStefan Schaeckeler static struct kobj_type ubifs_sb_ktype = { 772e3cbf42SStefan Schaeckeler .default_attrs = ubifs_attrs, 782e3cbf42SStefan Schaeckeler .sysfs_ops = &ubifs_attr_ops, 792e3cbf42SStefan Schaeckeler .release = ubifs_sb_release, 802e3cbf42SStefan Schaeckeler }; 812e3cbf42SStefan Schaeckeler 822e3cbf42SStefan Schaeckeler static struct kobj_type ubifs_ktype = { 832e3cbf42SStefan Schaeckeler .sysfs_ops = &ubifs_attr_ops, 842e3cbf42SStefan Schaeckeler }; 852e3cbf42SStefan Schaeckeler 862e3cbf42SStefan Schaeckeler static struct kset ubifs_kset = { 872e3cbf42SStefan Schaeckeler .kobj = {.ktype = &ubifs_ktype}, 882e3cbf42SStefan Schaeckeler }; 892e3cbf42SStefan Schaeckeler 902e3cbf42SStefan Schaeckeler int ubifs_sysfs_register(struct ubifs_info *c) 912e3cbf42SStefan Schaeckeler { 922e3cbf42SStefan Schaeckeler int ret, n; 932e3cbf42SStefan Schaeckeler char dfs_dir_name[UBIFS_DFS_DIR_LEN+1]; 942e3cbf42SStefan Schaeckeler 952e3cbf42SStefan Schaeckeler c->stats = kzalloc(sizeof(struct ubifs_stats_info), GFP_KERNEL); 962e3cbf42SStefan Schaeckeler if (!c->stats) { 972e3cbf42SStefan Schaeckeler ret = -ENOMEM; 982e3cbf42SStefan Schaeckeler goto out_last; 992e3cbf42SStefan Schaeckeler } 1002e3cbf42SStefan Schaeckeler n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, 1012e3cbf42SStefan Schaeckeler c->vi.ubi_num, c->vi.vol_id); 1022e3cbf42SStefan Schaeckeler 103*d3de970bSDan Carpenter if (n > UBIFS_DFS_DIR_LEN) { 1042e3cbf42SStefan Schaeckeler /* The array size is too small */ 1052e3cbf42SStefan Schaeckeler ret = -EINVAL; 1062e3cbf42SStefan Schaeckeler goto out_free; 1072e3cbf42SStefan Schaeckeler } 1082e3cbf42SStefan Schaeckeler 1092e3cbf42SStefan Schaeckeler c->kobj.kset = &ubifs_kset; 1102e3cbf42SStefan Schaeckeler init_completion(&c->kobj_unregister); 1112e3cbf42SStefan Schaeckeler 1122e3cbf42SStefan Schaeckeler ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL, 1132e3cbf42SStefan Schaeckeler "%s", dfs_dir_name); 1142e3cbf42SStefan Schaeckeler if (ret) 1152e3cbf42SStefan Schaeckeler goto out_put; 1162e3cbf42SStefan Schaeckeler 1172e3cbf42SStefan Schaeckeler return 0; 1182e3cbf42SStefan Schaeckeler 1192e3cbf42SStefan Schaeckeler out_put: 1202e3cbf42SStefan Schaeckeler kobject_put(&c->kobj); 1212e3cbf42SStefan Schaeckeler wait_for_completion(&c->kobj_unregister); 1222e3cbf42SStefan Schaeckeler out_free: 1232e3cbf42SStefan Schaeckeler kfree(c->stats); 1242e3cbf42SStefan Schaeckeler out_last: 1252e3cbf42SStefan Schaeckeler ubifs_err(c, "cannot create sysfs entry for ubifs%d_%d, error %d\n", 1262e3cbf42SStefan Schaeckeler c->vi.ubi_num, c->vi.vol_id, ret); 1272e3cbf42SStefan Schaeckeler return ret; 1282e3cbf42SStefan Schaeckeler } 1292e3cbf42SStefan Schaeckeler 1302e3cbf42SStefan Schaeckeler void ubifs_sysfs_unregister(struct ubifs_info *c) 1312e3cbf42SStefan Schaeckeler { 1322e3cbf42SStefan Schaeckeler kobject_del(&c->kobj); 1332e3cbf42SStefan Schaeckeler kobject_put(&c->kobj); 1342e3cbf42SStefan Schaeckeler wait_for_completion(&c->kobj_unregister); 1352e3cbf42SStefan Schaeckeler 1362e3cbf42SStefan Schaeckeler kfree(c->stats); 1372e3cbf42SStefan Schaeckeler } 1382e3cbf42SStefan Schaeckeler 1392e3cbf42SStefan Schaeckeler int __init ubifs_sysfs_init(void) 1402e3cbf42SStefan Schaeckeler { 1412e3cbf42SStefan Schaeckeler int ret; 1422e3cbf42SStefan Schaeckeler 1432e3cbf42SStefan Schaeckeler kobject_set_name(&ubifs_kset.kobj, "ubifs"); 1442e3cbf42SStefan Schaeckeler ubifs_kset.kobj.parent = fs_kobj; 1452e3cbf42SStefan Schaeckeler ret = kset_register(&ubifs_kset); 1462e3cbf42SStefan Schaeckeler 1472e3cbf42SStefan Schaeckeler return ret; 1482e3cbf42SStefan Schaeckeler } 1492e3cbf42SStefan Schaeckeler 1502e3cbf42SStefan Schaeckeler void ubifs_sysfs_exit(void) 1512e3cbf42SStefan Schaeckeler { 1522e3cbf42SStefan Schaeckeler kset_unregister(&ubifs_kset); 1532e3cbf42SStefan Schaeckeler } 154