@ -34,93 +34,16 @@ static struct vfsmount *debugfs_mount;
static int debugfs_mount_count ;
static bool debugfs_registered ;
static struct inode * debugfs_get_inode ( struct super_block * sb , umode_t mode , dev_t dev ,
void * data , const struct file_operations * fops )
static struct inode * debugfs_get_inode ( struct super_block * sb )
{
struct inode * inode = new_inode ( sb ) ;
if ( inode ) {
inode - > i_ino = get_next_ino ( ) ;
inode - > i_mode = mode ;
inode - > i_atime = inode - > i_mtime = inode - > i_ctime = CURRENT_TIME ;
switch ( mode & S_IFMT ) {
default :
init_special_inode ( inode , mode , dev ) ;
break ;
case S_IFREG :
inode - > i_fop = fops ? fops : & debugfs_file_operations ;
inode - > i_private = data ;
break ;
case S_IFLNK :
inode - > i_op = & debugfs_link_operations ;
inode - > i_private = data ;
break ;
case S_IFDIR :
inode - > i_op = & simple_dir_inode_operations ;
inode - > i_fop = & simple_dir_operations ;
/* directory inodes start off with i_nlink == 2
* ( for " . " entry ) */
inc_nlink ( inode ) ;
break ;
}
}
return inode ;
}
/* SMP-safe */
static int debugfs_mknod ( struct inode * dir , struct dentry * dentry ,
umode_t mode , dev_t dev , void * data ,
const struct file_operations * fops )
{
struct inode * inode ;
int error = - EPERM ;
if ( dentry - > d_inode )
return - EEXIST ;
inode = debugfs_get_inode ( dir - > i_sb , mode , dev , data , fops ) ;
if ( inode ) {
d_instantiate ( dentry , inode ) ;
dget ( dentry ) ;
error = 0 ;
}
return error ;
}
static int debugfs_mkdir ( struct inode * dir , struct dentry * dentry , umode_t mode )
{
int res ;
mode = ( mode & ( S_IRWXUGO | S_ISVTX ) ) | S_IFDIR ;
res = debugfs_mknod ( dir , dentry , mode , 0 , NULL , NULL ) ;
if ( ! res ) {
inc_nlink ( dir ) ;
fsnotify_mkdir ( dir , dentry ) ;
}
return res ;
}
static int debugfs_link ( struct inode * dir , struct dentry * dentry , umode_t mode ,
void * data )
{
mode = ( mode & S_IALLUGO ) | S_IFLNK ;
return debugfs_mknod ( dir , dentry , mode , 0 , data , NULL ) ;
}
static int debugfs_create ( struct inode * dir , struct dentry * dentry , umode_t mode ,
void * data , const struct file_operations * fops )
{
int res ;
mode = ( mode & S_IALLUGO ) | S_IFREG ;
res = debugfs_mknod ( dir , dentry , mode , 0 , data , fops ) ;
if ( ! res )
fsnotify_create ( dir , dentry ) ;
return res ;
}
static inline int debugfs_positive ( struct dentry * dentry )
{
return dentry - > d_inode & & ! d_unhashed ( dentry ) ;
@ -252,6 +175,18 @@ static const struct super_operations debugfs_super_operations = {
. show_options = debugfs_show_options ,
} ;
static struct vfsmount * debugfs_automount ( struct path * path )
{
struct vfsmount * ( * f ) ( void * ) ;
f = ( struct vfsmount * ( * ) ( void * ) ) path - > dentry - > d_fsdata ;
return f ( path - > dentry - > d_inode - > i_private ) ;
}
static const struct dentry_operations debugfs_dops = {
. d_delete = always_delete_dentry ,
. d_automount = debugfs_automount ,
} ;
static int debug_fill_super ( struct super_block * sb , void * data , int silent )
{
static struct tree_descr debug_files [ ] = { { " " } } ;
@ -276,6 +211,7 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent)
goto fail ;
sb - > s_op = & debugfs_super_operations ;
sb - > s_d_op = & debugfs_dops ;
debugfs_apply_options ( sb ) ;
@ -302,11 +238,9 @@ static struct file_system_type debug_fs_type = {
} ;
MODULE_ALIAS_FS ( " debugfs " ) ;
static struct dentry * __create_file ( const char * name , umode_t mode ,
struct dentry * parent , void * data ,
const struct file_operations * fops )
static struct dentry * start_creating ( const char * name , struct dentry * parent )
{
struct dentry * dentry = NULL ;
struct dentry * dentry ;
int error ;
pr_debug ( " debugfs: creating file '%s' \n " , name ) ;
@ -314,7 +248,7 @@ static struct dentry *__create_file(const char *name, umode_t mode,
error = simple_pin_fs ( & debug_fs_type , & debugfs_mount ,
& debugfs_mount_count ) ;
if ( error )
goto exit ;
return ERR_PTR ( error ) ;
/* If the parent is not specified, we create it in the root.
* We need the root dentry to do this , which is in the super
@ -326,31 +260,26 @@ static struct dentry *__create_file(const char *name, umode_t mode,
mutex_lock ( & parent - > d_inode - > i_mutex ) ;
dentry = lookup_one_len ( name , parent , strlen ( name ) ) ;
if ( ! IS_ERR ( dentry ) ) {
switch ( mode & S_IFMT ) {
case S_IFDIR :
error = debugfs_mkdir ( parent - > d_inode , dentry , mode ) ;
break ;
case S_IFLNK :
error = debugfs_link ( parent - > d_inode , dentry , mode ,
data ) ;
break ;
default :
error = debugfs_create ( parent - > d_inode , dentry , mode ,
data , fops ) ;
break ;
}
if ( ! IS_ERR ( dentry ) & & dentry - > d_inode ) {
dput ( dentry ) ;
} else
error = PTR_ERR ( dentry ) ;
mutex_unlock ( & parent - > d_inode - > i_mutex ) ;
if ( error ) {
dentry = NULL ;
simple_release_fs ( & debugfs_mount , & debugfs_mount_count ) ;
dentry = ERR_PTR ( - EEXIST ) ;
}
exit :
if ( IS_ERR ( dentry ) )
mutex_unlock ( & parent - > d_inode - > i_mutex ) ;
return dentry ;
}
static struct dentry * failed_creating ( struct dentry * dentry )
{
mutex_unlock ( & dentry - > d_parent - > d_inode - > i_mutex ) ;
dput ( dentry ) ;
simple_release_fs ( & debugfs_mount , & debugfs_mount_count ) ;
return NULL ;
}
static struct dentry * end_creating ( struct dentry * dentry )
{
mutex_unlock ( & dentry - > d_parent - > d_inode - > i_mutex ) ;
return dentry ;
}
@ -384,18 +313,70 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode,
struct dentry * parent , void * data ,
const struct file_operations * fops )
{
switch ( mode & S_IFMT ) {
case S_IFREG :
case 0 :
break ;
default :
BUG ( ) ;
}
struct dentry * dentry ;
struct inode * inode ;
if ( ! ( mode & S_IFMT ) )
mode | = S_IFREG ;
BUG_ON ( ! S_ISREG ( mode ) ) ;
dentry = start_creating ( name , parent ) ;
if ( IS_ERR ( dentry ) )
return NULL ;
return __create_file ( name , mode , parent , data , fops ) ;
inode = debugfs_get_inode ( dentry - > d_sb ) ;
if ( unlikely ( ! inode ) )
return failed_creating ( dentry ) ;
inode - > i_mode = mode ;
inode - > i_fop = fops ? fops : & debugfs_file_operations ;
inode - > i_private = data ;
d_instantiate ( dentry , inode ) ;
fsnotify_create ( dentry - > d_parent - > d_inode , dentry ) ;
return end_creating ( dentry ) ;
}
EXPORT_SYMBOL_GPL ( debugfs_create_file ) ;
/**
* debugfs_create_file_size - create a file in the debugfs filesystem
* @ name : a pointer to a string containing the name of the file to create .
* @ mode : the permission that the file should have .
* @ parent : a pointer to the parent dentry for this file . This should be a
* directory dentry if set . If this parameter is NULL , then the
* file will be created in the root of the debugfs filesystem .
* @ data : a pointer to something that the caller will want to get to later
* on . The inode . i_private pointer will point to this value on
* the open ( ) call .
* @ fops : a pointer to a struct file_operations that should be used for
* this file .
* @ file_size : initial file size
*
* This is the basic " create a file " function for debugfs . It allows for a
* wide range of flexibility in creating a file , or a directory ( if you want
* to create a directory , the debugfs_create_dir ( ) function is
* recommended to be used instead . )
*
* This function will return a pointer to a dentry if it succeeds . This
* pointer must be passed to the debugfs_remove ( ) function when the file is
* to be removed ( no automatic cleanup happens if your module is unloaded ,
* you are responsible here . ) If an error occurs , % NULL will be returned .
*
* If debugfs is not enabled in the kernel , the value - % ENODEV will be
* returned .
*/
struct dentry * debugfs_create_file_size ( const char * name , umode_t mode ,
struct dentry * parent , void * data ,
const struct file_operations * fops ,
loff_t file_size )
{
struct dentry * de = debugfs_create_file ( name , mode , parent , data , fops ) ;
if ( de )
de - > d_inode - > i_size = file_size ;
return de ;
}
EXPORT_SYMBOL_GPL ( debugfs_create_file_size ) ;
/**
* debugfs_create_dir - create a directory in the debugfs filesystem
* @ name : a pointer to a string containing the name of the directory to
@ -416,11 +397,64 @@ EXPORT_SYMBOL_GPL(debugfs_create_file);
*/
struct dentry * debugfs_create_dir ( const char * name , struct dentry * parent )
{
return __create_file ( name , S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO ,
parent , NULL , NULL ) ;
struct dentry * dentry = start_creating ( name , parent ) ;
struct inode * inode ;
if ( IS_ERR ( dentry ) )
return NULL ;
inode = debugfs_get_inode ( dentry - > d_sb ) ;
if ( unlikely ( ! inode ) )
return failed_creating ( dentry ) ;
inode - > i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO ;
inode - > i_op = & simple_dir_inode_operations ;
inode - > i_fop = & simple_dir_operations ;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
inc_nlink ( inode ) ;
d_instantiate ( dentry , inode ) ;
inc_nlink ( dentry - > d_parent - > d_inode ) ;
fsnotify_mkdir ( dentry - > d_parent - > d_inode , dentry ) ;
return end_creating ( dentry ) ;
}
EXPORT_SYMBOL_GPL ( debugfs_create_dir ) ;
/**
* debugfs_create_automount - create automount point in the debugfs filesystem
* @ name : a pointer to a string containing the name of the file to create .
* @ parent : a pointer to the parent dentry for this file . This should be a
* directory dentry if set . If this parameter is NULL , then the
* file will be created in the root of the debugfs filesystem .
* @ f : function to be called when pathname resolution steps on that one .
* @ data : opaque argument to pass to f ( ) .
*
* @ f should return what - > d_automount ( ) would .
*/
struct dentry * debugfs_create_automount ( const char * name ,
struct dentry * parent ,
struct vfsmount * ( * f ) ( void * ) ,
void * data )
{
struct dentry * dentry = start_creating ( name , parent ) ;
struct inode * inode ;
if ( IS_ERR ( dentry ) )
return NULL ;
inode = debugfs_get_inode ( dentry - > d_sb ) ;
if ( unlikely ( ! inode ) )
return failed_creating ( dentry ) ;
inode - > i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO ;
inode - > i_flags | = S_AUTOMOUNT ;
inode - > i_private = data ;
dentry - > d_fsdata = ( void * ) f ;
d_instantiate ( dentry , inode ) ;
return end_creating ( dentry ) ;
}
EXPORT_SYMBOL ( debugfs_create_automount ) ;
/**
* debugfs_create_symlink - create a symbolic link in the debugfs filesystem
* @ name : a pointer to a string containing the name of the symbolic link to
@ -447,17 +481,28 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir);
struct dentry * debugfs_create_symlink ( const char * name , struct dentry * parent ,
const char * target )
{
struct dentry * result ;
char * link ;
link = kstrdup ( target , GFP_KERNEL ) ;
struct dentry * dentry ;
struct inode * inode ;
char * link = kstrdup ( target , GFP_KERNEL ) ;
if ( ! link )
return NULL ;
result = __create_file ( name , S_IFLNK | S_IRWXUGO , parent , link , NULL ) ;
if ( ! result )
dentry = start_creating ( name , parent ) ;
if ( IS_ERR ( dentry ) ) {
kfree ( link ) ;
return result ;
return NULL ;
}
inode = debugfs_get_inode ( dentry - > d_sb ) ;
if ( unlikely ( ! inode ) ) {
kfree ( link ) ;
return failed_creating ( dentry ) ;
}
inode - > i_mode = S_IFLNK | S_IRWXUGO ;
inode - > i_op = & debugfs_link_operations ;
inode - > i_private = link ;
d_instantiate ( dentry , inode ) ;
return end_creating ( dentry ) ;
}
EXPORT_SYMBOL_GPL ( debugfs_create_symlink ) ;