Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 552ff317 authored by Artem Bityutskiy's avatar Artem Bityutskiy
Browse files

UBIFS: add debugfs support



We need to have a possibility to see various UBIFS variables
and ask UBIFS to dump various information. Debugfs is what
we need.

Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent 17c2f9f8
Loading
Loading
Loading
Loading
+156 −17
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include "ubifs.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/debugfs.h>

#ifdef CONFIG_UBIFS_FS_DEBUG

@@ -988,21 +989,19 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
	err = 1;
	key_read(c, &dent1->key, &key);
	if (keys_cmp(c, &zbr1->key, &key)) {
		dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
		ubifs_err("1st entry at %d:%d has key %s", zbr1->lnum,
			  zbr1->offs, DBGKEY(&key));
		dbg_err("but it should have key %s according to tnc",
			DBGKEY(&zbr1->key));
			dbg_dump_node(c, dent1);
		ubifs_err("but it should have key %s according to tnc",
			  DBGKEY(&zbr1->key)); dbg_dump_node(c, dent1);
		goto out_free;
	}

	key_read(c, &dent2->key, &key);
	if (keys_cmp(c, &zbr2->key, &key)) {
		dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
		ubifs_err("2nd entry at %d:%d has key %s", zbr1->lnum,
			  zbr1->offs, DBGKEY(&key));
		dbg_err("but it should have key %s according to tnc",
			DBGKEY(&zbr2->key));
			dbg_dump_node(c, dent2);
		ubifs_err("but it should have key %s according to tnc",
			  DBGKEY(&zbr2->key)); dbg_dump_node(c, dent2);
		goto out_free;
	}

@@ -1015,14 +1014,14 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
		goto out_free;
	}
	if (cmp == 0 && nlen1 == nlen2)
		dbg_err("2 xent/dent nodes with the same name");
		ubifs_err("2 xent/dent nodes with the same name");
	else
		dbg_err("bad order of colliding key %s",
		ubifs_err("bad order of colliding key %s",
			DBGKEY(&key));

	dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
	ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
	dbg_dump_node(c, dent1);
	dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
	ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
	dbg_dump_node(c, dent2);

out_free:
@@ -2103,7 +2102,7 @@ static void failure_mode_init(struct ubifs_info *c)

	fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
	if (!fmi) {
		dbg_err("Failed to register failure mode - no memory");
		ubifs_err("Failed to register failure mode - no memory");
		return;
	}
	fmi->c = c;
@@ -2383,4 +2382,144 @@ void ubifs_debugging_exit(struct ubifs_info *c)
	kfree(c->dbg);
}

/*
 * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
 * contain the stuff specific to particular file-system mounts.
 */
static struct dentry *debugfs_rootdir;

/**
 * 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. Returns zero in case of success and a negative error code in
 * case of failure.
 */
int dbg_debugfs_init(void)
{
	debugfs_rootdir = debugfs_create_dir("ubifs", NULL);
	if (IS_ERR(debugfs_rootdir)) {
		int err = PTR_ERR(debugfs_rootdir);
		ubifs_err("cannot create \"ubifs\" debugfs directory, "
			  "error %d\n", err);
		return err;
	}

	return 0;
}

/**
 * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
 */
void dbg_debugfs_exit(void)
{
	debugfs_remove(debugfs_rootdir);
}

static int open_debugfs_file(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
				  size_t count, loff_t *ppos)
{
	struct ubifs_info *c = file->private_data;
	struct ubifs_debug_info *d = c->dbg;

	if (file->f_path.dentry == d->dump_lprops)
		dbg_dump_lprops(c);
	else if (file->f_path.dentry == d->dump_budg) {
		spin_lock(&c->space_lock);
		dbg_dump_budg(c);
		spin_unlock(&c->space_lock);
	} else if (file->f_path.dentry == d->dump_budg) {
		mutex_lock(&c->tnc_mutex);
		dbg_dump_tnc(c);
		mutex_unlock(&c->tnc_mutex);
	} else
		return -EINVAL;

	*ppos += count;
	return count;
}

static const struct file_operations debugfs_fops = {
	.open = open_debugfs_file,
	.write = write_debugfs_file,
	.owner = THIS_MODULE,
};

/**
 * 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. Returns
 * zero in case of success and a negative error code in case of failure.
 *
 * 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.
 */
int dbg_debugfs_init_fs(struct ubifs_info *c)
{
	int err;
	const char *fname;
	struct dentry *dent;
	struct ubifs_debug_info *d = c->dbg;

	sprintf(d->debugfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
	d->debugfs_dir = debugfs_create_dir(d->debugfs_dir_name,
					      debugfs_rootdir);
	if (IS_ERR(d->debugfs_dir)) {
		err = PTR_ERR(d->debugfs_dir);
		ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
			  d->debugfs_dir_name, err);
		goto out;
	}

	fname = "dump_lprops";
	dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
				   &debugfs_fops);
	if (IS_ERR(dent))
		goto out_remove;
	d->dump_lprops = dent;

	fname = "dump_budg";
	dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
				   &debugfs_fops);
	if (IS_ERR(dent))
		goto out_remove;
	d->dump_budg = dent;

	fname = "dump_tnc";
	dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
				   &debugfs_fops);
	if (IS_ERR(dent))
		goto out_remove;
	d->dump_tnc = dent;

	return 0;

