Skip to content

Commit

Permalink
UBI: use debugfs for the extra checks knobs
Browse files Browse the repository at this point in the history
This patch introduces debugfs support to UBI. All the UBI stuff is kept in the
"ubi" debugfs directory, which contains per-UBI device "ubi/ubiX"
sub-directories, containing debugging files. This file also creates
"ubi/ubiX/chk_gen" and "ubi/ubiX/chk_io" knobs for switching general and I/O
extra checks on and off. And it removes the 'debug_chks' UBI module parameters.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
  • Loading branch information
Artem Bityutskiy authored and Artem Bityutskiy committed Jun 1, 2011
1 parent d99383b commit 2a734bb
Show file tree
Hide file tree
Showing 9 changed files with 310 additions and 36 deletions.
26 changes: 24 additions & 2 deletions drivers/mtd/ubi/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,10 +953,14 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (!ubi->peb_buf2)
goto out_free;

err = ubi_debugging_init_dev(ubi);
if (err)
goto out_free;

err = attach_by_scanning(ubi);
if (err) {
dbg_err("failed to attach by scanning, error %d", err);
goto out_free;
goto out_debugging;
}

if (ubi->autoresize_vol_id != -1) {
Expand All @@ -969,12 +973,16 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (err)
goto out_detach;

err = ubi_debugfs_init_dev(ubi);
if (err)
goto out_uif;

ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
if (IS_ERR(ubi->bgt_thread)) {
err = PTR_ERR(ubi->bgt_thread);
ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
err);
goto out_uif;
goto out_debugfs;
}

ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
Expand Down Expand Up @@ -1008,12 +1016,16 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
return ubi_num;

out_debugfs:
ubi_debugfs_exit_dev(ubi);
out_uif:
uif_close(ubi);
out_detach:
ubi_wl_close(ubi);
free_internal_volumes(ubi);
vfree(ubi->vtbl);
out_debugging:
ubi_debugging_exit_dev(ubi);
out_free:
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
Expand Down Expand Up @@ -1080,11 +1092,13 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
*/
get_device(&ubi->dev);

ubi_debugfs_exit_dev(ubi);
uif_close(ubi);
ubi_wl_close(ubi);
free_internal_volumes(ubi);
vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
ubi_debugging_exit_dev(ubi);
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
Expand Down Expand Up @@ -1199,6 +1213,11 @@ static int __init ubi_init(void)
if (!ubi_wl_entry_slab)
goto out_dev_unreg;

err = ubi_debugfs_init();
if (err)
goto out_slab;


/* Attach MTD devices */
for (i = 0; i < mtd_devs; i++) {
struct mtd_dev_param *p = &mtd_dev_param[i];
Expand Down Expand Up @@ -1247,6 +1266,8 @@ static int __init ubi_init(void)
ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
mutex_unlock(&ubi_devices_mutex);
}
ubi_debugfs_exit();
out_slab:
kmem_cache_destroy(ubi_wl_entry_slab);
out_dev_unreg:
misc_deregister(&ubi_ctrl_cdev);
Expand All @@ -1270,6 +1291,7 @@ static void __exit ubi_exit(void)
ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
mutex_unlock(&ubi_devices_mutex);
}
ubi_debugfs_exit();
kmem_cache_destroy(ubi_wl_entry_slab);
misc_deregister(&ubi_ctrl_cdev);
class_remove_file(ubi_class, &ubi_version);
Expand Down
231 changes: 227 additions & 4 deletions drivers/mtd/ubi/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@
#ifdef CONFIG_MTD_UBI_DEBUG

#include "ubi.h"
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

unsigned int ubi_chk_flags;
unsigned int ubi_tst_flags;

module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
module_param_named(debug_tsts, ubi_tst_flags, uint, S_IRUGO | S_IWUSR);

MODULE_PARM_DESC(debug_chks, "Debug check flags");
MODULE_PARM_DESC(debug_tsts, "Debug special test flags");

/**
Expand Down Expand Up @@ -239,4 +238,228 @@ void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
return;
}

/**
* ubi_debugging_init_dev - initialize debugging for an UBI device.
* @ubi: UBI device description object
*
* This function initializes debugging-related data for UBI device @ubi.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
int ubi_debugging_init_dev(struct ubi_device *ubi)
{
ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL);
if (!ubi->dbg)
return -ENOMEM;

return 0;
}

/**
* ubi_debugging_exit_dev - free debugging data for an UBI device.
* @ubi: UBI device description object
*/
void ubi_debugging_exit_dev(struct ubi_device *ubi)
{
kfree(ubi->dbg);
}

