Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ubifs: Export filesystem error counters

Not all ubifs filesystem errors are propagated to userspace.

Export bad magic, bad node and crc errors via sysfs. This allows userspace
to notice filesystem errors:

/sys/fs/ubifs/ubiX_Y/errors_magic
/sys/fs/ubifs/ubiX_Y/errors_node
/sys/fs/ubifs/ubiX_Y/errors_crc

The counters are reset to 0 with a remount.

Signed-off-by: Stefan Schaeckeler <sschaeck@cisco.com>
Signed-off-by: Richard Weinberger <richard@nod.at>

authored by

Stefan Schaeckeler and committed by
Richard Weinberger
2e3cbf42 3fea4d9d

+225 -2
+1 -1
fs/ubifs/Makefile
··· 5 5 ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o 6 6 ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o 7 7 ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o 8 - ubifs-y += misc.o 8 + ubifs-y += misc.o sysfs.o 9 9 ubifs-$(CONFIG_FS_ENCRYPTION) += crypto.o 10 10 ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o 11 11 ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o
+21
fs/ubifs/io.c
··· 194 194 return err; 195 195 } 196 196 197 + static void record_magic_error(struct ubifs_stats_info *stats) 198 + { 199 + if (stats) 200 + stats->magic_errors++; 201 + } 202 + 203 + static void record_node_error(struct ubifs_stats_info *stats) 204 + { 205 + if (stats) 206 + stats->node_errors++; 207 + } 208 + 209 + static void record_crc_error(struct ubifs_stats_info *stats) 210 + { 211 + if (stats) 212 + stats->crc_errors++; 213 + } 214 + 197 215 /** 198 216 * ubifs_check_node - check node. 199 217 * @c: UBIFS file-system description object ··· 256 238 if (!quiet) 257 239 ubifs_err(c, "bad magic %#08x, expected %#08x", 258 240 magic, UBIFS_NODE_MAGIC); 241 + record_magic_error(c->stats); 259 242 err = -EUCLEAN; 260 243 goto out; 261 244 } ··· 265 246 if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) { 266 247 if (!quiet) 267 248 ubifs_err(c, "bad node type %d", type); 249 + record_node_error(c->stats); 268 250 goto out; 269 251 } 270 252 ··· 290 270 if (!quiet) 291 271 ubifs_err(c, "bad CRC: calculated %#08x, read %#08x", 292 272 crc, node_crc); 273 + record_crc_error(c->stats); 293 274 err = -EUCLEAN; 294 275 goto out; 295 276 }
+15 -1
fs/ubifs/super.c
··· 1264 1264 if (err) 1265 1265 return err; 1266 1266 1267 + err = ubifs_sysfs_register(c); 1268 + if (err) 1269 + goto out_debugging; 1270 + 1267 1271 err = check_volume_empty(c); 1268 1272 if (err) 1269 1273 goto out_free; ··· 1644 1640 vfree(c->sbuf); 1645 1641 kfree(c->bottom_up_buf); 1646 1642 kfree(c->sup_node); 1643 + ubifs_sysfs_unregister(c); 1644 + out_debugging: 1647 1645 ubifs_debugging_exit(c); 1648 1646 return err; 1649 1647 } ··· 1689 1683 kfree(c->bottom_up_buf); 1690 1684 kfree(c->sup_node); 1691 1685 ubifs_debugging_exit(c); 1686 + ubifs_sysfs_unregister(c); 1692 1687 } 1693 1688 1694 1689 /** ··· 2440 2433 2441 2434 dbg_debugfs_init(); 2442 2435 2436 + err = ubifs_sysfs_init(); 2437 + if (err) 2438 + goto out_dbg; 2439 + 2443 2440 err = register_filesystem(&ubifs_fs_type); 2444 2441 if (err) { 2445 2442 pr_err("UBIFS error (pid %d): cannot register file system, error %d", 2446 2443 current->pid, err); 2447 - goto out_dbg; 2444 + goto out_sysfs; 2448 2445 } 2449 2446 return 0; 2450 2447 2448 + out_sysfs: 2449 + ubifs_sysfs_exit(); 2451 2450 out_dbg: 2452 2451 dbg_debugfs_exit(); 2453 2452 ubifs_compressors_exit(); ··· 2472 2459 WARN_ON(atomic_long_read(&ubifs_clean_zn_cnt) != 0); 2473 2460 2474 2461 dbg_debugfs_exit(); 2462 + ubifs_sysfs_exit(); 2475 2463 ubifs_compressors_exit(); 2476 2464 unregister_shrinker(&ubifs_shrinker_info); 2477 2465
+153
fs/ubifs/sysfs.c
··· 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 + }
+35
fs/ubifs/ubifs.h
··· 27 27 #include <linux/security.h> 28 28 #include <linux/xattr.h> 29 29 #include <linux/random.h> 30 + #include <linux/sysfs.h> 31 + #include <linux/completion.h> 30 32 #include <crypto/hash_info.h> 31 33 #include <crypto/hash.h> 32 34 #include <crypto/algapi.h> ··· 156 154 #define UBIFS_HASH_ARR_SZ 0 157 155 #define UBIFS_HMAC_ARR_SZ 0 158 156 #endif 157 + 158 + /* 159 + * The UBIFS sysfs directory name pattern and maximum name length (3 for "ubi" 160 + * + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte. 161 + */ 162 + #define UBIFS_DFS_DIR_NAME "ubi%d_%d" 163 + #define UBIFS_DFS_DIR_LEN (3 + 1 + 2*2 + 1) 159 164 160 165 /* 161 166 * Lockdep classes for UBIFS inode @ui_mutex. ··· 999 990 int dent_budget; 1000 991 }; 1001 992 993 + /** 994 + * ubifs_stats_info - per-FS statistics information. 995 + * @magic_errors: number of bad magic numbers (will be reset with a new mount). 996 + * @node_errors: number of bad nodes (will be reset with a new mount). 997 + * @crc_errors: number of bad crcs (will be reset with a new mount). 998 + */ 999 + struct ubifs_stats_info { 1000 + unsigned int magic_errors; 1001 + unsigned int node_errors; 1002 + unsigned int crc_errors; 1003 + }; 1004 + 1002 1005 struct ubifs_debug_info; 1003 1006 1004 1007 /** ··· 1272 1251 * @mount_opts: UBIFS-specific mount options 1273 1252 * 1274 1253 * @dbg: debugging-related information 1254 + * @stats: statistics exported over sysfs 1255 + * 1256 + * @kobj: kobject for /sys/fs/ubifs/ 1257 + * @kobj_unregister: completion to unregister sysfs kobject 1275 1258 */ 1276 1259 struct ubifs_info { 1277 1260 struct super_block *vfs_sb; ··· 1310 1285 int cmt_state; 1311 1286 spinlock_t cs_lock; 1312 1287 wait_queue_head_t cmt_wq; 1288 + 1289 + struct kobject kobj; 1290 + struct completion kobj_unregister; 1313 1291 1314 1292 unsigned int big_lpt:1; 1315 1293 unsigned int space_fixup:1; ··· 1521 1493 struct ubifs_mount_opts mount_opts; 1522 1494 1523 1495 struct ubifs_debug_info *dbg; 1496 + struct ubifs_stats_info *stats; 1524 1497 }; 1525 1498 1526 1499 extern struct list_head ubifs_infos; ··· 2100 2071 void *out_buf, int *out_len, int *compr_type); 2101 2072 int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, 2102 2073 void *out, int *out_len, int compr_type); 2074 + 2075 + /* sysfs.c */ 2076 + int ubifs_sysfs_init(void); 2077 + void ubifs_sysfs_exit(void); 2078 + int ubifs_sysfs_register(struct ubifs_info *c); 2079 + void ubifs_sysfs_unregister(struct ubifs_info *c); 2103 2080 2104 2081 #include "debug.h" 2105 2082 #include "misc.h"