out_remove:
	err = PTR_ERR(dent);
	ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
		  fname, err);
	debugfs_remove_recursive(d->debugfs_dir);
out:
	return err;
}

/**
 * dbg_debugfs_exit_fs - remove all debugfs files.
 * @c: UBIFS file-system description object
 */
void dbg_debugfs_exit_fs(struct ubifs_info *c)
{
	debugfs_remove_recursive(c->dbg->debugfs_dir);
}

#endif /* CONFIG_UBIFS_FS_DEBUG */
+24 −3
Original line number Diff line number Diff line
@@ -43,6 +43,13 @@
 * @new_nhead_offs: used by LPT tree size checker
 * @new_ihead_lnum: used by debugging to check ihead_lnum
 * @new_ihead_offs: used by debugging to check ihead_offs
 *
 * debugfs_dir_name: name of debugfs directory containing this file-system's
 *                   files
 * debugfs_dir: direntry object of the file-system debugfs directory
 * dump_lprops: "dump lprops" debugfs knob
 * dump_budg: "dump budgeting information" debugfs knob
 * dump_tnc: "dump TNC" debugfs knob
 */
struct ubifs_debug_info {
	void *buf;
@@ -61,6 +68,12 @@ struct ubifs_debug_info {
	int new_nhead_offs;
	int new_ihead_lnum;
	int new_ihead_offs;

	char debugfs_dir_name[100];
	struct dentry *debugfs_dir;
	struct dentry *dump_lprops;
	struct dentry *dump_budg;
	struct dentry *dump_tnc;
};

#define ubifs_assert(expr) do {                                                \
@@ -251,7 +264,6 @@ int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c);

/* Dump functions */

const char *dbg_ntype(int type);
const char *dbg_cstate(int cmt_state);
const char *dbg_get_key_dump(const struct ubifs_info *c,
@@ -274,7 +286,6 @@ void dbg_dump_tnc(struct ubifs_info *c);
void dbg_dump_index(struct ubifs_info *c);

/* Checking helper functions */

typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
				 struct ubifs_zbranch *zbr, void *priv);
typedef int (*dbg_znode_callback)(struct ubifs_info *c,
@@ -354,6 +365,12 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
	return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
}

/* Debugfs-related stuff */
int dbg_debugfs_init(void);
void dbg_debugfs_exit(void);
int dbg_debugfs_init_fs(struct ubifs_info *c);
void dbg_debugfs_exit_fs(struct ubifs_info *c);

#else /* !CONFIG_UBIFS_FS_DEBUG */

/* Use "if (0)" to make compiler check arguments even if debugging is off */
@@ -434,6 +451,10 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
#define dbg_force_in_the_gaps()                    0
#define dbg_failure_mode                           0

#endif /* !CONFIG_UBIFS_FS_DEBUG */
#define dbg_debugfs_init()                         0
#define dbg_debugfs_exit()
#define dbg_debugfs_init_fs(c)                     0
#define dbg_debugfs_exit_fs(c)                     0

#endif /* !CONFIG_UBIFS_FS_DEBUG */
#endif /* !__UBIFS_DEBUG_H__ */
+12 −0
Original line number Diff line number Diff line
@@ -1258,6 +1258,10 @@ static int mount_ubifs(struct ubifs_info *c)
		}
	}

	err = dbg_debugfs_init_fs(c);
	if (err)
		goto out_infos;

	err = dbg_check_filesystem(c);
	if (err)
		goto out_infos;
@@ -1369,6 +1373,7 @@ static void ubifs_umount(struct ubifs_info *c)
	dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
		c->vi.vol_id);

	dbg_debugfs_exit_fs(c);
	spin_lock(&ubifs_infos_lock);
	list_del(&c->infos_list);
	spin_unlock(&ubifs_infos_lock);
@@ -2078,12 +2083,18 @@ static int __init ubifs_init(void)
	register_shrinker(&ubifs_shrinker_info);

	err = ubifs_compressors_init();
	if (err)
		goto out_shrinker;

	err = dbg_debugfs_init();
	if (err)
		goto out_compr;

	return 0;

out_compr:
	ubifs_compressors_exit();
out_shrinker:
	unregister_shrinker(&ubifs_shrinker_info);
	kmem_cache_destroy(ubifs_inode_slab);
out_reg:
@@ -2098,6 +2109,7 @@ static void __exit ubifs_exit(void)
	ubifs_assert(list_empty(&ubifs_infos));
	ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0);

	dbg_debugfs_exit();
	ubifs_compressors_exit();
	unregister_shrinker(&ubifs_shrinker_info);
	kmem_cache_destroy(ubifs_inode_slab);
+1 −0
Original line number Diff line number Diff line
@@ -1158,6 +1158,7 @@ struct ubifs_debug_info;
 * @mount_opts: UBIFS-specific mount options
 *
 * @dbg: debugging-related information
 * @dfs: debugfs support-related information
 */
struct ubifs_info {
	struct super_block *vfs_sb;