/*
* Root directory for UBI stuff in debugfs. Contains sub-directories which
* contain the stuff specific to particular UBI devices.
*/
static struct dentry *dfs_rootdir;

/**
* ubi_debugfs_init - create UBI debugfs directory.
*
* Create UBI debugfs directory. Returns zero in case of success and a negative
* error code in case of failure.
*/
int ubi_debugfs_init(void)
{
dfs_rootdir = debugfs_create_dir("ubi", NULL);
if (IS_ERR_OR_NULL(dfs_rootdir)) {
int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);

ubi_err("cannot create \"ubi\" debugfs directory, error %d\n",
err);
return err;
}

return 0;
}

/**
* ubi_debugfs_exit - remove UBI debugfs directory.
*/
void ubi_debugfs_exit(void)
{
debugfs_remove(dfs_rootdir);
}

/* Read an UBI debugfs file */
static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
unsigned long ubi_num = (unsigned long)file->private_data;
struct dentry *dent = file->f_path.dentry;
struct ubi_device *ubi;
struct ubi_debug_info *d;
char buf[3];
int val;

ubi = ubi_get_device(ubi_num);
if (!ubi)
return -ENODEV;
d = ubi->dbg;

if (dent == d->dfs_chk_gen)
val = d->chk_gen;
else if (dent == d->dfs_chk_io)
val = d->chk_io;
else {
count = -EINVAL;
goto out;
}

if (val)
buf[0] = '1';
else
buf[0] = '0';
buf[1] = '\n';
buf[2] = 0x00;

count = simple_read_from_buffer(user_buf, count, ppos, buf, 2);

out:
ubi_put_device(ubi);
return count;
}

/* Write an UBI debugfs file */
static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
unsigned long ubi_num = (unsigned long)file->private_data;
struct dentry *dent = file->f_path.dentry;
struct ubi_device *ubi;
struct ubi_debug_info *d;
size_t buf_size;
char buf[8];
int val;

ubi = ubi_get_device(ubi_num);
if (!ubi)
return -ENODEV;
d = ubi->dbg;

buf_size = min_t(size_t, count, (sizeof(buf) - 1));
if (copy_from_user(buf, user_buf, buf_size)) {
count = -EFAULT;
goto out;
}

if (buf[0] == '1')
val = 1;
else if (buf[0] == '0')
val = 0;
else {
count = -EINVAL;
goto out;
}

if (dent == d->dfs_chk_gen)
d->chk_gen = val;
else if (dent == d->dfs_chk_io)
d->chk_io = val;
else
count = -EINVAL;

out:
ubi_put_device(ubi);
return count;
}

static int default_open(struct inode *inode, struct file *file)
{
if (inode->i_private)
file->private_data = inode->i_private;

return 0;
}

/* File operations for all UBI debugfs files */
static const struct file_operations dfs_fops = {
.read = dfs_file_read,
.write = dfs_file_write,
.open = default_open,
.llseek = no_llseek,
.owner = THIS_MODULE,
};

/**
* ubi_debugfs_init_dev - initialize debugfs for an UBI device.
* @ubi: UBI device description object
*
* This function creates all debugfs files for UBI device @ubi. Returns zero in
* case of success and a negative error code in case of failure.
*/
int ubi_debugfs_init_dev(struct ubi_device *ubi)
{
int err, n;
unsigned long ubi_num = ubi->ubi_num;
const char *fname;
struct dentry *dent;
struct ubi_debug_info *d = ubi->dbg;

n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
ubi->ubi_num);
if (n == UBI_DFS_DIR_LEN) {
/* The array size is too small */
fname = UBI_DFS_DIR_NAME;
dent = ERR_PTR(-EINVAL);
goto out;
}

fname = d->dfs_dir_name;
dent = debugfs_create_dir(fname, dfs_rootdir);
if (IS_ERR_OR_NULL(dent))
goto out;
d->dfs_dir = dent;

fname = "chk_gen";
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_gen = dent;

fname = "chk_io";
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_io = dent;

return 0;

out_remove:
debugfs_remove_recursive(d->dfs_dir);
out:
err = dent ? PTR_ERR(dent) : -ENODEV;
ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n",
fname, err);
return err;
}

/**
* dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi
* @ubi: UBI device description object
*/
void ubi_debugfs_exit_dev(struct ubi_device *ubi)
{
debugfs_remove_recursive(ubi->dbg->dfs_dir);
}

#endif /* CONFIG_MTD_UBI_DEBUG */
Loading

0 comments on commit 2a734bb

Please sign in to comment.