2015-07-17 17:38:13 +03:00
/*
* What : / sys / kernel / debug / orangefs / debug - help
* Date : June 2015
* Contact : Mike Marshall < hubcap @ omnibond . com >
* Description :
* List of client and kernel debug keywords .
*
*
* What : / sys / kernel / debug / orangefs / client - debug
* Date : June 2015
* Contact : Mike Marshall < hubcap @ omnibond . com >
* Description :
* Debug setting for " the client " , the userspace
* helper for the kernel module .
*
*
* What : / sys / kernel / debug / orangefs / kernel - debug
* Date : June 2015
* Contact : Mike Marshall < hubcap @ omnibond . com >
* Description :
* Debug setting for the orangefs kernel module .
*
* Any of the keywords , or comma - separated lists
* of keywords , from debug - help can be catted to
* client - debug or kernel - debug .
*
* " none " , " all " and " verbose " are special keywords
* for client - debug . Setting client - debug to " all "
* is kind of like trying to drink water from a
* fire hose , " verbose " triggers most of the same
* output except for the constant flow of output
* from the main wait loop .
*
* " none " and " all " are similar settings for kernel - debug
* no need for a " verbose " .
*/
# include <linux/debugfs.h>
# include <linux/slab.h>
# include <linux/uaccess.h>
2015-12-04 20:56:14 +03:00
# include "orangefs-debugfs.h"
2015-07-17 17:38:13 +03:00
# include "protocol.h"
2015-12-04 20:56:14 +03:00
# include "orangefs-kernel.h"
2015-07-17 17:38:13 +03:00
static int orangefs_debug_disabled = 1 ;
static int orangefs_debug_help_open ( struct inode * , struct file * ) ;
const struct file_operations debug_help_fops = {
. open = orangefs_debug_help_open ,
. read = seq_read ,
. release = seq_release ,
. llseek = seq_lseek ,
} ;
static void * help_start ( struct seq_file * , loff_t * ) ;
static void * help_next ( struct seq_file * , void * , loff_t * ) ;
static void help_stop ( struct seq_file * , void * ) ;
static int help_show ( struct seq_file * , void * ) ;
static const struct seq_operations help_debug_ops = {
. start = help_start ,
. next = help_next ,
. stop = help_stop ,
. show = help_show ,
} ;
/*
* Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and
* ORANGEFS_KMOD_DEBUG_FILE .
*/
2015-07-28 20:27:51 +03:00
static DEFINE_MUTEX ( orangefs_debug_lock ) ;
2015-07-17 17:38:13 +03:00
int orangefs_debug_open ( struct inode * , struct file * ) ;
static ssize_t orangefs_debug_read ( struct file * ,
char __user * ,
size_t ,
loff_t * ) ;
static ssize_t orangefs_debug_write ( struct file * ,
const char __user * ,
size_t ,
loff_t * ) ;
static const struct file_operations kernel_debug_fops = {
. open = orangefs_debug_open ,
. read = orangefs_debug_read ,
. write = orangefs_debug_write ,
. llseek = generic_file_llseek ,
} ;
/*
* initialize kmod debug operations , create orangefs debugfs dir and
* ORANGEFS_KMOD_DEBUG_HELP_FILE .
*/
2015-11-24 23:12:14 +03:00
int orangefs_debugfs_init ( void )
2015-07-17 17:38:13 +03:00
{
int rc = - ENOMEM ;
debug_dir = debugfs_create_dir ( " orangefs " , NULL ) ;
if ( ! debug_dir )
goto out ;
help_file_dentry = debugfs_create_file ( ORANGEFS_KMOD_DEBUG_HELP_FILE ,
0444 ,
debug_dir ,
debug_help_string ,
& debug_help_fops ) ;
if ( ! help_file_dentry )
goto out ;
orangefs_debug_disabled = 0 ;
rc = 0 ;
out :
if ( rc )
2015-11-24 23:12:14 +03:00
orangefs_debugfs_cleanup ( ) ;
2015-07-17 17:38:13 +03:00
return rc ;
}
2015-11-24 23:12:14 +03:00
void orangefs_debugfs_cleanup ( void )
2015-07-17 17:38:13 +03:00
{
debugfs_remove_recursive ( debug_dir ) ;
}
/* open ORANGEFS_KMOD_DEBUG_HELP_FILE */
static int orangefs_debug_help_open ( struct inode * inode , struct file * file )
{
int rc = - ENODEV ;
int ret ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" orangefs_debug_help_open: start \n " ) ;
if ( orangefs_debug_disabled )
goto out ;
ret = seq_open ( file , & help_debug_ops ) ;
if ( ret )
goto out ;
( ( struct seq_file * ) ( file - > private_data ) ) - > private = inode - > i_private ;
rc = 0 ;
out :
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" orangefs_debug_help_open: rc:%d: \n " ,
rc ) ;
return rc ;
}
/*
* I think start always gets called again after stop . Start
* needs to return NULL when it is done . The whole " payload "
* in this case is a single ( long ) string , so by the second
* time we get to start ( pos = 1 ) , we ' re done .
*/
static void * help_start ( struct seq_file * m , loff_t * pos )
{
void * payload = NULL ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " help_start: start \n " ) ;
if ( * pos = = 0 )
payload = m - > private ;
return payload ;
}
static void * help_next ( struct seq_file * m , void * v , loff_t * pos )
{
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " help_next: start \n " ) ;
return NULL ;
}
static void help_stop ( struct seq_file * m , void * p )
{
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " help_stop: start \n " ) ;
}
static int help_show ( struct seq_file * m , void * v )
{
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " help_show: start \n " ) ;
seq_puts ( m , v ) ;
return 0 ;
}
/*
* initialize the kernel - debug file .
*/
2015-11-24 23:12:14 +03:00
int orangefs_kernel_debug_init ( void )
2015-07-17 17:38:13 +03:00
{
int rc = - ENOMEM ;
struct dentry * ret ;
char * k_buffer = NULL ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: start \n " , __func__ ) ;
2015-11-24 23:12:14 +03:00
k_buffer = kzalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 17:38:13 +03:00
if ( ! k_buffer )
goto out ;
2015-11-24 23:12:14 +03:00
if ( strlen ( kernel_debug_string ) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN ) {
2015-07-17 17:38:13 +03:00
strcpy ( k_buffer , kernel_debug_string ) ;
strcat ( k_buffer , " \n " ) ;
} else {
strcpy ( k_buffer , " none \n " ) ;
pr_info ( " %s: overflow 1! \n " , __func__ ) ;
}
ret = debugfs_create_file ( ORANGEFS_KMOD_DEBUG_FILE ,
0444 ,
debug_dir ,
k_buffer ,
& kernel_debug_fops ) ;
if ( ! ret ) {
pr_info ( " %s: failed to create %s. \n " ,
__func__ ,
ORANGEFS_KMOD_DEBUG_FILE ) ;
goto out ;
}
rc = 0 ;
out :
if ( rc )
2015-11-24 23:12:14 +03:00
orangefs_debugfs_cleanup ( ) ;
2015-07-17 17:38:13 +03:00
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: rc:%d: \n " , __func__ , rc ) ;
return rc ;
}
/*
* initialize the client - debug file .
*/
2015-11-24 23:12:14 +03:00
int orangefs_client_debug_init ( void )
2015-07-17 17:38:13 +03:00
{
int rc = - ENOMEM ;
char * c_buffer = NULL ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: start \n " , __func__ ) ;
2015-11-24 23:12:14 +03:00
c_buffer = kzalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 17:38:13 +03:00
if ( ! c_buffer )
goto out ;
2015-11-24 23:12:14 +03:00
if ( strlen ( client_debug_string ) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN ) {
2015-07-17 17:38:13 +03:00
strcpy ( c_buffer , client_debug_string ) ;
strcat ( c_buffer , " \n " ) ;
} else {
strcpy ( c_buffer , " none \n " ) ;
pr_info ( " %s: overflow! 2 \n " , __func__ ) ;
}
client_debug_dentry = debugfs_create_file ( ORANGEFS_CLIENT_DEBUG_FILE ,
0444 ,
debug_dir ,
c_buffer ,
& kernel_debug_fops ) ;
if ( ! client_debug_dentry ) {
pr_info ( " %s: failed to create %s. \n " ,
__func__ ,
ORANGEFS_CLIENT_DEBUG_FILE ) ;
goto out ;
}
rc = 0 ;
out :
if ( rc )
2015-11-24 23:12:14 +03:00
orangefs_debugfs_cleanup ( ) ;
2015-07-17 17:38:13 +03:00
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: rc:%d: \n " , __func__ , rc ) ;
return rc ;
}
/* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
int orangefs_debug_open ( struct inode * inode , struct file * file )
{
int rc = - ENODEV ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" %s: orangefs_debug_disabled: %d \n " ,
__func__ ,
orangefs_debug_disabled ) ;
if ( orangefs_debug_disabled )
goto out ;
rc = 0 ;
mutex_lock ( & orangefs_debug_lock ) ;
file - > private_data = inode - > i_private ;
mutex_unlock ( & orangefs_debug_lock ) ;
out :
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" orangefs_debug_open: rc: %d \n " ,
rc ) ;
return rc ;
}
static ssize_t orangefs_debug_read ( struct file * file ,
char __user * ubuf ,
size_t count ,
loff_t * ppos )
{
char * buf ;
int sprintf_ret ;
ssize_t read_ret = - ENOMEM ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " orangefs_debug_read: start \n " ) ;
2015-11-24 23:12:14 +03:00
buf = kmalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 17:38:13 +03:00
if ( ! buf )
goto out ;
mutex_lock ( & orangefs_debug_lock ) ;
sprintf_ret = sprintf ( buf , " %s " , ( char * ) file - > private_data ) ;
mutex_unlock ( & orangefs_debug_lock ) ;
read_ret = simple_read_from_buffer ( ubuf , count , ppos , buf , sprintf_ret ) ;
kfree ( buf ) ;
out :
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" orangefs_debug_read: ret: %zu \n " ,
read_ret ) ;
return read_ret ;
}
static ssize_t orangefs_debug_write ( struct file * file ,
const char __user * ubuf ,
size_t count ,
loff_t * ppos )
{
char * buf ;
int rc = - EFAULT ;
size_t silly = 0 ;
char * debug_string ;
2015-11-24 23:12:14 +03:00
struct orangefs_kernel_op_s * new_op = NULL ;
2015-07-17 17:38:13 +03:00
struct client_debug_mask c_mask = { NULL , 0 , 0 } ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" orangefs_debug_write: %s \n " ,
file - > f_path . dentry - > d_name . name ) ;
/*
* Thwart users who try to jamb a ridiculous number
* of bytes into the debug file . . .
*/
2015-11-24 23:12:14 +03:00
if ( count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1 ) {
2015-07-17 17:38:13 +03:00
silly = count ;
2015-11-24 23:12:14 +03:00
count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1 ;
2015-07-17 17:38:13 +03:00
}
2015-12-22 19:13:50 +03:00
buf = kzalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 17:38:13 +03:00
if ( ! buf )
goto out ;
if ( copy_from_user ( buf , ubuf , count - 1 ) ) {
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" %s: copy_from_user failed! \n " ,
__func__ ) ;
goto out ;
}
/*
* Map the keyword string from userspace into a valid debug mask .
* The mapping process involves mapping the human - inputted string
* into a valid mask , and then rebuilding the string from the
* verified valid mask .
*
* A service operation is required to set a new client - side
* debug mask .
*/
if ( ! strcmp ( file - > f_path . dentry - > d_name . name ,
ORANGEFS_KMOD_DEBUG_FILE ) ) {
debug_string_to_mask ( buf , & gossip_debug_mask , 0 ) ;
debug_mask_to_string ( & gossip_debug_mask , 0 ) ;
debug_string = kernel_debug_string ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" New kernel debug string is %s \n " ,
kernel_debug_string ) ;
} else {
/* Can't reset client debug mask if client is not running. */
if ( is_daemon_in_service ( ) ) {
pr_info ( " %s: Client not running :%d: \n " ,
__func__ ,
is_daemon_in_service ( ) ) ;
goto out ;
}
debug_string_to_mask ( buf , & c_mask , 1 ) ;
debug_mask_to_string ( & c_mask , 1 ) ;
debug_string = client_debug_string ;
2015-11-24 23:12:14 +03:00
new_op = op_alloc ( ORANGEFS_VFS_OP_PARAM ) ;
2015-07-17 17:38:13 +03:00
if ( ! new_op ) {
pr_info ( " %s: op_alloc failed! \n " , __func__ ) ;
goto out ;
}
new_op - > upcall . req . param . op =
2015-11-24 23:12:14 +03:00
ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES ;
new_op - > upcall . req . param . type = ORANGEFS_PARAM_REQUEST_SET ;
2015-07-17 17:38:13 +03:00
memset ( new_op - > upcall . req . param . s_value ,
0 ,
2015-11-24 23:12:14 +03:00
ORANGEFS_MAX_DEBUG_STRING_LEN ) ;
2015-07-17 17:38:13 +03:00
sprintf ( new_op - > upcall . req . param . s_value ,
" %llx %llx \n " ,
c_mask . mask1 ,
c_mask . mask2 ) ;
/* service_operation returns 0 on success... */
rc = service_operation ( new_op ,
2015-11-24 23:12:14 +03:00
" orangefs_param " ,
ORANGEFS_OP_INTERRUPTIBLE ) ;
2015-07-17 17:38:13 +03:00
if ( rc )
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" %s: service_operation failed! rc:%d: \n " ,
__func__ ,
rc ) ;
op_release ( new_op ) ;
}
mutex_lock ( & orangefs_debug_lock ) ;
2015-11-24 23:12:14 +03:00
memset ( file - > f_inode - > i_private , 0 , ORANGEFS_MAX_DEBUG_STRING_LEN ) ;
2015-07-17 17:38:13 +03:00
sprintf ( ( char * ) file - > f_inode - > i_private , " %s \n " , debug_string ) ;
mutex_unlock ( & orangefs_debug_lock ) ;
* ppos + = count ;
if ( silly )
rc = silly ;
else
rc = count ;
out :
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
" orangefs_debug_write: rc: %d \n " ,
rc ) ;
kfree ( buf ) ;
return rc ;
}