diff --git a/qdf/inc/qdf_trace.h b/qdf/inc/qdf_trace.h index 0e61330af1..7795abed07 100644 --- a/qdf/inc/qdf_trace.h +++ b/qdf/inc/qdf_trace.h @@ -596,6 +596,43 @@ QDF_STATUS qdf_trace_spin_lock_init(void) #endif #endif +#ifdef WLAN_MAX_LOGS_PER_SEC +/** + * qdf_detected_excessive_logging() - Excessive logging detected + * + * Track logging count using a quasi-tumbling window. + * If the max logging count for a given window is exceeded, + * return true else fails. + * + * Return: true/false + */ +bool qdf_detected_excessive_logging(void); + +/** + * qdf_rl_print_count_set() - set the ratelimiting print count + * @rl_print_time: ratelimiting print count + * + * Return: none + */ +void qdf_rl_print_count_set(uint32_t rl_print_count); + +/** + * qdf_rl_print_time_set() - set the ratelimiting print time + * @rl_print_time: ratelimiting print time + * + * Return: none + */ +void qdf_rl_print_time_set(uint32_t rl_print_time); + +#else /* WLAN_MAX_LOGS_PER_SEC */ +static inline bool qdf_detected_excessive_logging(void) +{ + return false; +} +static inline void qdf_rl_print_count_set(uint32_t rl_print_count) {} +static inline void qdf_rl_print_time_set(uint32_t rl_print_time) {} +#endif /* WLAN_MAX_LOGS_PER_SEC */ + #ifdef ENABLE_MTRACE_LOG /** * qdf_mtrace_log() - Logs a message tracepoint to DIAG diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index 1d81721ece..abb142be78 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -3207,9 +3207,86 @@ void qdf_trace_display(void) } qdf_export_symbol(qdf_trace_display); +#ifdef WLAN_MAX_LOGS_PER_SEC +static qdf_time_t __log_window_end; +static qdf_atomic_t __log_window_count; +uint32_t qdf_rl_print_count = WLAN_MAX_LOGS_PER_SEC; +uint32_t qdf_rl_print_time = 1; +uint32_t qdf_rl_print_supressed; + +/** + * qdf_detected_excessive_logging() - Excessive logging detected + * + * Track logging count using a quasi-tumbling window. + * If the max logging count for a given window is exceeded, + * return true else fails. + * + * Return: true/false + */ +bool qdf_detected_excessive_logging(void) +{ + qdf_time_t now = qdf_system_ticks(); + bool excessive_prints = false; + + /* + * If 'now' is more recent than the end of the window, reset. + * + * Note: This is not thread safe, and can result in more than one reset. + * For our purposes, this is fine. + */ + if (!qdf_atomic_read(&__log_window_count)) { + __log_window_end = now + (qdf_system_ticks_per_sec * qdf_rl_print_time); + } else if (qdf_system_time_after(now, __log_window_end)) { + __log_window_end = now + (qdf_system_ticks_per_sec * qdf_rl_print_time); + qdf_atomic_set(&__log_window_count, 0); + } + + if (qdf_atomic_inc_return(&__log_window_count) > qdf_rl_print_count) + excessive_prints = true; + + return excessive_prints; +} + +void qdf_rl_print_count_set(uint32_t rl_print_count) +{ + qdf_rl_print_count = rl_print_count; +} + +qdf_export_symbol(qdf_rl_print_count_set); + +void qdf_rl_print_time_set(uint32_t rl_print_time) +{ + qdf_rl_print_time = rl_print_time; +} + +qdf_export_symbol(qdf_rl_print_time_set); + +static inline void qdf_rl_print_supressed_log(void) +{ + if (qdf_rl_print_supressed) { + pr_err("QDF Ratelimiting: %d prints supressed", + qdf_rl_print_supressed); + qdf_rl_print_supressed = 0; + } +} + +static inline void qdf_rl_print_supressed_inc(void) +{ + qdf_rl_print_supressed++; +} +#else +#define qdf_rl_print_supressed_log() +#define qdf_rl_print_supressed_inc() +#endif /* WLAN_MAX_LOGS_PER_SEC */ + #ifdef QDF_TRACE_PRINT_ENABLE static inline void print_to_console(char *str_buffer) { + if (qdf_detected_excessive_logging()) { + qdf_rl_print_supressed_inc(); + return; + } + qdf_rl_print_supressed_log(); pr_err("%s\n", str_buffer); } #else diff --git a/utils/logging/src/wlan_logging_sock_svc.c b/utils/logging/src/wlan_logging_sock_svc.c index e003ee380f..1ce0c08658 100644 --- a/utils/logging/src/wlan_logging_sock_svc.c +++ b/utils/logging/src/wlan_logging_sock_svc.c @@ -308,41 +308,14 @@ static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts) } #ifdef WLAN_MAX_LOGS_PER_SEC -static qdf_time_t __log_window_end_ticks; -static qdf_atomic_t __log_window_count; - -/** - * assert_on_excessive_logging() - Check for and panic on excessive logging - * - * Track logging count using a quasi-tumbling window, 1 second long. If the max - * logging count for a given window is exceeded, panic. - * - * Return: None - */ -static void assert_on_excessive_logging(void) +static inline void wlan_panic_on_excessive_logging(void) { - qdf_time_t now = qdf_system_ticks(); - - /* - * If 'now' is more recent than the end of the window, reset. - * - * Note: This is not thread safe, and can result in more than one reset. - * For our purposes, this is fine. - */ - if (!qdf_atomic_read(&__log_window_count)) { - __log_window_end_ticks = now + qdf_system_ticks_per_sec; - } else if (qdf_system_time_after(now, __log_window_end_ticks)) { - __log_window_end_ticks = now + qdf_system_ticks_per_sec; - qdf_atomic_set(&__log_window_count, 0); - } - - /* this _is_ thread safe, and results in at most one panic */ - if (qdf_atomic_inc_return(&__log_window_count) == WLAN_MAX_LOGS_PER_SEC) + if (qdf_detected_excessive_logging()) QDF_DEBUG_PANIC("Exceeded %d logs per second", WLAN_MAX_LOGS_PER_SEC); } #else -static inline void assert_on_excessive_logging(void) { } +static inline void wlan_panic_on_excessive_logging(void) {} #endif /* WLAN_MAX_LOGS_PER_SEC */ static inline void @@ -351,19 +324,19 @@ log_to_console(QDF_TRACE_LEVEL level, const char *timestamp, const char *msg) switch (level) { case QDF_TRACE_LEVEL_FATAL: pr_alert("%s %s\n", timestamp, msg); - assert_on_excessive_logging(); + wlan_panic_on_excessive_logging(); break; case QDF_TRACE_LEVEL_ERROR: pr_err("%s %s\n", timestamp, msg); - assert_on_excessive_logging(); + wlan_panic_on_excessive_logging(); break; case QDF_TRACE_LEVEL_WARN: pr_warn("%s %s\n", timestamp, msg); - assert_on_excessive_logging(); + wlan_panic_on_excessive_logging(); break; case QDF_TRACE_LEVEL_INFO: pr_info("%s %s\n", timestamp, msg); - assert_on_excessive_logging(); + wlan_panic_on_excessive_logging(); break; case QDF_TRACE_LEVEL_INFO_HIGH: case QDF_TRACE_LEVEL_INFO_MED: