@ -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 " ) ;
/**
@ -239,4 +238,228 @@ out:
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 */