Rate-Limited printk: Preventing Kernel Log Flooding in Linux 6.x
📋 Table of Contents
- The Problem: Kernel Log Flooding
- What Is Rate Limiting in Kernel Logging?
- How Rate Limiting Works Internally
- Controlling Rate Limits via sysctl
- Using printk_ratelimited in Your Driver
- The pr_<foo>_ratelimited Macro Family
- When Should You Use Rate-Limited Logging?
- How the Rate Limiter Decides — Flow Diagram
- Interview Q&A
1. The Problem: Kernel Log Flooding
Every Linux kernel driver developer eventually faces a situation where a piece of code that runs very frequently — like an interrupt handler, a timer callback, or a hot path inside a driver — also needs to emit a log message when something goes wrong.
The challenge is: if that code path fires hundreds or thousands of times per second, a regular printk() call on each execution will fill the kernel ring buffer extremely fast. Important messages from other subsystems get pushed out, the system becomes sluggish because logging I/O competes with real work, and diagnosing the actual problem becomes harder, not easier.
printk() on every interrupt event would generate thousands of log lines per second — crippling the system and making the log useless.
The Linux kernel solves this with rate-limited logging. Rate limiting means: allow a certain number of log messages through within a defined time window, and silently suppress the rest. When suppression ends, the kernel emits a single summary line telling you how many messages were dropped — so you never lose visibility into the scale of the problem.
2. What Is Rate Limiting in Kernel Logging?
Rate limiting in kernel logging is a built-in mechanism that controls how many identical or repetitive log messages can appear in the kernel ring buffer within a given time interval. It is not about filtering messages by content — it is purely about frequency control.
The two parameters that govern this behavior are:
- Time interval — the window in seconds during which the burst count is measured
- Burst count — the maximum number of messages allowed to pass through during the time interval before rate limiting activates
Once the burst count is exhausted within the time window, subsequent messages are silently counted but not printed. When the window expires and messages start flowing again, the kernel first prints a line like:
[timestamp] my_driver: 4820 callbacks suppressed
This tells you the exact number of messages that were held back, which is extremely useful during debugging.
3. How Rate Limiting Works Internally
The rate-limiting logic in the Linux kernel lives in lib/ratelimit.c. The core function is ___ratelimit(), which maintains a struct ratelimit_state per call site. This structure keeps track of:
- When the current time window started
- How many messages have been printed in this window
- How many messages have been suppressed in this window
Each time a rate-limited printk is called, the kernel checks:
- Has the current time window expired? If yes, reset the counter and start fresh.
- Is the current count within the allowed burst? If yes, print the message and increment the counter.
- Is the burst exceeded? If yes, suppress the message, increment the suppressed counter, and continue.
When a new window starts after suppression, the kernel first emits the suppressed count, then allows the next burst.
DEFINE_RATELIMIT_STATE() and the underlying token bucket algorithm has been stable since Linux 3.x. The printk_ratelimited() macro uses a statically allocated ratelimit state local to each call site, so different call sites in your driver have independent rate limits.
4. Controlling Rate Limits via sysctl
The kernel exposes the global default rate-limit parameters through the sysctl interface under /proc/sys/kernel/. You can read and modify them at runtime without rebooting.
Reading the current values
# Read both parameters at once
cat /proc/sys/kernel/printk_ratelimit
cat /proc/sys/kernel/printk_ratelimit_burst
On a typical Linux 6.x system the defaults are:
printk_ratelimit= 5 (seconds — the time window)printk_ratelimit_burst= 10 (messages allowed per window)
Modifying them temporarily (until reboot)
# Allow 20 messages every 10 seconds
echo 10 > /proc/sys/kernel/printk_ratelimit
echo 20 > /proc/sys/kernel/printk_ratelimit_burst
Making changes permanent via sysctl.conf
# Add to /etc/sysctl.conf or /etc/sysctl.d/99-custom.conf
kernel.printk_ratelimit = 10
kernel.printk_ratelimit_burst = 20
# Apply immediately
sudo sysctl -p
printk_ratelimited(). However, drivers that define their own DEFINE_RATELIMIT_STATE() with explicit interval and burst values are not affected by the sysctl knobs — they use whatever values the driver hardcodes.
5. Using printk_ratelimited in Your Driver
Using rate-limited printk in a kernel module or device driver is straightforward. The API is a drop-in replacement for regular printk(). It takes the same arguments: a log level constant followed by a format string and optional arguments.
Basic syntax
printk_ratelimited(KERN_WARNING "mydriver: something went wrong: %d\n", error_code);
Complete minimal kernel module example
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Rate-limited printk demo — Linux 6.x");
static struct timer_list demo_timer;
static unsigned long fire_count = 0;
/* Timer callback — fires every 100ms */
static void timer_handler(struct timer_list *t)
{
fire_count++;
/*
* This runs 10 times per second.
* With rate limiting: only ~10 messages pass through
* every 5 seconds. The rest are suppressed.
*/
printk_ratelimited(KERN_WARNING
"mymodule: timer fired (count=%lu)\n", fire_count);
/* Re-arm the timer */
mod_timer(&demo_timer, jiffies + msecs_to_jiffies(100));
}
static int __init demo_init(void)
{
pr_info("mymodule: loaded\n");
timer_setup(&demo_timer, timer_handler, 0);
mod_timer(&demo_timer, jiffies + msecs_to_jiffies(100));
return 0;
}
static void __exit demo_exit(void)
{
del_timer_sync(&demo_timer);
pr_info("mymodule: removed (total fires=%lu)\n", fire_count);
}
module_init(demo_init);
module_exit(demo_exit);
When you load this module and watch the kernel log with dmesg -w, you will see roughly 10 lines per 5-second window, followed by a suppressed-count line, rather than a flood of 50 lines every 5 seconds.
printk_ratelimited() (with the d at the end). The older printk_ratelimit() (without the d) is deprecated and should not be used in new kernel code.
6. The pr_<foo>_ratelimited Macro Family
Just as the kernel provides the convenient pr_info(), pr_warn(), pr_err() shorthand macros for regular printk at specific log levels, it also provides rate-limited equivalents for every log level. These are cleaner, shorter, and the recommended way to do rate-limited logging in modern kernel code.
The complete list
pr_emerg_ratelimited(fmt, ...) /* KERN_EMERG — system unusable */
pr_alert_ratelimited(fmt, ...) /* KERN_ALERT — action must be taken immediately */
pr_crit_ratelimited(fmt, ...) /* KERN_CRIT — critical condition */
pr_err_ratelimited(fmt, ...) /* KERN_ERR — error condition */
pr_warn_ratelimited(fmt, ...) /* KERN_WARNING — warning condition */
pr_notice_ratelimited(fmt, ...) /* KERN_NOTICE — normal but significant */
pr_info_ratelimited(fmt, ...) /* KERN_INFO — informational */
Notice there is no pr_debug_ratelimited() — debug messages are typically already conditional on CONFIG_DYNAMIC_DEBUG or similar mechanisms and don’t need rate limiting in the same way.
Example usage in a real driver scenario
#include <linux/module.h>
#include <linux/kernel.h>
/*
* This simulates an interrupt handler in a network driver.
* Network interrupts can fire thousands of times per second
* under heavy load, so rate-limited logging is essential.
*/
static irqreturn_t mynic_interrupt(int irq, void *dev_id)
{
u32 status = read_hw_status(dev_id);
if (status & ERR_FIFO_OVERFLOW) {
/*
* FIFO overflow can happen in bursts.
* Rate-limit prevents log flooding during
* a network storm or sustained hardware error.
*/
pr_warn_ratelimited("mynic: FIFO overflow detected (status=0x%08x)\n",
status);
clear_fifo(dev_id);
}
if (status & ERR_LINK_DOWN) {
/* Link events are rare — regular printk is fine here */
pr_err("mynic: link down on port %d\n", get_port(dev_id));
}
return IRQ_HANDLED;
}
In the example above, a FIFO overflow can happen repeatedly in rapid succession. Using pr_warn_ratelimited() ensures the log stays readable without losing the information that overflows are occurring. A link-down event, being rare, does not need rate limiting.
7. When Should You Use Rate-Limited Logging?
Knowing when to reach for rate-limited printk versus regular printk is an important skill for kernel driver development. Here is a practical guide:
| Code Location | Call Frequency | Recommended API | Reason |
|---|---|---|---|
| Interrupt handler | Very high (kHz) | pr_warn_ratelimited() |
Prevents log flood |
| Timer callback | High (10s-100s Hz) | printk_ratelimited() |
Avoids buffer saturation |
| Hot path (network RX/TX) | Very high | pr_err_ratelimited() |
Error visibility without flooding |
| Module init / probe | Once | pr_info() / pr_err() |
No repetition risk |
| Error recovery path | Low (rare errors) | pr_err() |
Each occurrence matters |
| Hardware watchdog / retries | Bursty | pr_warn_ratelimited() |
Capture burst without overrun |
8. How the Rate Limiter Decides — Flow Diagram
Every call to printk_ratelimited() goes through a decision path inside ___ratelimit(). The diagram below shows that path using inline HTML:
expired?
Print suppressed count
limit?
message
+ count++
| Variable | Where Set | Default (Linux 6.x) | Effect |
|---|---|---|---|
interval |
sysctl or DEFINE_RATELIMIT_STATE | 5 seconds | Time window duration |
burst |
sysctl or DEFINE_RATELIMIT_STATE | 10 messages | Max messages per window |
printed |
Auto-tracked per call site | Resets each window | Count of messages printed this window |
missed |
Auto-tracked per call site | Resets after reporting | Count shown in “N callbacks suppressed” line |
📌 Key Takeaways
- Use
printk_ratelimited()whenever a code path can fire at high frequency - The default is 10 messages per 5-second window, adjustable via
/proc/sys/kernel/printk_ratelimit* - Suppressed messages are counted and reported — you never silently lose information about event frequency
- The
pr_<foo>_ratelimited()macros are the modern, preferred way to do rate-limited logging - Never use the deprecated
printk_ratelimit()without the d in new code - Different call sites maintain independent rate-limit state — one noisy path does not suppress others
🎯 Interview Q&A — Rate-Limited printk
/proc/sys/kernel/printk_ratelimit and /proc/sys/kernel/printk_ratelimit_burst respectively.printk_ratelimited() (with d) is the current API — it is a complete macro that wraps printk() with a per-call-site rate limit state. printk_ratelimit() (without d) is an older, deprecated function that returned a boolean to let the caller decide whether to print. The newer form is cleaner, safer, and is what you should use in all new kernel code.N callbacks suppressed before the next actual message, where N is the count of suppressed messages. This is handled internally by ___ratelimit() in lib/ratelimit.c.printk_ratelimited() calls that use the global default ratelimit state. Subsystems or drivers that initialize their own DEFINE_RATELIMIT_STATE() with explicit interval and burst values are not affected by the sysctl settings — they use their own independently tuned parameters.pr_emerg_ratelimited(), pr_alert_ratelimited(), pr_crit_ratelimited(), pr_err_ratelimited(), pr_warn_ratelimited(), pr_notice_ratelimited(), and pr_info_ratelimited(). There is no debug-level variant as debug messages are handled through separate mechanisms like CONFIG_DYNAMIC_DEBUG.lib/ratelimit.c, specifically in the ___ratelimit() function. The struct ratelimit_state that tracks per-call-site state is defined in include/linux/ratelimit.h.Explore the complete free kernel programming series on EmbeddedPathashala — from writing your first module to building production-quality device drivers.
View Full Course Index Device Driver Series