2023-11-16 19:44:01 -05:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2023 Red Hat
*/
# include "logger.h"
2024-02-13 10:51:19 -05:00
# include <asm/current.h>
2023-11-16 19:44:01 -05:00
# include <linux/delay.h>
# include <linux/hardirq.h>
# include <linux/module.h>
# include <linux/printk.h>
# include <linux/sched.h>
2024-02-09 13:17:05 -06:00
# include "errors.h"
2023-11-16 19:44:01 -05:00
# include "thread-device.h"
2024-02-09 10:10:03 -06:00
# include "thread-utils.h"
2023-11-16 19:44:01 -05:00
2024-02-14 09:22:04 -06:00
int vdo_log_level = VDO_LOG_DEFAULT ;
2023-11-16 19:44:01 -05:00
2024-02-14 09:22:04 -06:00
int vdo_get_log_level ( void )
2023-11-16 19:44:01 -05:00
{
2024-02-10 10:42:00 -06:00
int log_level_latch = READ_ONCE ( vdo_log_level ) ;
2024-02-14 09:22:04 -06:00
if ( unlikely ( log_level_latch > VDO_LOG_MAX ) ) {
log_level_latch = VDO_LOG_DEFAULT ;
2024-02-10 10:42:00 -06:00
WRITE_ONCE ( vdo_log_level , log_level_latch ) ;
}
return log_level_latch ;
2023-11-16 19:44:01 -05:00
}
static const char * get_current_interrupt_type ( void )
{
if ( in_nmi ( ) )
return " NMI " ;
if ( in_irq ( ) )
return " HI " ;
if ( in_softirq ( ) )
return " SI " ;
return " INTR " ;
}
/**
* emit_log_message_to_kernel ( ) - Emit a log message to the kernel at the specified priority .
*
* @ priority : The priority at which to log the message
* @ fmt : The format string of the message
*/
static void emit_log_message_to_kernel ( int priority , const char * fmt , . . . )
{
va_list args ;
struct va_format vaf ;
2024-02-14 09:22:04 -06:00
if ( priority > vdo_get_log_level ( ) )
2023-11-16 19:44:01 -05:00
return ;
va_start ( args , fmt ) ;
vaf . fmt = fmt ;
vaf . va = & args ;
switch ( priority ) {
2024-02-14 09:22:04 -06:00
case VDO_LOG_EMERG :
case VDO_LOG_ALERT :
case VDO_LOG_CRIT :
2024-02-14 18:25:14 -05:00
pr_crit ( " %pV " , & vaf ) ;
2023-11-16 19:44:01 -05:00
break ;
2024-02-14 09:22:04 -06:00
case VDO_LOG_ERR :
2024-02-14 18:25:14 -05:00
pr_err ( " %pV " , & vaf ) ;
2023-11-16 19:44:01 -05:00
break ;
2024-02-14 09:22:04 -06:00
case VDO_LOG_WARNING :
2024-02-14 18:25:14 -05:00
pr_warn ( " %pV " , & vaf ) ;
2023-11-16 19:44:01 -05:00
break ;
2024-02-14 09:22:04 -06:00
case VDO_LOG_NOTICE :
case VDO_LOG_INFO :
2024-02-14 18:25:14 -05:00
pr_info ( " %pV " , & vaf ) ;
2023-11-16 19:44:01 -05:00
break ;
2024-02-14 09:22:04 -06:00
case VDO_LOG_DEBUG :
2024-02-14 18:25:14 -05:00
pr_debug ( " %pV " , & vaf ) ;
2023-11-16 19:44:01 -05:00
break ;
default :
printk ( KERN_DEFAULT " %pV " , & vaf ) ;
break ;
}
va_end ( args ) ;
}
/**
* emit_log_message ( ) - Emit a log message to the kernel log in a format suited to the current
* thread context .
*
* Context info formats :
*
* interrupt : uds [ NMI ] : blah
* kvdo thread : kvdo12 : foobarQ : blah
* thread w / device id : kvdo12 : myprog : blah
* other thread : uds : myprog : blah
*
* Fields : module name , interrupt level , process name , device ID .
*
* @ priority : the priority at which to log the message
* @ module : The name of the module doing the logging
* @ prefix : The prefix of the log message
* @ vaf1 : The first message format descriptor
* @ vaf2 : The second message format descriptor
*/
static void emit_log_message ( int priority , const char * module , const char * prefix ,
const struct va_format * vaf1 , const struct va_format * vaf2 )
{
int device_instance ;
/*
* In interrupt context , identify the interrupt type and module . Ignore the process / thread
* since it could be anything .
*/
if ( in_interrupt ( ) ) {
const char * type = get_current_interrupt_type ( ) ;
emit_log_message_to_kernel ( priority , " %s[%s]: %s%pV%pV \n " , module , type ,
prefix , vaf1 , vaf2 ) ;
return ;
}
/* Not at interrupt level; we have a process we can look at, and might have a device ID. */
2024-02-09 14:53:05 -06:00
device_instance = vdo_get_thread_device_id ( ) ;
2023-11-16 19:44:01 -05:00
if ( device_instance > = 0 ) {
emit_log_message_to_kernel ( priority , " %s%u:%s: %s%pV%pV \n " , module ,
device_instance , current - > comm , prefix , vaf1 ,
vaf2 ) ;
return ;
}
/*
* If it ' s a kernel thread and the module name is a prefix of its name , assume it is ours
* and only identify the thread .
*/
if ( ( ( current - > flags & PF_KTHREAD ) ! = 0 ) & &
( strncmp ( module , current - > comm , strlen ( module ) ) = = 0 ) ) {
emit_log_message_to_kernel ( priority , " %s: %s%pV%pV \n " , current - > comm ,
prefix , vaf1 , vaf2 ) ;
return ;
}
/* Identify the module and the process. */
emit_log_message_to_kernel ( priority , " %s: %s: %s%pV%pV \n " , module , current - > comm ,
prefix , vaf1 , vaf2 ) ;
}
/*
2024-02-14 09:22:04 -06:00
* vdo_log_embedded_message ( ) - Log a message embedded within another message .
2023-11-16 19:44:01 -05:00
* @ priority : the priority at which to log the message
* @ module : the name of the module doing the logging
* @ prefix : optional string prefix to message , may be NULL
* @ fmt1 : format of message first part ( required )
* @ args1 : arguments for message first part ( required )
* @ fmt2 : format of message second part
*/
2024-02-14 09:22:04 -06:00
void vdo_log_embedded_message ( int priority , const char * module , const char * prefix ,
2023-11-16 19:44:01 -05:00
const char * fmt1 , va_list args1 , const char * fmt2 , . . . )
{
va_list args1_copy ;
va_list args2 ;
struct va_format vaf1 , vaf2 ;
va_start ( args2 , fmt2 ) ;
if ( module = = NULL )
2024-02-14 09:22:04 -06:00
module = VDO_LOGGING_MODULE_NAME ;
2023-11-16 19:44:01 -05:00
if ( prefix = = NULL )
prefix = " " ;
/*
* It is implementation dependent whether va_list is defined as an array type that decays
* to a pointer when passed as an argument . Copy args1 and args2 with va_copy so that vaf1
* and vaf2 get proper va_list pointers irrespective of how va_list is defined .
*/
va_copy ( args1_copy , args1 ) ;
vaf1 . fmt = fmt1 ;
vaf1 . va = & args1_copy ;
vaf2 . fmt = fmt2 ;
vaf2 . va = & args2 ;
emit_log_message ( priority , module , prefix , & vaf1 , & vaf2 ) ;
va_end ( args1_copy ) ;
va_end ( args2 ) ;
}
2024-02-14 09:22:04 -06:00
int vdo_vlog_strerror ( int priority , int errnum , const char * module , const char * format ,
2023-11-16 19:44:01 -05:00
va_list args )
{
2024-02-14 09:22:04 -06:00
char errbuf [ VDO_MAX_ERROR_MESSAGE_SIZE ] ;
2023-11-16 19:44:01 -05:00
const char * message = uds_string_error ( errnum , errbuf , sizeof ( errbuf ) ) ;
2024-02-14 09:22:04 -06:00
vdo_log_embedded_message ( priority , module , NULL , format , args , " : %s (%d) " ,
2023-11-16 19:44:01 -05:00
message , errnum ) ;
return errnum ;
}
2024-02-14 09:22:04 -06:00
int __vdo_log_strerror ( int priority , int errnum , const char * module , const char * format , . . . )
2023-11-16 19:44:01 -05:00
{
va_list args ;
va_start ( args , format ) ;
2024-02-14 09:22:04 -06:00
vdo_vlog_strerror ( priority , errnum , module , format , args ) ;
2023-11-16 19:44:01 -05:00
va_end ( args ) ;
return errnum ;
}
2024-02-14 09:22:04 -06:00
void vdo_log_backtrace ( int priority )
2023-11-16 19:44:01 -05:00
{
2024-02-14 09:22:04 -06:00
if ( priority > vdo_get_log_level ( ) )
2023-11-16 19:44:01 -05:00
return ;
dump_stack ( ) ;
}
2024-02-14 09:22:04 -06:00
void __vdo_log_message ( int priority , const char * module , const char * format , . . . )
2023-11-16 19:44:01 -05:00
{
va_list args ;
va_start ( args , format ) ;
2024-02-14 09:22:04 -06:00
vdo_log_embedded_message ( priority , module , NULL , format , args , " %s " , " " ) ;
2023-11-16 19:44:01 -05:00
va_end ( args ) ;
}
/*
* Sleep or delay a few milliseconds in an attempt to allow the log buffers to be flushed lest they
* be overrun .
*/
2024-02-14 09:22:04 -06:00
void vdo_pause_for_logger ( void )
2023-11-16 19:44:01 -05:00
{
fsleep ( 4000 ) ;
}