// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of UBIFS. * * Copyright (C) 2006-2008 Nokia Corporation * * Authors: Artem Bityutskiy (Битюцкий Артём) * Adrian Hunter */ /* * This file implements most of the debugging stuff which is compiled in only * when it is enabled. But some debugging check functions are implemented in * corresponding subsystem, just because they are closely related and utilize * various local functions of those subsystems. */ #include <linux/module.h> #include <linux/debugfs.h> #include <linux/math64.h> #include <linux/uaccess.h> #include <linux/random.h> #include <linux/ctype.h> #include "ubifs.h" static DEFINE_SPINLOCK(dbg_lock); static const char *get_key_fmt(int fmt) { … } static const char *get_key_hash(int hash) { … } static const char *get_key_type(int type) { … } static const char *get_dent_type(int type) { … } const char *dbg_snprintf_key(const struct ubifs_info *c, const union ubifs_key *key, char *buffer, int len) { … } const char *dbg_ntype(int type) { … } static const char *dbg_gtype(int type) { … } const char *dbg_cstate(int cmt_state) { … } const char *dbg_jhead(int jhead) { … } static void dump_ch(const struct ubifs_ch *ch) { … } void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode) { … } void ubifs_dump_node(const struct ubifs_info *c, const void *node, int node_len) { … } void ubifs_dump_budget_req(const struct ubifs_budget_req *req) { … } void ubifs_dump_lstats(const struct ubifs_lp_stats *lst) { … } void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi) { … } void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp) { … } void ubifs_dump_lprops(struct ubifs_info *c) { … } void ubifs_dump_lpt_info(struct ubifs_info *c) { … } void ubifs_dump_leb(const struct ubifs_info *c, int lnum) { … } void ubifs_dump_znode(const struct ubifs_info *c, const struct ubifs_znode *znode) { … } void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) { … } void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, struct ubifs_nnode *parent, int iip) { … } void ubifs_dump_tnc(struct ubifs_info *c) { … } static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode, void *priv) { … } /** * ubifs_dump_index - dump the on-flash index. * @c: UBIFS file-system description object * * This function dumps whole UBIFS indexing B-tree, unlike 'ubifs_dump_tnc()' * which dumps only in-memory znodes and does not read znodes which from flash. */ void ubifs_dump_index(struct ubifs_info *c) { … } /** * dbg_save_space_info - save information about flash space. * @c: UBIFS file-system description object * * This function saves information about UBIFS free space, dirty space, etc, in * order to check it later. */ void dbg_save_space_info(struct ubifs_info *c) { … } /** * dbg_check_space_info - check flash space information. * @c: UBIFS file-system description object * * This function compares current flash space information with the information * which was saved when the 'dbg_save_space_info()' function was called. * Returns zero if the information has not changed, and %-EINVAL if it has * changed. */ int dbg_check_space_info(struct ubifs_info *c) { … } /** * dbg_check_synced_i_size - check synchronized inode size. * @c: UBIFS file-system description object * @inode: inode to check * * If inode is clean, synchronized inode size has to be equivalent to current * inode size. This function has to be called only for locked inodes (@i_mutex * has to be locked). Returns %0 if synchronized inode size if correct, and * %-EINVAL if not. */ int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode) { … } /* * dbg_check_dir - check directory inode size and link count. * @c: UBIFS file-system description object * @dir: the directory to calculate size for * @size: the result is returned here * * This function makes sure that directory size and link count are correct. * Returns zero in case of success and a negative error code in case of * failure. * * Note, it is good idea to make sure the @dir->i_mutex is locked before * calling this function. */ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) { … } /** * dbg_check_key_order - make sure that colliding keys are properly ordered. * @c: UBIFS file-system description object * @zbr1: first zbranch * @zbr2: following zbranch * * In UBIFS indexing B-tree colliding keys has to be sorted in binary order of * names of the direntries/xentries which are referred by the keys. This * function reads direntries/xentries referred by @zbr1 and @zbr2 and makes * sure the name of direntry/xentry referred by @zbr1 is less than * direntry/xentry referred by @zbr2. Returns zero if this is true, %1 if not, * and a negative error code in case of failure. */ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, struct ubifs_zbranch *zbr2) { … } /** * dbg_check_znode - check if znode is all right. * @c: UBIFS file-system description object * @zbr: zbranch which points to this znode * * This function makes sure that znode referred to by @zbr is all right. * Returns zero if it is, and %-EINVAL if it is not. */ static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr) { … } /** * dbg_check_tnc - check TNC tree. * @c: UBIFS file-system description object * @extra: do extra checks that are possible at start commit * * This function traverses whole TNC tree and checks every znode. Returns zero * if everything is all right and %-EINVAL if something is wrong with TNC. */ int dbg_check_tnc(struct ubifs_info *c, int extra) { … } /** * dbg_walk_index - walk the on-flash index. * @c: UBIFS file-system description object * @leaf_cb: called for each leaf node * @znode_cb: called for each indexing node * @priv: private data which is passed to callbacks * * This function walks the UBIFS index and calls the @leaf_cb for each leaf * node and @znode_cb for each indexing node. Returns zero in case of success * and a negative error code in case of failure. * * It would be better if this function removed every znode it pulled to into * the TNC, so that the behavior more closely matched the non-debugging * behavior. */ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, dbg_znode_callback znode_cb, void *priv) { … } /** * add_size - add znode size to partially calculated index size. * @c: UBIFS file-system description object * @znode: znode to add size for * @priv: partially calculated index size * * This is a helper function for 'dbg_check_idx_size()' which is called for * every indexing node and adds its size to the 'long long' variable pointed to * by @priv. */ static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv) { … } /** * dbg_check_idx_size - check index size. * @c: UBIFS file-system description object * @idx_size: size to check * * This function walks the UBIFS index, calculates its size and checks that the * size is equivalent to @idx_size. Returns zero in case of success and a * negative error code in case of failure. */ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size) { … } /** * struct fsck_inode - information about an inode used when checking the file-system. * @rb: link in the RB-tree of inodes * @inum: inode number * @mode: inode type, permissions, etc * @nlink: inode link count * @xattr_cnt: count of extended attributes * @references: how many directory/xattr entries refer this inode (calculated * while walking the index) * @calc_cnt: for directory inode count of child directories * @size: inode size (read from on-flash inode) * @xattr_sz: summary size of all extended attributes (read from on-flash * inode) * @calc_sz: for directories calculated directory size * @calc_xcnt: count of extended attributes * @calc_xsz: calculated summary size of all extended attributes * @xattr_nms: sum of lengths of all extended attribute names belonging to this * inode (read from on-flash inode) * @calc_xnms: calculated sum of lengths of all extended attribute names */ struct fsck_inode { … }; /** * struct fsck_data - private FS checking information. * @inodes: RB-tree of all inodes (contains @struct fsck_inode objects) */ struct fsck_data { … }; /** * add_inode - add inode information to RB-tree of inodes. * @c: UBIFS file-system description object * @fsckd: FS checking information * @ino: raw UBIFS inode to add * * This is a helper function for 'check_leaf()' which adds information about * inode @ino to the RB-tree of inodes. Returns inode information pointer in * case of success and a negative error code in case of failure. */ static struct fsck_inode *add_inode(struct ubifs_info *c, struct fsck_data *fsckd, struct ubifs_ino_node *ino) { … } /** * search_inode - search inode in the RB-tree of inodes. * @fsckd: FS checking information * @inum: inode number to search * * This is a helper function for 'check_leaf()' which searches inode @inum in * the RB-tree of inodes and returns an inode information pointer or %NULL if * the inode was not found. */ static struct fsck_inode *search_inode(struct fsck_data *fsckd, ino_t inum) { … } /** * read_add_inode - read inode node and add it to RB-tree of inodes. * @c: UBIFS file-system description object * @fsckd: FS checking information * @inum: inode number to read * * This is a helper function for 'check_leaf()' which finds inode node @inum in * the index, reads it, and adds it to the RB-tree of inodes. Returns inode * information pointer in case of success and a negative error code in case of * failure. */ static struct fsck_inode *read_add_inode(struct ubifs_info *c, struct fsck_data *fsckd, ino_t inum) { … } /** * check_leaf - check leaf node. * @c: UBIFS file-system description object * @zbr: zbranch of the leaf node to check * @priv: FS checking information * * This is a helper function for 'dbg_check_filesystem()' which is called for * every single leaf node while walking the indexing tree. It checks that the * leaf node referred from the indexing tree exists, has correct CRC, and does * some other basic validation. This function is also responsible for building * an RB-tree of inodes - it adds all inodes into the RB-tree. It also * calculates reference count, size, etc for each inode in order to later * compare them to the information stored inside the inodes and detect possible * inconsistencies. Returns zero in case of success and a negative error code * in case of failure. */ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, void *priv) { … } /** * free_inodes - free RB-tree of inodes. * @fsckd: FS checking information */ static void free_inodes(struct fsck_data *fsckd) { … } /** * check_inodes - checks all inodes. * @c: UBIFS file-system description object * @fsckd: FS checking information * * This is a helper function for 'dbg_check_filesystem()' which walks the * RB-tree of inodes after the index scan has been finished, and checks that * inode nlink, size, etc are correct. Returns zero if inodes are fine, * %-EINVAL if not, and a negative error code in case of failure. */ static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd) { … } /** * dbg_check_filesystem - check the file-system. * @c: UBIFS file-system description object * * This function checks the file system, namely: * o makes sure that all leaf nodes exist and their CRCs are correct; * o makes sure inode nlink, size, xattr size/count are correct (for all * inodes). * * The function reads whole indexing tree and all nodes, so it is pretty * heavy-weight. Returns zero if the file-system is consistent, %-EINVAL if * not, and a negative error code in case of failure. */ int dbg_check_filesystem(struct ubifs_info *c) { … } /** * dbg_check_data_nodes_order - check that list of data nodes is sorted. * @c: UBIFS file-system description object * @head: the list of nodes ('struct ubifs_scan_node' objects) * * This function returns zero if the list of data nodes is sorted correctly, * and %-EINVAL if not. */ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head) { … } /** * dbg_check_nondata_nodes_order - check that list of data nodes is sorted. * @c: UBIFS file-system description object * @head: the list of nodes ('struct ubifs_scan_node' objects) * * This function returns zero if the list of non-data nodes is sorted correctly, * and %-EINVAL if not. */ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) { … } static inline int chance(unsigned int n, unsigned int out_of) { … } static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) { … } static int corrupt_data(const struct ubifs_info *c, const void *buf, unsigned int len) { … } int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs, int len) { … } int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len) { … } int dbg_leb_unmap(struct ubifs_info *c, int lnum) { … } int dbg_leb_map(struct ubifs_info *c, int lnum) { … } /* * Root directory for UBIFS stuff in debugfs. Contains sub-directories which * contain the stuff specific to particular file-system mounts. */ static struct dentry *dfs_rootdir; static int dfs_file_open(struct inode *inode, struct file *file) { … } /** * provide_user_output - provide output to the user reading a debugfs file. * @val: boolean value for the answer * @u: the buffer to store the answer at * @count: size of the buffer * @ppos: position in the @u output buffer * * This is a simple helper function which stores @val boolean value in the user * buffer when the user reads one of UBIFS debugfs files. Returns amount of * bytes written to @u in case of success and a negative error code in case of * failure. */ static int provide_user_output(int val, char __user *u, size_t count, loff_t *ppos) { … } static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count, loff_t *ppos) { … } /** * interpret_user_input - interpret user debugfs file input. * @u: user-provided buffer with the input * @count: buffer size * * This is a helper function which interpret user input to a boolean UBIFS * debugfs file. Returns %0 or %1 in case of success and a negative error code * in case of failure. */ static int interpret_user_input(const char __user *u, size_t count) { … } static ssize_t dfs_file_write(struct file *file, const char __user *u, size_t count, loff_t *ppos) { … } static const struct file_operations dfs_fops = …; /** * dbg_debugfs_init_fs - initialize debugfs for UBIFS instance. * @c: UBIFS file-system description object * * This function creates all debugfs files for this instance of UBIFS. * * Note, the only reason we have not merged this function with the * 'ubifs_debugging_init()' function is because it is better to initialize * debugfs interfaces at the very end of the mount process, and remove them at * the very beginning of the mount process. */ void dbg_debugfs_init_fs(struct ubifs_info *c) { … } /** * dbg_debugfs_exit_fs - remove all debugfs files. * @c: UBIFS file-system description object */ void dbg_debugfs_exit_fs(struct ubifs_info *c) { … } struct ubifs_global_debug_info ubifs_dbg; static struct dentry *dfs_chk_gen; static struct dentry *dfs_chk_index; static struct dentry *dfs_chk_orph; static struct dentry *dfs_chk_lprops; static struct dentry *dfs_chk_fs; static struct dentry *dfs_tst_rcvry; static ssize_t dfs_global_file_read(struct file *file, char __user *u, size_t count, loff_t *ppos) { … } static ssize_t dfs_global_file_write(struct file *file, const char __user *u, size_t count, loff_t *ppos) { … } static const struct file_operations dfs_global_fops = …; /** * dbg_debugfs_init - initialize debugfs file-system. * * UBIFS uses debugfs file-system to expose various debugging knobs to * user-space. This function creates "ubifs" directory in the debugfs * file-system. */ void dbg_debugfs_init(void) { … } /** * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system. */ void dbg_debugfs_exit(void) { … } void ubifs_assert_failed(struct ubifs_info *c, const char *expr, const char *file, int line) { … } /** * ubifs_debugging_init - initialize UBIFS debugging. * @c: UBIFS file-system description object * * This function initializes debugging-related data for the file system. * Returns zero in case of success and a negative error code in case of * failure. */ int ubifs_debugging_init(struct ubifs_info *c) { … } /** * ubifs_debugging_exit - free debugging data. * @c: UBIFS file-system description object */ void ubifs_debugging_exit(struct ubifs_info *c) { … }