在Linux操作操作系统某一些异常情况下,大家常会在log文件中看到N messages supressed (N为数字).
下面来解析一下产生原因和含义.
假设有如下情况(仅仅是假设):某设备收到数据(Data)后,需要在内核空分配一缓冲区,如果因为某种原因分配缓冲区失败时,驱动程序(Procedures)(Procedures)用printk打印日志:“Allocte Mem failed".
像上述异常处理情况看似没什么问题,但是在异常情况下,如果每个数据(Data)包分配计算机内存都失败,那会出现用户的 console或者是日志文件中不断出现"Allocate Mem failed".这样会导致“拒绝服务”.
为此,Linux对日志的输出使用了RateLimit机制.
将上述过程改写为:
if (net_ratelimit())
{
printk(KERN_WARNING "Allocate Mem failed.\n");
}
int net_msg_cost =5*HZ;
int net_msg_burst =10;
int net_ratelimit(void)
{
return __printk_ratelimit(net_msg_cost, net_msg_burst);
}
int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
static DEFINE_SPINLOCK(ratelimit_lock);
static unsigned long toks =10 * 5 * HZ;
static unsigned long last_msg;
static int missed;unsigned long flags;
unsigned long now =jiffies;
spin_lock_irqsave(&ratelimit_lock, flags);
toks +=now - last_msg;last_msg =now;
if (toks > (ratelimit_burst * ratelimit_jiffies))
toks =ratelimit_burst * ratelimit_jiffies;
if (toks >=ratelimit_jiffies)
{
int lost =missed;
missed =0;
toks -=ratelimit_jiffies;
spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost)
printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
return 1;
}
missed++;
spin_unlock_irqrestore(&ratelimit_lock, flags);
return 0;
}
思考:
I ratelimit_jiffies的含义到底是什么?
从表面看,ratelimit_jiffies代表了阈值,仔细分析下来发现,当然他还有个作用就是控制多少时间之内的message不重复显示,而不能是在超过该段时间后,输出 N message suppressed消息,当中N为这段时间内欲输出但被suppressed的数目。
II ratelimit_burst的含义是什么?
从表面看 ratelimit_burst*ratelimit_jiffies 控制了 toks 的上限.在最开始的阶段,当toks达到最大上限时,此时必定超过阈值,但missed又为0,所以我们可以得出结论,不怎么会输出message suppressed消息,但由于返回值为1,所以我们可以得出结论会让相应的模块输出应有的message,因为
if (net_ratelimit())
{
printk(KERN_WARNING "Allocate Mem failed.\n");
}
此后toks递减ratelimit_jiffies,当再一次调用__printk_ratelimit后,
如果上次递减后的数值+"now - last_msg"还超过阈值则还可能会再输出相应的消息.所以我们可以得出结论ratelimit_burst*ratelimit_jiffies控制了在消息抑制前输出的消息多少.
III 注意: toks 和 missed 是静态局部变量
最后,我在加一点,在 LDD 3 的第四章中(P83),也讲述了对于 printk 打印速度的限制,不过使用的是内核自己提供的 API,
int printk_ratelimit(void) 函数,
使用方法和上面讲述的基本相同,
if( printk_ratelimit())
printk(KERN_NOTICE "xxxxxxxxxxxx\n");
/* minimum time in jiffies between messages */
int printk_ratelimit_jiffies = 5 * HZ;
/* number of messages we send before ratelimiting */
int printk_ratelimit_burst = 10;
int printk_ratelimit(void)
{
return __printk_ratelimit(printk_ratelimit_jiffies,
printk_ratelimit_burst);
}
主要工作还是由这个 __printk_ratelimit()函数来完成的,这个函数需要两个参数,是由静态定义的,
这两个参数实际上可以通过 proc 文件系统进行修改,
/proc/sys/kernel/printk_ratelimit 文件控制在重新打开消息之前应该等待的秒数。
/proc/sys/kernel/printk_burst 文件控制在进行速度限制之前可以接受的消息。
int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
static DEFINE_SPINLOCK(ratelimit_lock);
static unsigned long toks = 10 * 5 * HZ;
static unsigned long last_msg;
static int missed;
unsigned long flags;
unsigned long now = jiffies;
spin_lock_irqsave(&ratelimit_lock, flags);
toks += now - last_msg;
last_msg = now;
if (toks > (ratelimit_burst * ratelimit_jiffies))
toks = ratelimit_burst * ratelimit_jiffies;
if (toks >= ratelimit_jiffies) {
int lost = missed;
missed = 0;
toks -= ratelimit_jiffies;
spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost)
printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
return 1;
}
missed++;
spin_unlock_irqrestore(&ratelimit_lock, flags);
return 0;
}
在 LDD3 中的第四章中也描述了 printk 打印级别的控制,
主要是通过 /proc/sys/kernel/printk 文件对打印级别进行限制。
http://qgjie456.blog.163.com/blog/static/354513672008101331854328/
下面来解析一下产生原因和含义.
假设有如下情况(仅仅是假设):某设备收到数据(Data)后,需要在内核空分配一缓冲区,如果因为某种原因分配缓冲区失败时,驱动程序(Procedures)(Procedures)用printk打印日志:“Allocte Mem failed".
像上述异常处理情况看似没什么问题,但是在异常情况下,如果每个数据(Data)包分配计算机内存都失败,那会出现用户的 console或者是日志文件中不断出现"Allocate Mem failed".这样会导致“拒绝服务”.
为此,Linux对日志的输出使用了RateLimit机制.
将上述过程改写为:
if (net_ratelimit())
{
printk(KERN_WARNING "Allocate Mem failed.\n");
}
int net_msg_cost =5*HZ;
int net_msg_burst =10;
int net_ratelimit(void)
{
return __printk_ratelimit(net_msg_cost, net_msg_burst);
}
int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
static DEFINE_SPINLOCK(ratelimit_lock);
static unsigned long toks =10 * 5 * HZ;
static unsigned long last_msg;
static int missed;unsigned long flags;
unsigned long now =jiffies;
spin_lock_irqsave(&ratelimit_lock, flags);
toks +=now - last_msg;last_msg =now;
if (toks > (ratelimit_burst * ratelimit_jiffies))
toks =ratelimit_burst * ratelimit_jiffies;
if (toks >=ratelimit_jiffies)
{
int lost =missed;
missed =0;
toks -=ratelimit_jiffies;
spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost)
printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
return 1;
}
missed++;
spin_unlock_irqrestore(&ratelimit_lock, flags);
return 0;
}
思考:
I ratelimit_jiffies的含义到底是什么?
从表面看,ratelimit_jiffies代表了阈值,仔细分析下来发现,当然他还有个作用就是控制多少时间之内的message不重复显示,而不能是在超过该段时间后,输出 N message suppressed消息,当中N为这段时间内欲输出但被suppressed的数目。
II ratelimit_burst的含义是什么?
从表面看 ratelimit_burst*ratelimit_jiffies 控制了 toks 的上限.在最开始的阶段,当toks达到最大上限时,此时必定超过阈值,但missed又为0,所以我们可以得出结论,不怎么会输出message suppressed消息,但由于返回值为1,所以我们可以得出结论会让相应的模块输出应有的message,因为
if (net_ratelimit())
{
printk(KERN_WARNING "Allocate Mem failed.\n");
}
此后toks递减ratelimit_jiffies,当再一次调用__printk_ratelimit后,
如果上次递减后的数值+"now - last_msg"还超过阈值则还可能会再输出相应的消息.所以我们可以得出结论ratelimit_burst*ratelimit_jiffies控制了在消息抑制前输出的消息多少.
III 注意: toks 和 missed 是静态局部变量
最后,我在加一点,在 LDD 3 的第四章中(P83),也讲述了对于 printk 打印速度的限制,不过使用的是内核自己提供的 API,
int printk_ratelimit(void) 函数,
使用方法和上面讲述的基本相同,
if( printk_ratelimit())
printk(KERN_NOTICE "xxxxxxxxxxxx\n");
/* minimum time in jiffies between messages */
int printk_ratelimit_jiffies = 5 * HZ;
/* number of messages we send before ratelimiting */
int printk_ratelimit_burst = 10;
int printk_ratelimit(void)
{
return __printk_ratelimit(printk_ratelimit_jiffies,
printk_ratelimit_burst);
}
主要工作还是由这个 __printk_ratelimit()函数来完成的,这个函数需要两个参数,是由静态定义的,
这两个参数实际上可以通过 proc 文件系统进行修改,
/proc/sys/kernel/printk_ratelimit 文件控制在重新打开消息之前应该等待的秒数。
/proc/sys/kernel/printk_burst 文件控制在进行速度限制之前可以接受的消息。
int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
static DEFINE_SPINLOCK(ratelimit_lock);
static unsigned long toks = 10 * 5 * HZ;
static unsigned long last_msg;
static int missed;
unsigned long flags;
unsigned long now = jiffies;
spin_lock_irqsave(&ratelimit_lock, flags);
toks += now - last_msg;
last_msg = now;
if (toks > (ratelimit_burst * ratelimit_jiffies))
toks = ratelimit_burst * ratelimit_jiffies;
if (toks >= ratelimit_jiffies) {
int lost = missed;
missed = 0;
toks -= ratelimit_jiffies;
spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost)
printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
return 1;
}
missed++;
spin_unlock_irqrestore(&ratelimit_lock, flags);
return 0;
}
在 LDD3 中的第四章中也描述了 printk 打印级别的控制,
主要是通过 /proc/sys/kernel/printk 文件对打印级别进行限制。
http://qgjie456.blog.163.com/blog/static/354513672008101331854328/