在Linux系统某些异常情况下,大家常会在log文件中看到N messages supressed (N为数字)。下面来解析一下产生原因和含义。
假设有如下情况(仅仅是假设):。
某设备收到数据后,需要在内核空分配一缓冲区,如果因为某种原因分配缓冲区失败时,驱动程序用printk打印日志:“Allocte Mem failed".。
象上述异常处理情况看似没什么问题,但是在异常情况下,如果每个数据包分配内存都失败,那会出现用户的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;
/*last_msg:是上个message 产生的时间*/
static unsigned long last_msg;
static int missed;
unsigned long flags;
unsigned long now = jiffies;
spin_lock_irqsave(&ratelimit_lock, flags);
/*当toks不超过阈值时,返回0,否则,输出N messages supressed 消息并返回1,注意toks是个静态变量*/
/*toks随时间增加*/
toks += now - last_msg;
/*更新last_msg*/
last_msg = now;
/*toks设置上限*/
if (toks > (ratelimit_burst * ratelimit_jiffies))
toks = ratelimit_burst * ratelimit_jiffies;
/*toks超过阈值,阈值为ratelimit_jiffies*/
if (toks >= ratelimit_jiffies) {
int lost = missed;
/*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;
}
思考:
1.ratelimit_jiffies的含义到底是什么?从表面看,ratelimit_jiffies代表了阈值,仔细分析下来发现,其实它还有个作用就是控制多少时间之内的message不重复显示,而在超过该段时间后,输出 N message suppressed消息,其中N为这段时间内欲输出但被suppressed的数目
2.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控制了在消息抑制前输出的消息多少。
3.注意:toks、missed是静态局部变量
以上几点为我自己的一些理解,如果有不妥或错误的地方欢迎指正

