2015-07-17 10:38:13 -04: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 12:56:14 -05:00
# include "orangefs-debugfs.h"
2015-07-17 10:38:13 -04:00
# include "protocol.h"
2015-12-04 12:56:14 -05:00
# include "orangefs-kernel.h"
2015-07-17 10:38:13 -04:00
2016-08-15 11:38:36 -04:00
# define DEBUG_HELP_STRING_SIZE 4096
# define HELP_STRING_UNINITIALIZED \
" Client Debug Keywords are unknown until the first time \n " \
" the client is started after boot. \n "
# define ORANGEFS_KMOD_DEBUG_HELP_FILE "debug-help"
# define ORANGEFS_KMOD_DEBUG_FILE "kernel-debug"
# define ORANGEFS_CLIENT_DEBUG_FILE "client-debug"
# define ORANGEFS_VERBOSE "verbose"
# define ORANGEFS_ALL "all"
2015-07-17 10:38:13 -04:00
2016-08-15 11:38:36 -04:00
/*
* An array of client_debug_mask will be built to hold debug keyword / mask
* values fetched from userspace .
*/
struct client_debug_mask {
char * keyword ;
__u64 mask1 ;
__u64 mask2 ;
2015-07-17 10:38:13 -04:00
} ;
2016-08-15 11:38:36 -04:00
static int orangefs_kernel_debug_init ( void ) ;
static int orangefs_debug_help_open ( struct inode * , struct file * ) ;
2015-07-17 10:38:13 -04:00
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 * ) ;
2016-08-15 11:38:36 -04:00
static int orangefs_debug_open ( struct inode * , struct file * ) ;
2015-07-17 10:38:13 -04:00
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 * ) ;
2016-08-15 11:38:36 -04:00
static int orangefs_prepare_cdm_array ( char * ) ;
static void debug_mask_to_string ( void * , int ) ;
static void do_k_string ( void * , int ) ;
static void do_c_string ( void * , int ) ;
static int keyword_is_amalgam ( char * ) ;
static int check_amalgam_keyword ( void * , int ) ;
static void debug_string_to_mask ( char * , void * , int ) ;
static void do_c_mask ( int , char * , struct client_debug_mask * * ) ;
static void do_k_mask ( int , char * , __u64 * * ) ;
static char kernel_debug_string [ ORANGEFS_MAX_DEBUG_STRING_LEN ] = " none " ;
static char * debug_help_string ;
static char client_debug_string [ ORANGEFS_MAX_DEBUG_STRING_LEN ] ;
static char client_debug_array_string [ ORANGEFS_MAX_DEBUG_STRING_LEN ] ;
static struct dentry * help_file_dentry ;
static struct dentry * client_debug_dentry ;
static struct dentry * debug_dir ;
static unsigned int kernel_mask_set_mod_init ;
static int orangefs_debug_disabled = 1 ;
static int help_string_initialized ;
static const struct seq_operations help_debug_ops = {
. start = help_start ,
. next = help_next ,
. stop = help_stop ,
. show = help_show ,
} ;
const struct file_operations debug_help_fops = {
2016-11-16 11:52:19 -05:00
. owner = THIS_MODULE ,
2016-08-15 11:38:36 -04:00
. open = orangefs_debug_help_open ,
. read = seq_read ,
. release = seq_release ,
. llseek = seq_lseek ,
} ;
2015-07-17 10:38:13 -04:00
static const struct file_operations kernel_debug_fops = {
2016-11-16 11:52:19 -05:00
. owner = THIS_MODULE ,
2015-07-17 10:38:13 -04:00
. open = orangefs_debug_open ,
. read = orangefs_debug_read ,
. write = orangefs_debug_write ,
. llseek = generic_file_llseek ,
} ;
2016-08-15 11:38:36 -04:00
static int client_all_index ;
static int client_verbose_index ;
static struct client_debug_mask * cdm_array ;
static int cdm_element_count ;
static struct client_debug_mask client_debug_mask ;
/*
* Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and
* ORANGEFS_KMOD_DEBUG_FILE .
*/
static DEFINE_MUTEX ( orangefs_debug_lock ) ;
2016-11-04 16:32:25 -04:00
/* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */
static DEFINE_MUTEX ( orangefs_help_file_lock ) ;
2015-07-17 10:38:13 -04:00
/*
* initialize kmod debug operations , create orangefs debugfs dir and
* ORANGEFS_KMOD_DEBUG_HELP_FILE .
*/
2016-08-15 11:38:36 -04:00
int orangefs_debugfs_init ( int debug_mask )
2015-07-17 10:38:13 -04:00
{
int rc = - ENOMEM ;
2016-08-15 11:38:36 -04:00
/* convert input debug mask to a 64-bit unsigned integer */
orangefs_gossip_debug_mask = ( unsigned long long ) debug_mask ;
/*
* set the kernel ' s gossip debug string ; invalid mask values will
* be ignored .
*/
debug_mask_to_string ( & orangefs_gossip_debug_mask , 0 ) ;
/* remove any invalid values from the mask */
debug_string_to_mask ( kernel_debug_string , & orangefs_gossip_debug_mask ,
0 ) ;
/*
* if the mask has a non - zero value , then indicate that the mask
* was set when the kernel module was loaded . The orangefs dev ioctl
* command will look at this boolean to determine if the kernel ' s
* debug mask should be overwritten when the client - core is started .
*/
if ( orangefs_gossip_debug_mask ! = 0 )
kernel_mask_set_mod_init = true ;
pr_info ( " %s: called with debug mask: :%s: :%llx: \n " ,
__func__ ,
kernel_debug_string ,
( unsigned long long ) orangefs_gossip_debug_mask ) ;
2015-07-17 10:38:13 -04:00
debug_dir = debugfs_create_dir ( " orangefs " , NULL ) ;
2016-03-14 15:30:39 -04:00
if ( ! debug_dir ) {
pr_info ( " %s: debugfs_create_dir failed. \n " , __func__ ) ;
2015-07-17 10:38:13 -04:00
goto out ;
2016-03-14 15:30:39 -04:00
}
2015-07-17 10:38:13 -04:00
help_file_dentry = debugfs_create_file ( ORANGEFS_KMOD_DEBUG_HELP_FILE ,
0444 ,
debug_dir ,
debug_help_string ,
& debug_help_fops ) ;
2016-03-14 15:30:39 -04:00
if ( ! help_file_dentry ) {
pr_info ( " %s: debugfs_create_file failed. \n " , __func__ ) ;
2015-07-17 10:38:13 -04:00
goto out ;
2016-03-14 15:30:39 -04:00
}
2015-07-17 10:38:13 -04:00
orangefs_debug_disabled = 0 ;
2016-08-15 11:38:36 -04:00
rc = orangefs_kernel_debug_init ( ) ;
out :
return rc ;
}
/*
* initialize the kernel - debug file .
*/
static int orangefs_kernel_debug_init ( void )
{
int rc = - ENOMEM ;
struct dentry * ret ;
char * k_buffer = NULL ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: start \n " , __func__ ) ;
k_buffer = kzalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
if ( ! k_buffer )
goto out ;
if ( strlen ( kernel_debug_string ) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN ) {
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 ;
}
2015-07-17 10:38:13 -04:00
rc = 0 ;
out :
2016-08-15 11:38:36 -04:00
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: rc:%d: \n " , __func__ , rc ) ;
2015-07-17 10:38:13 -04:00
return rc ;
}
2016-08-15 11:38:36 -04:00
2015-11-24 15:12:14 -05:00
void orangefs_debugfs_cleanup ( void )
2015-07-17 10:38:13 -04:00
{
2016-03-27 02:54:23 +08:00
debugfs_remove_recursive ( debug_dir ) ;
2015-07-17 10:38:13 -04:00
}
/* 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 " ) ;
2016-11-04 16:32:25 -04:00
mutex_lock ( & orangefs_help_file_lock ) ;
2015-07-17 10:38:13 -04:00
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 " ) ;
2016-11-04 16:32:25 -04:00
mutex_unlock ( & orangefs_help_file_lock ) ;
2015-07-17 10:38:13 -04:00
}
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 client - debug file .
*/
2015-11-24 15:12:14 -05:00
int orangefs_client_debug_init ( void )
2015-07-17 10:38:13 -04:00
{
int rc = - ENOMEM ;
char * c_buffer = NULL ;
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: start \n " , __func__ ) ;
2015-11-24 15:12:14 -05:00
c_buffer = kzalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 10:38:13 -04:00
if ( ! c_buffer )
goto out ;
2015-11-24 15:12:14 -05:00
if ( strlen ( client_debug_string ) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN ) {
2015-07-17 10:38:13 -04: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 ) {
2016-03-14 15:30:39 -04:00
pr_info ( " %s: failed to create updated %s. \n " ,
2015-07-17 10:38:13 -04:00
__func__ ,
ORANGEFS_CLIENT_DEBUG_FILE ) ;
goto out ;
}
rc = 0 ;
out :
gossip_debug ( GOSSIP_DEBUGFS_DEBUG , " %s: rc:%d: \n " , __func__ , rc ) ;
return rc ;
}
/* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
2016-08-15 11:38:36 -04:00
static int orangefs_debug_open ( struct inode * inode , struct file * file )
2015-07-17 10:38:13 -04:00
{
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 15:12:14 -05:00
buf = kmalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 10:38:13 -04: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 15:12:14 -05:00
struct orangefs_kernel_op_s * new_op = NULL ;
2015-07-17 10:38:13 -04:00
struct client_debug_mask c_mask = { NULL , 0 , 0 } ;
2016-12-04 18:24:56 -05:00
char * s ;
2015-07-17 10:38:13 -04:00
gossip_debug ( GOSSIP_DEBUGFS_DEBUG ,
2016-08-07 12:20:01 -04:00
" orangefs_debug_write: %pD \n " ,
file ) ;
2015-07-17 10:38:13 -04:00
/*
* Thwart users who try to jamb a ridiculous number
* of bytes into the debug file . . .
*/
2015-11-24 15:12:14 -05:00
if ( count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1 ) {
2015-07-17 10:38:13 -04:00
silly = count ;
2015-11-24 15:12:14 -05:00
count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1 ;
2015-07-17 10:38:13 -04:00
}
2015-12-22 17:13:50 +01:00
buf = kzalloc ( ORANGEFS_MAX_DEBUG_STRING_LEN , GFP_KERNEL ) ;
2015-07-17 10:38:13 -04: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 ) ) {
2016-08-15 11:38:36 -04:00
debug_string_to_mask ( buf , & orangefs_gossip_debug_mask , 0 ) ;
debug_mask_to_string ( & orangefs_gossip_debug_mask , 0 ) ;
2015-07-17 10:38:13 -04:00
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 15:12:14 -05:00
new_op = op_alloc ( ORANGEFS_VFS_OP_PARAM ) ;
2015-07-17 10:38:13 -04:00
if ( ! new_op ) {
pr_info ( " %s: op_alloc failed! \n " , __func__ ) ;
goto out ;
}
new_op - > upcall . req . param . op =
2015-11-24 15:12:14 -05:00
ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES ;
new_op - > upcall . req . param . type = ORANGEFS_PARAM_REQUEST_SET ;
2015-07-17 10:38:13 -04:00
memset ( new_op - > upcall . req . param . s_value ,
0 ,
2015-11-24 15:12:14 -05:00
ORANGEFS_MAX_DEBUG_STRING_LEN ) ;
2015-07-17 10:38:13 -04: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 15:12:14 -05:00
" orangefs_param " ,
ORANGEFS_OP_INTERRUPTIBLE ) ;
2015-07-17 10:38:13 -04: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 ) ;
2016-12-04 18:24:56 -05:00
s = file_inode ( file ) - > i_private ;
memset ( s , 0 , ORANGEFS_MAX_DEBUG_STRING_LEN ) ;
sprintf ( s , " %s \n " , debug_string ) ;
2015-07-17 10:38:13 -04:00
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 ;
}
2016-08-15 11:38:36 -04:00
/*
* After obtaining a string representation of the client ' s debug
* keywords and their associated masks , this function is called to build an
* array of these values .
*/
static int orangefs_prepare_cdm_array ( char * debug_array_string )
{
int i ;
int rc = - EINVAL ;
char * cds_head = NULL ;
char * cds_delimiter = NULL ;
int keyword_len = 0 ;
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: start \n " , __func__ ) ;
/*
* figure out how many elements the cdm_array needs .
*/
for ( i = 0 ; i < strlen ( debug_array_string ) ; i + + )
if ( debug_array_string [ i ] = = ' \n ' )
cdm_element_count + + ;
if ( ! cdm_element_count ) {
pr_info ( " No elements in client debug array string! \n " ) ;
goto out ;
}
cdm_array =
kzalloc ( cdm_element_count * sizeof ( struct client_debug_mask ) ,
GFP_KERNEL ) ;
if ( ! cdm_array ) {
pr_info ( " malloc failed for cdm_array! \n " ) ;
rc = - ENOMEM ;
goto out ;
}
cds_head = debug_array_string ;
for ( i = 0 ; i < cdm_element_count ; i + + ) {
cds_delimiter = strchr ( cds_head , ' \n ' ) ;
* cds_delimiter = ' \0 ' ;
keyword_len = strcspn ( cds_head , " " ) ;
cdm_array [ i ] . keyword = kzalloc ( keyword_len + 1 , GFP_KERNEL ) ;
if ( ! cdm_array [ i ] . keyword ) {
rc = - ENOMEM ;
goto out ;
}
sscanf ( cds_head ,
" %s %llx %llx " ,
cdm_array [ i ] . keyword ,
( unsigned long long * ) & ( cdm_array [ i ] . mask1 ) ,
( unsigned long long * ) & ( cdm_array [ i ] . mask2 ) ) ;
if ( ! strcmp ( cdm_array [ i ] . keyword , ORANGEFS_VERBOSE ) )
client_verbose_index = i ;
if ( ! strcmp ( cdm_array [ i ] . keyword , ORANGEFS_ALL ) )
client_all_index = i ;
cds_head = cds_delimiter + 1 ;
}
rc = cdm_element_count ;
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: rc:%d: \n " , __func__ , rc ) ;
out :
return rc ;
}
/*
* / sys / kernel / debug / orangefs / debug - help can be catted to
* see all the available kernel and client debug keywords .
*
2016-11-04 16:32:25 -04:00
* When orangefs . ko initializes , we have no idea what keywords the
2016-08-15 11:38:36 -04:00
* client supports , nor their associated masks .
*
2016-11-04 16:32:25 -04:00
* We pass through this function once at module - load and stamp a
2016-08-15 11:38:36 -04:00
* boilerplate " we don't know " message for the client in the
* debug - help file . We pass through here again when the client
* starts and then we can fill out the debug - help file fully .
*
* The client might be restarted any number of times between
2016-11-04 16:32:25 -04:00
* module reloads , we only build the debug - help file the first time .
2016-08-15 11:38:36 -04:00
*/
int orangefs_prepare_debugfs_help_string ( int at_boot )
{
char * client_title = " Client Debug Keywords: \n " ;
char * kernel_title = " Kernel Debug Keywords: \n " ;
2016-11-04 16:32:25 -04:00
size_t string_size = DEBUG_HELP_STRING_SIZE ;
size_t result_size ;
size_t i ;
char * new ;
int rc = - EINVAL ;
2016-08-15 11:38:36 -04:00
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: start \n " , __func__ ) ;
2016-11-04 16:32:25 -04:00
if ( at_boot )
2016-08-15 11:38:36 -04:00
client_title = HELP_STRING_UNINITIALIZED ;
2016-11-04 16:32:25 -04:00
/* build a new debug_help_string. */
new = kzalloc ( DEBUG_HELP_STRING_SIZE , GFP_KERNEL ) ;
if ( ! new ) {
rc = - ENOMEM ;
goto out ;
}
/*
* strlcat ( dst , src , size ) will append at most
* " size - strlen(dst) - 1 " bytes of src onto dst ,
* null terminating the result , and return the total
* length of the string it tried to create .
*
* We ' ll just plow through here building our new debug
* help string and let strlcat take care of assuring that
* dst doesn ' t overflow .
*/
strlcat ( new , client_title , string_size ) ;
if ( ! at_boot ) {
/*
2016-08-15 11:38:36 -04:00
* fill the client keyword / mask array and remember
* how many elements there were .
*/
cdm_element_count =
orangefs_prepare_cdm_array ( client_debug_array_string ) ;
2016-12-02 15:18:06 +00:00
if ( cdm_element_count < = 0 ) {
kfree ( new ) ;
2016-08-15 11:38:36 -04:00
goto out ;
2016-12-02 15:18:06 +00:00
}
2016-08-15 11:38:36 -04:00
for ( i = 0 ; i < cdm_element_count ; i + + ) {
2016-11-04 16:32:25 -04:00
strlcat ( new , " \t " , string_size ) ;
strlcat ( new , cdm_array [ i ] . keyword , string_size ) ;
strlcat ( new , " \n " , string_size ) ;
2016-08-15 11:38:36 -04:00
}
}
2016-11-04 16:32:25 -04:00
strlcat ( new , " \n " , string_size ) ;
strlcat ( new , kernel_title , string_size ) ;
2016-08-15 11:38:36 -04:00
for ( i = 0 ; i < num_kmod_keyword_mask_map ; i + + ) {
2016-11-04 16:32:25 -04:00
strlcat ( new , " \t " , string_size ) ;
strlcat ( new , s_kmod_keyword_mask_map [ i ] . keyword , string_size ) ;
result_size = strlcat ( new , " \n " , string_size ) ;
2016-08-15 11:38:36 -04:00
}
2016-11-04 16:32:25 -04:00
/* See if we tried to put too many bytes into "new"... */
if ( result_size > = string_size ) {
kfree ( new ) ;
2016-08-15 11:38:36 -04:00
goto out ;
}
2016-11-04 16:32:25 -04:00
if ( at_boot ) {
debug_help_string = new ;
} else {
mutex_lock ( & orangefs_help_file_lock ) ;
memset ( debug_help_string , 0 , DEBUG_HELP_STRING_SIZE ) ;
strlcat ( debug_help_string , new , string_size ) ;
mutex_unlock ( & orangefs_help_file_lock ) ;
2016-08-15 11:38:36 -04:00
}
rc = 0 ;
2016-11-04 16:32:25 -04:00
out : return rc ;
2016-08-15 11:38:36 -04:00
}
/*
* kernel = type 0
* client = type 1
*/
static void debug_mask_to_string ( void * mask , int type )
{
int i ;
int len = 0 ;
char * debug_string ;
int element_count = 0 ;
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: start \n " , __func__ ) ;
if ( type ) {
debug_string = client_debug_string ;
element_count = cdm_element_count ;
} else {
debug_string = kernel_debug_string ;
element_count = num_kmod_keyword_mask_map ;
}
memset ( debug_string , 0 , ORANGEFS_MAX_DEBUG_STRING_LEN ) ;
/*
* Some keywords , like " all " or " verbose " , are amalgams of
* numerous other keywords . Make a special check for those
* before grinding through the whole mask only to find out
* later . . .
*/
if ( check_amalgam_keyword ( mask , type ) )
goto out ;
/* Build the debug string. */
for ( i = 0 ; i < element_count ; i + + )
if ( type )
do_c_string ( mask , i ) ;
else
do_k_string ( mask , i ) ;
len = strlen ( debug_string ) ;
if ( ( len ) & & ( type ) )
client_debug_string [ len - 1 ] = ' \0 ' ;
else if ( len )
kernel_debug_string [ len - 1 ] = ' \0 ' ;
else if ( type )
strcpy ( client_debug_string , " none " ) ;
else
strcpy ( kernel_debug_string , " none " ) ;
out :
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: string:%s: \n " , __func__ , debug_string ) ;
return ;
}
static void do_k_string ( void * k_mask , int index )
{
__u64 * mask = ( __u64 * ) k_mask ;
if ( keyword_is_amalgam ( ( char * ) s_kmod_keyword_mask_map [ index ] . keyword ) )
goto out ;
if ( * mask & s_kmod_keyword_mask_map [ index ] . mask_val ) {
if ( ( strlen ( kernel_debug_string ) +
strlen ( s_kmod_keyword_mask_map [ index ] . keyword ) )
< ORANGEFS_MAX_DEBUG_STRING_LEN - 1 ) {
strcat ( kernel_debug_string ,
s_kmod_keyword_mask_map [ index ] . keyword ) ;
strcat ( kernel_debug_string , " , " ) ;
} else {
gossip_err ( " %s: overflow! \n " , __func__ ) ;
strcpy ( kernel_debug_string , ORANGEFS_ALL ) ;
goto out ;
}
}
out :
return ;
}
static void do_c_string ( void * c_mask , int index )
{
struct client_debug_mask * mask = ( struct client_debug_mask * ) c_mask ;
if ( keyword_is_amalgam ( cdm_array [ index ] . keyword ) )
goto out ;
if ( ( mask - > mask1 & cdm_array [ index ] . mask1 ) | |
( mask - > mask2 & cdm_array [ index ] . mask2 ) ) {
if ( ( strlen ( client_debug_string ) +
strlen ( cdm_array [ index ] . keyword ) + 1 )
< ORANGEFS_MAX_DEBUG_STRING_LEN - 2 ) {
strcat ( client_debug_string ,
cdm_array [ index ] . keyword ) ;
strcat ( client_debug_string , " , " ) ;
} else {
gossip_err ( " %s: overflow! \n " , __func__ ) ;
strcpy ( client_debug_string , ORANGEFS_ALL ) ;
goto out ;
}
}
out :
return ;
}
static int keyword_is_amalgam ( char * keyword )
{
int rc = 0 ;
if ( ( ! strcmp ( keyword , ORANGEFS_ALL ) ) | | ( ! strcmp ( keyword , ORANGEFS_VERBOSE ) ) )
rc = 1 ;
return rc ;
}
/*
* kernel = type 0
* client = type 1
*
* return 1 if we found an amalgam .
*/
static int check_amalgam_keyword ( void * mask , int type )
{
__u64 * k_mask ;
struct client_debug_mask * c_mask ;
int k_all_index = num_kmod_keyword_mask_map - 1 ;
int rc = 0 ;
if ( type ) {
c_mask = ( struct client_debug_mask * ) mask ;
if ( ( c_mask - > mask1 = = cdm_array [ client_all_index ] . mask1 ) & &
( c_mask - > mask2 = = cdm_array [ client_all_index ] . mask2 ) ) {
strcpy ( client_debug_string , ORANGEFS_ALL ) ;
rc = 1 ;
goto out ;
}
if ( ( c_mask - > mask1 = = cdm_array [ client_verbose_index ] . mask1 ) & &
( c_mask - > mask2 = = cdm_array [ client_verbose_index ] . mask2 ) ) {
strcpy ( client_debug_string , ORANGEFS_VERBOSE ) ;
rc = 1 ;
goto out ;
}
} else {
k_mask = ( __u64 * ) mask ;
if ( * k_mask > = s_kmod_keyword_mask_map [ k_all_index ] . mask_val ) {
strcpy ( kernel_debug_string , ORANGEFS_ALL ) ;
rc = 1 ;
goto out ;
}
}
out :
return rc ;
}
/*
* kernel = type 0
* client = type 1
*/
static void debug_string_to_mask ( char * debug_string , void * mask , int type )
{
char * unchecked_keyword ;
int i ;
char * strsep_fodder = kstrdup ( debug_string , GFP_KERNEL ) ;
char * original_pointer ;
int element_count = 0 ;
struct client_debug_mask * c_mask = NULL ;
__u64 * k_mask = NULL ;
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: start \n " , __func__ ) ;
if ( type ) {
c_mask = ( struct client_debug_mask * ) mask ;
element_count = cdm_element_count ;
} else {
k_mask = ( __u64 * ) mask ;
* k_mask = 0 ;
element_count = num_kmod_keyword_mask_map ;
}
original_pointer = strsep_fodder ;
while ( ( unchecked_keyword = strsep ( & strsep_fodder , " , " ) ) )
if ( strlen ( unchecked_keyword ) ) {
for ( i = 0 ; i < element_count ; i + + )
if ( type )
do_c_mask ( i ,
unchecked_keyword ,
& c_mask ) ;
else
do_k_mask ( i ,
unchecked_keyword ,
& k_mask ) ;
}
kfree ( original_pointer ) ;
}
static void do_c_mask ( int i , char * unchecked_keyword ,
struct client_debug_mask * * sane_mask )
{
if ( ! strcmp ( cdm_array [ i ] . keyword , unchecked_keyword ) ) {
( * * sane_mask ) . mask1 = ( * * sane_mask ) . mask1 | cdm_array [ i ] . mask1 ;
( * * sane_mask ) . mask2 = ( * * sane_mask ) . mask2 | cdm_array [ i ] . mask2 ;
}
}
static void do_k_mask ( int i , char * unchecked_keyword , __u64 * * sane_mask )
{
if ( ! strcmp ( s_kmod_keyword_mask_map [ i ] . keyword , unchecked_keyword ) )
* * sane_mask = ( * * sane_mask ) |
s_kmod_keyword_mask_map [ i ] . mask_val ;
}
int orangefs_debugfs_new_client_mask ( void __user * arg )
{
struct dev_mask2_info_s mask2_info = { 0 } ;
int ret ;
ret = copy_from_user ( & mask2_info ,
( void __user * ) arg ,
sizeof ( struct dev_mask2_info_s ) ) ;
if ( ret ! = 0 )
return - EIO ;
client_debug_mask . mask1 = mask2_info . mask1_value ;
client_debug_mask . mask2 = mask2_info . mask2_value ;
pr_info ( " %s: client debug mask has been been received "
" :%llx: :%llx: \n " ,
__func__ ,
( unsigned long long ) client_debug_mask . mask1 ,
( unsigned long long ) client_debug_mask . mask2 ) ;
return ret ;
}
int orangefs_debugfs_new_client_string ( void __user * arg )
{
int ret ;
ret = copy_from_user ( & client_debug_array_string ,
2017-02-09 14:38:50 -05:00
( void __user * ) arg ,
ORANGEFS_MAX_DEBUG_STRING_LEN ) ;
2016-11-04 16:32:25 -04:00
if ( ret ! = 0 ) {
pr_info ( " %s: CLIENT_STRING: copy_from_user failed \n " ,
__func__ ) ;
2017-02-09 14:38:50 -05:00
return - EFAULT ;
2016-11-04 16:32:25 -04:00
}
2016-08-15 11:38:36 -04:00
/*
* The real client - core makes an effort to ensure
* that actual strings that aren ' t too long to fit in
* this buffer is what we get here . We ' re going to use
* string functions on the stuff we got , so we ' ll make
* this extra effort to try and keep from
* flowing out of this buffer when we use the string
* functions , even if somehow the stuff we end up
* with here is garbage .
*/
client_debug_array_string [ ORANGEFS_MAX_DEBUG_STRING_LEN - 1 ] =
' \0 ' ;
2017-02-09 14:38:50 -05:00
2016-08-15 11:38:36 -04:00
pr_info ( " %s: client debug array string has been received. \n " ,
__func__ ) ;
if ( ! help_string_initialized ) {
2016-11-04 16:32:25 -04:00
/* Build a proper debug help string. */
2017-02-09 14:38:50 -05:00
ret = orangefs_prepare_debugfs_help_string ( 0 ) ;
if ( ret ) {
2016-08-15 11:38:36 -04:00
gossip_err ( " %s: no debug help string \n " ,
__func__ ) ;
2017-02-09 14:38:50 -05:00
return ret ;
2016-08-15 11:38:36 -04:00
}
}
debug_mask_to_string ( & client_debug_mask , 1 ) ;
debugfs_remove ( client_debug_dentry ) ;
orangefs_client_debug_init ( ) ;
help_string_initialized + + ;
2017-02-09 14:38:50 -05:00
return 0 ;
2016-08-15 11:38:36 -04:00
}
int orangefs_debugfs_new_debug ( void __user * arg )
{
struct dev_mask_info_s mask_info = { 0 } ;
int ret ;
ret = copy_from_user ( & mask_info ,
( void __user * ) arg ,
sizeof ( mask_info ) ) ;
if ( ret ! = 0 )
return - EIO ;
if ( mask_info . mask_type = = KERNEL_MASK ) {
if ( ( mask_info . mask_value = = 0 )
& & ( kernel_mask_set_mod_init ) ) {
/*
* the kernel debug mask was set when the
* kernel module was loaded ; don ' t override
* it if the client - core was started without
* a value for ORANGEFS_KMODMASK .
*/
return 0 ;
}
debug_mask_to_string ( & mask_info . mask_value ,
mask_info . mask_type ) ;
orangefs_gossip_debug_mask = mask_info . mask_value ;
pr_info ( " %s: kernel debug mask has been modified to "
" :%s: :%llx: \n " ,
__func__ ,
kernel_debug_string ,
( unsigned long long ) orangefs_gossip_debug_mask ) ;
} else if ( mask_info . mask_type = = CLIENT_MASK ) {
debug_mask_to_string ( & mask_info . mask_value ,
mask_info . mask_type ) ;
pr_info ( " %s: client debug mask has been modified to "
" :%s: :%llx: \n " ,
__func__ ,
client_debug_string ,
llu ( mask_info . mask_value ) ) ;
} else {
gossip_lerr ( " Invalid mask type.... \n " ) ;
return - EINVAL ;
}
return ret ;
}