参考
当WARN_ONCE或者WARN_ON_ONCE被第一次触发时,会输出调用栈,后面就不会了。可以使用下面的命令重置,这样再次触发时,还可以输出一次调用栈:
echo 1 > /sys/kernel/debug/clear_warn_once
相关的实现在kernel\panic.c:
/* Support resetting WARN*_ONCE state */ static int clear_warn_once_set(void *data, u64 val) { generic_bug_clear_once(); memset(__start_once, 0, __end_once - __start_once); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(clear_warn_once_fops, NULL, clear_warn_once_set, "%lld\n");
其中generic_bug_clear_once在lib\bug.c中:
static void clear_once_table(struct bug_entry *start, struct bug_entry *end) { struct bug_entry *bug; for (bug = start; bug < end; bug++) bug->flags &= ~BUGFLAG_DONE; } void generic_bug_clear_once(void) { #ifdef CONFIG_MODULES struct module *mod; rcu_read_lock_sched(); list_for_each_entry_rcu(mod, &module_bug_list, bug_list) clear_once_table(mod->bug_table, mod->bug_table + mod->num_bugs); rcu_read_unlock_sched(); #endif clear_once_table(__start___bug_table, __stop___bug_table); }
在clear_warn_once_set中做了两件事:
- 调用generic_bug_clear_once把模块以及内核自己的所有的bug_entry->flags成员的BUGFLAG_DONE位清除
- 将内核的
*(.data.once)
段的内容清0
也就是说,WARN_ON_ONCE或者WARN_ONCE会利用上面两种数据段的内容来判断是否需要输出上下文信息,这个在后面的文章中再分析。