2006-01-02 21:04:38 +03:00
/*
2006-10-17 08:42:04 +04:00
* net / tipc / dbg . c : TIPC print buffer routines for debugging
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 1996 - 2006 , Ericsson AB
2008-05-05 12:20:42 +04:00
* Copyright ( c ) 2005 - 2007 , Wind River Systems
2006-01-02 21:04:38 +03:00
* All rights reserved .
*
2006-01-11 15:30:43 +03:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 21:04:38 +03:00
* modification , are permitted provided that the following conditions are met :
*
2006-01-11 15:30:43 +03:00
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
2006-01-02 21:04:38 +03:00
*
2006-01-11 15:30:43 +03:00
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
2006-01-02 21:04:38 +03:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "config.h"
# include "dbg.h"
2008-05-05 12:22:30 +04:00
/*
* TIPC pre - defines the following print buffers :
*
* TIPC_NULL : null buffer ( i . e . print nowhere )
* TIPC_CONS : system console
* TIPC_LOG : TIPC log buffer
*
* Additional user - defined print buffers are also permitted .
*/
2006-01-02 21:04:38 +03:00
2008-05-05 12:22:30 +04:00
static struct print_buf null_buf = { NULL , 0 , NULL , 0 } ;
2008-05-05 12:22:59 +04:00
struct print_buf * const TIPC_NULL = & null_buf ;
2006-10-17 08:42:04 +04:00
2008-05-05 12:22:30 +04:00
static struct print_buf cons_buf = { NULL , 0 , NULL , 1 } ;
2008-05-05 12:22:59 +04:00
struct print_buf * const TIPC_CONS = & cons_buf ;
2006-01-02 21:04:38 +03:00
2008-05-05 12:22:30 +04:00
static struct print_buf log_buf = { NULL , 0 , NULL , 1 } ;
2008-05-05 12:22:59 +04:00
struct print_buf * const TIPC_LOG = & log_buf ;
2006-01-02 21:04:38 +03:00
2008-05-05 12:22:30 +04:00
/*
* Locking policy when using print buffers .
*
* 1 ) tipc_printf ( ) uses ' print_lock ' to protect against concurrent access to
* ' print_string ' when writing to a print buffer . This also protects against
* concurrent writes to the print buffer being written to .
*
* 2 ) tipc_dump ( ) and tipc_log_XXX ( ) leverage the aforementioned
* use of ' print_lock ' to protect against all types of concurrent operations
* on their associated print buffer ( not just write operations ) .
*
* Note : All routines of the form tipc_printbuf_XXX ( ) are lock - free , and rely
* on the caller to prevent simultaneous use of the print buffer ( s ) being
* manipulated .
*/
static char print_string [ TIPC_PB_MAX_STR ] ;
static DEFINE_SPINLOCK ( print_lock ) ;
2006-01-02 21:04:38 +03:00
# define FORMAT(PTR,LEN,FMT) \
{ \
va_list args ; \
va_start ( args , FMT ) ; \
LEN = vsprintf ( PTR , FMT , args ) ; \
va_end ( args ) ; \
* ( PTR + LEN ) = ' \0 ' ; \
}
/**
2006-01-18 02:38:21 +03:00
* tipc_printbuf_init - initialize print buffer to empty
2006-10-17 08:42:04 +04:00
* @ pb : pointer to print buffer structure
* @ raw : pointer to character array used by print buffer
* @ size : size of character array
*
2008-05-05 12:22:30 +04:00
* Note : If the character array is too small ( or absent ) , the print buffer
* becomes a null device that discards anything written to it .
2006-01-02 21:04:38 +03:00
*/
2006-10-17 08:42:04 +04:00
void tipc_printbuf_init ( struct print_buf * pb , char * raw , u32 size )
2006-01-02 21:04:38 +03:00
{
2006-10-17 08:42:04 +04:00
pb - > buf = raw ;
pb - > crs = raw ;
pb - > size = size ;
2008-05-05 12:22:30 +04:00
pb - > echo = 0 ;
2006-10-17 08:42:04 +04:00
if ( size < TIPC_PB_MIN_SIZE ) {
pb - > buf = NULL ;
} else if ( raw ) {
pb - > buf [ 0 ] = 0 ;
2008-05-05 12:22:59 +04:00
pb - > buf [ size - 1 ] = ~ 0 ;
2006-10-17 08:42:04 +04:00
}
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_printbuf_reset - reinitialize print buffer to empty state
2006-10-17 08:42:04 +04:00
* @ pb : pointer to print buffer structure
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
void tipc_printbuf_reset ( struct print_buf * pb )
2006-01-02 21:04:38 +03:00
{
2008-05-05 12:22:59 +04:00
if ( pb - > buf ) {
2008-05-05 12:22:30 +04:00
pb - > crs = pb - > buf ;
pb - > buf [ 0 ] = 0 ;
pb - > buf [ pb - > size - 1 ] = ~ 0 ;
}
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_printbuf_empty - test if print buffer is in empty state
2006-10-17 08:42:04 +04:00
* @ pb : pointer to print buffer structure
*
* Returns non - zero if print buffer is empty .
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
int tipc_printbuf_empty ( struct print_buf * pb )
2006-01-02 21:04:38 +03:00
{
2006-10-17 08:42:04 +04:00
return ( ! pb - > buf | | ( pb - > crs = = pb - > buf ) ) ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_printbuf_validate - check for print buffer overflow
2006-10-17 08:42:04 +04:00
* @ pb : pointer to print buffer structure
2007-02-09 17:25:21 +03:00
*
* Verifies that a print buffer has captured all data written to it .
2006-01-02 21:04:38 +03:00
* If data has been lost , linearize buffer and prepend an error message
2007-02-09 17:25:21 +03:00
*
2006-10-17 08:42:04 +04:00
* Returns length of print buffer data string ( including trailing NUL )
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
int tipc_printbuf_validate ( struct print_buf * pb )
2006-01-02 21:04:38 +03:00
{
2007-02-09 17:25:21 +03:00
char * err = " \n \n *** PRINT BUFFER OVERFLOW *** \n \n " ;
char * cp_buf ;
struct print_buf cb ;
2006-01-02 21:04:38 +03:00
2006-10-17 08:42:04 +04:00
if ( ! pb - > buf )
2006-01-02 21:04:38 +03:00
return 0 ;
2006-10-17 08:42:04 +04:00
if ( pb - > buf [ pb - > size - 1 ] = = 0 ) {
2007-02-09 17:25:21 +03:00
cp_buf = kmalloc ( pb - > size , GFP_ATOMIC ) ;
2008-05-05 12:22:59 +04:00
if ( cp_buf ) {
2007-02-09 17:25:21 +03:00
tipc_printbuf_init ( & cb , cp_buf , pb - > size ) ;
tipc_printbuf_move ( & cb , pb ) ;
tipc_printbuf_move ( pb , & cb ) ;
kfree ( cp_buf ) ;
memcpy ( pb - > buf , err , strlen ( err ) ) ;
} else {
tipc_printbuf_reset ( pb ) ;
tipc_printf ( pb , err ) ;
}
2006-01-02 21:04:38 +03:00
}
return ( pb - > crs - pb - > buf + 1 ) ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_printbuf_move - move print buffer contents to another print buffer
2006-10-17 08:42:04 +04:00
* @ pb_to : pointer to destination print buffer structure
* @ pb_from : pointer to source print buffer structure
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Current contents of destination print buffer ( if any ) are discarded .
* Source print buffer becomes empty if a successful move occurs .
*/
2006-01-18 02:38:21 +03:00
void tipc_printbuf_move ( struct print_buf * pb_to , struct print_buf * pb_from )
2006-01-02 21:04:38 +03:00
{
int len ;
/* Handle the cases where contents can't be moved */
2006-10-17 08:42:04 +04:00
if ( ! pb_to - > buf )
2006-01-02 21:04:38 +03:00
return ;
2006-10-17 08:42:04 +04:00
if ( ! pb_from - > buf ) {
2006-01-18 02:38:21 +03:00
tipc_printbuf_reset ( pb_to ) ;
2006-01-02 21:04:38 +03:00
return ;
}
if ( pb_to - > size < pb_from - > size ) {
2008-05-05 12:21:12 +04:00
strcpy ( pb_to - > buf , " *** PRINT BUFFER MOVE ERROR *** " ) ;
pb_to - > buf [ pb_to - > size - 1 ] = ~ 0 ;
pb_to - > crs = strchr ( pb_to - > buf , 0 ) ;
2006-01-02 21:04:38 +03:00
return ;
}
/* Copy data from char after cursor to end (if used) */
2006-10-17 08:42:04 +04:00
2006-01-02 21:04:38 +03:00
len = pb_from - > buf + pb_from - > size - pb_from - > crs - 2 ;
2008-05-05 12:22:59 +04:00
if ( ( pb_from - > buf [ pb_from - > size - 1 ] = = 0 ) & & ( len > 0 ) ) {
2006-01-02 21:04:38 +03:00
strcpy ( pb_to - > buf , pb_from - > crs + 1 ) ;
pb_to - > crs = pb_to - > buf + len ;
} else
pb_to - > crs = pb_to - > buf ;
/* Copy data from start to cursor (always) */
2006-10-17 08:42:04 +04:00
2006-01-02 21:04:38 +03:00
len = pb_from - > crs - pb_from - > buf ;
strcpy ( pb_to - > crs , pb_from - > buf ) ;
pb_to - > crs + = len ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_reset ( pb_from ) ;
2006-01-02 21:04:38 +03:00
}
/**
2008-05-05 12:22:30 +04:00
* tipc_printf - append formatted output to print buffer
* @ pb : pointer to print buffer
2006-10-17 08:42:04 +04:00
* @ fmt : formatted info to be printed
2006-01-02 21:04:38 +03:00
*/
void tipc_printf ( struct print_buf * pb , const char * fmt , . . . )
{
int chars_to_add ;
int chars_left ;
char save_char ;
spin_lock_bh ( & print_lock ) ;
2008-05-05 12:22:30 +04:00
2006-01-02 21:04:38 +03:00
FORMAT ( print_string , chars_to_add , fmt ) ;
2006-10-17 08:42:04 +04:00
if ( chars_to_add > = TIPC_PB_MAX_STR )
strcpy ( print_string , " *** PRINT BUFFER STRING TOO LONG *** " ) ;
2006-01-02 21:04:38 +03:00
2008-05-05 12:22:30 +04:00
if ( pb - > buf ) {
chars_left = pb - > buf + pb - > size - pb - > crs - 1 ;
if ( chars_to_add < = chars_left ) {
strcpy ( pb - > crs , print_string ) ;
pb - > crs + = chars_to_add ;
} else if ( chars_to_add > = ( pb - > size - 1 ) ) {
strcpy ( pb - > buf , print_string + chars_to_add + 1
- pb - > size ) ;
pb - > crs = pb - > buf + pb - > size - 1 ;
} else {
strcpy ( pb - > buf , print_string + chars_left ) ;
save_char = print_string [ chars_left ] ;
print_string [ chars_left ] = 0 ;
strcpy ( pb - > crs , print_string ) ;
print_string [ chars_left ] = save_char ;
pb - > crs = pb - > buf + chars_to_add - chars_left ;
2007-02-09 17:25:21 +03:00
}
2006-01-02 21:04:38 +03:00
}
2008-05-05 12:22:30 +04:00
if ( pb - > echo )
2009-03-19 05:11:29 +03:00
printk ( " %s " , print_string ) ;
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & print_lock ) ;
}
2008-05-05 12:24:06 +04:00
# ifdef CONFIG_TIPC_DEBUG
2006-01-02 21:04:38 +03:00
/**
* print_to_console - write string of bytes to console in multiple chunks
*/
static void print_to_console ( char * crs , int len )
{
int rest = len ;
while ( rest > 0 ) {
2006-10-17 08:42:04 +04:00
int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR ;
2006-01-02 21:04:38 +03:00
char c = crs [ sz ] ;
crs [ sz ] = 0 ;
printk ( ( const char * ) crs ) ;
crs [ sz ] = c ;
rest - = sz ;
crs + = sz ;
}
}
/**
* printbuf_dump - write print buffer contents to console
*/
static void printbuf_dump ( struct print_buf * pb )
{
int len ;
2006-10-17 08:42:04 +04:00
if ( ! pb - > buf ) {
printk ( " *** PRINT BUFFER NOT ALLOCATED *** " ) ;
return ;
}
2006-01-02 21:04:38 +03:00
/* Dump print buffer from char after cursor to end (if used) */
2006-10-17 08:42:04 +04:00
2006-01-02 21:04:38 +03:00
len = pb - > buf + pb - > size - pb - > crs - 2 ;
if ( ( pb - > buf [ pb - > size - 1 ] = = 0 ) & & ( len > 0 ) )
print_to_console ( pb - > crs + 1 , len ) ;
/* Dump print buffer from start to cursor (always) */
2006-10-17 08:42:04 +04:00
2006-01-02 21:04:38 +03:00
len = pb - > crs - pb - > buf ;
print_to_console ( pb - > buf , len ) ;
}
/**
2008-05-05 12:24:06 +04:00
* tipc_dump_dbg - dump ( non - console ) print buffer to console
2008-05-05 12:22:30 +04:00
* @ pb : pointer to print buffer
2006-01-02 21:04:38 +03:00
*/
2008-05-05 12:24:06 +04:00
void tipc_dump_dbg ( struct print_buf * pb , const char * fmt , . . . )
2006-01-02 21:04:38 +03:00
{
int len ;
2008-05-05 12:22:30 +04:00
if ( pb = = TIPC_CONS )
return ;
2006-01-02 21:04:38 +03:00
spin_lock_bh ( & print_lock ) ;
2008-05-05 12:22:30 +04:00
2006-10-17 08:42:04 +04:00
FORMAT ( print_string , len , fmt ) ;
printk ( print_string ) ;
2006-01-02 21:04:38 +03:00
2008-05-05 12:22:30 +04:00
printk ( " \n ---- Start of %s log dump ---- \n \n " ,
( pb = = TIPC_LOG ) ? " global " : " local " ) ;
printbuf_dump ( pb ) ;
tipc_printbuf_reset ( pb ) ;
printk ( " \n ---- End of dump ---- \n " ) ;
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & print_lock ) ;
}
2008-05-05 12:24:06 +04:00
# endif
2006-01-02 21:04:38 +03:00
/**
2008-05-05 12:20:04 +04:00
* tipc_log_resize - change the size of the TIPC log buffer
* @ log_size : print buffer size to use
2006-01-02 21:04:38 +03:00
*/
2008-05-05 12:20:42 +04:00
int tipc_log_resize ( int log_size )
2006-01-02 21:04:38 +03:00
{
2008-05-05 12:20:42 +04:00
int res = 0 ;
2006-01-02 21:04:38 +03:00
spin_lock_bh ( & print_lock ) ;
2006-01-18 02:38:21 +03:00
if ( TIPC_LOG - > buf ) {
kfree ( TIPC_LOG - > buf ) ;
TIPC_LOG - > buf = NULL ;
2006-01-02 21:04:38 +03:00
}
if ( log_size ) {
2006-10-17 08:42:04 +04:00
if ( log_size < TIPC_PB_MIN_SIZE )
log_size = TIPC_PB_MIN_SIZE ;
2008-05-05 12:22:30 +04:00
res = TIPC_LOG - > echo ;
2006-10-17 08:42:04 +04:00
tipc_printbuf_init ( TIPC_LOG , kmalloc ( log_size , GFP_ATOMIC ) ,
log_size ) ;
2008-05-05 12:22:30 +04:00
TIPC_LOG - > echo = res ;
2008-05-05 12:20:42 +04:00
res = ! TIPC_LOG - > buf ;
2006-01-02 21:04:38 +03:00
}
2008-05-05 12:20:04 +04:00
spin_unlock_bh ( & print_lock ) ;
2008-05-05 12:20:42 +04:00
return res ;
2006-01-02 21:04:38 +03:00
}
/**
2008-05-05 12:20:04 +04:00
* tipc_log_resize_cmd - reconfigure size of TIPC log buffer
2006-01-02 21:04:38 +03:00
*/
2008-05-05 12:20:04 +04:00
struct sk_buff * tipc_log_resize_cmd ( const void * req_tlv_area , int req_tlv_space )
2006-01-02 21:04:38 +03:00
{
u32 value ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_UNSIGNED ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 21:04:38 +03:00
2006-11-08 11:19:09 +03:00
value = ntohl ( * ( __be32 * ) TLV_DATA ( req_tlv_area ) ) ;
2006-01-02 21:04:38 +03:00
if ( value ! = delimit ( value , 0 , 32768 ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_INVALID_VALUE
" (log size must be 0-32768) " ) ;
2008-05-05 12:20:42 +04:00
if ( tipc_log_resize ( value ) )
return tipc_cfg_reply_error_string (
" unable to create specified log (log size is now 0) " ) ;
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_none ( ) ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_log_dump - capture TIPC log buffer contents in configuration message
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_log_dump ( void )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * reply ;
spin_lock_bh ( & print_lock ) ;
2008-05-05 12:21:12 +04:00
if ( ! TIPC_LOG - > buf ) {
spin_unlock_bh ( & print_lock ) ;
2006-01-18 02:38:21 +03:00
reply = tipc_cfg_reply_ultra_string ( " log not activated \n " ) ;
2008-05-05 12:21:12 +04:00
} else if ( tipc_printbuf_empty ( TIPC_LOG ) ) {
spin_unlock_bh ( & print_lock ) ;
2006-01-18 02:38:21 +03:00
reply = tipc_cfg_reply_ultra_string ( " log is empty \n " ) ;
2008-05-05 12:21:12 +04:00
}
2006-01-02 21:04:38 +03:00
else {
struct tlv_desc * rep_tlv ;
struct print_buf pb ;
int str_len ;
2006-01-18 02:38:21 +03:00
str_len = min ( TIPC_LOG - > size , 32768u ) ;
2008-05-05 12:21:12 +04:00
spin_unlock_bh ( & print_lock ) ;
2006-01-18 02:38:21 +03:00
reply = tipc_cfg_reply_alloc ( TLV_SPACE ( str_len ) ) ;
2006-01-02 21:04:38 +03:00
if ( reply ) {
rep_tlv = ( struct tlv_desc * ) reply - > data ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_init ( & pb , TLV_DATA ( rep_tlv ) , str_len ) ;
2008-05-05 12:21:12 +04:00
spin_lock_bh ( & print_lock ) ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_move ( & pb , TIPC_LOG ) ;
2008-05-05 12:21:12 +04:00
spin_unlock_bh ( & print_lock ) ;
2006-01-02 21:04:38 +03:00
str_len = strlen ( TLV_DATA ( rep_tlv ) ) + 1 ;
skb_put ( reply , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
}
}
return reply ;
}