Linux内核中的panic
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核中的panic相关的知识,希望对你有一定的参考价值。
目录
一、内核配置
CONFIG_MAGIC_SYSRQ=y
二、程序触发panic
在内核中调用函数panic
panic("whoa, a kernel panic!");
三、命令行执行触发panic
命令行下执行
#设置内核panic
echo 1 > /proc/sys/kernel/panic_on_oops
#使能内核magic sysrq
echo 1 > /proc/sys/kernel/sysrq
#magic sysrq feature
echo c > /proc/sysrq-trigger
查看内核中sysrq,上述的c代表 crash
benshushu:~# echo ? > /proc/sysrq-trigger ;dmesg | tail -n1
[ 154.967245] sysrq: SysRq : HELP : loglevel(0-9) reboot(b) crash(c)
terminate-all-tasks(e) memory-full-oom-kill(f) kill-all-tasks(i) thaw-filesystems(j)
sak(k) show-backtrace-all-active-cpus(l) show-memory-usage(m) nice-all-RT-tasks(n)
poweroff(o) show-registers(p) show-all-timers(q) unraw(r) sync(s)
show-task-states(t) unmount(u) show-blocked-tasks(w) dump-ftrace-buffer(z)
四、panic源码
大部分省略
void panic(const char *fmt, ...)
local_irq_disable();
preempt_disable_notrace();
pr_emerg("Kernel panic - not syncing: %s\\n", buf);
kgdb_panic(buf);
kmsg_dump(KMSG_DUMP_PANIC);
if (_crash_kexec_post_notifiers)
__crash_kexec(NULL);
pr_emerg("---[ end Kernel panic - not syncing: %s ]---\\n", buf);
/* Do not scroll important messages printed above */
suppress_printk = 1;
local_irq_enable();
for (i = 0; ; i += PANIC_TIMER_STEP)
touch_softlockup_watchdog();
if (i >= i_next)
i += panic_blink(state ^= 1);
i_next = i + 3600 / PANIC_BLINK_SPD;
mdelay(PANIC_TIMER_STEP);
解析panic
- 代码尽其所能避免复杂性和可能的死锁
- KERN_EMERG 内核打印信息 “Kernel panic - not syncing”
- panic_print_sys_info();确定并显示更多系统信息–例如所有任务信息、内存、计时器、锁、ftrace信息和所有内核打印。具体取决于panic_print的bitmask
- 函数所做的最后一件事就是在单个启用的处理器核上无限循环;在循环中,它重置非屏蔽中断(NMI),然后定期调用一个名为架构依赖的panic_blink函数;在x86上,该事件会引起键盘LED会闪烁,驱动drivers/input/serio/i8042.c:i8042_panic_blink().
五、系统收到收到panic处理方式
- 当内核kexec/kdump使能,进入dump-capture kernel状态
- 定制panic处理函数,除了常规的紧急处理代码之外,还会调用处理函数
- 当内核参数panic=n,表示panic持续时间,在n秒后重启
六、编写自定义内核panic处理程序例程
内核支持四种不同类型,基于回调函数执行的环境
- 原子的Atomic:函数运行在原子上下文,不能阻塞
- 阻塞Blocking:函数运行在进程上下文,可以阻塞
- 睡眠Sleepable RCU:函数运行在进程上下文,可以阻塞,免锁机制
- 原始Raw:在任何上下文中运行,可以或可以不阻塞
1、内核中的使用
- drivers/net/netconsole.c:netconsole_netdev_event()
- register_reboot_notifier()
2、自定义处理函数示例
原子的 注册函数,实际上对spin_lock_irqsave/spin_unlock_irqsave封装
// include/linux/notifier.h
struct notifier_block
notifier_fn_t notifier_call;
struct notifier_block __rcu *next;
int priority;
;
// kernel/panic.c
ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
EXPORT_SYMBOL(panic_notifier_list);
int atomic_notifier_chain_register(struct atomic_notifier_head*,struct notifier_block*);
int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *n);
1、从文件名可以知道,atomic原子操作,不能阻塞
2、注册 atomic_notifier_chain_register
3、注销 atomic_notifier_chain_unregister
七、实例代码
#define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/delay.h>
MODULE_LICENSE("Dual MIT/GPL");
static void dev_ring_alarm(void)
pr_emerg("!!! ALARM !!!\\n");
//回调函数的实现
static int mypanic_handler(struct notifier_block *nb, unsigned long val, void *data)
//打印参数
pr_emerg("\\n************ Panic : SOUNDING ALARM ************\\n\\
val = %lu\\n\\
data(str) = \\"%s\\"\\n", val, (char *)data);
//执行的函数
dev_ring_alarm();
return NOTIFY_OK;
//结构体
static struct notifier_block mypanic_nb =
.notifier_call = mypanic_handler,//回调函数
// .priority = INT_MAX
;
static int __init panic_notifier_init(void)
//注册函数
atomic_notifier_chain_register(&panic_notifier_list, &mypanic_nb);
pr_info("Registered panic notifier\\n");
//延时500ms 并触发panic
mdelay(500);
panic("Linux Kernel Debugging!");
return 0; /* success */
static void __exit panic_notifier_exit(void)
atomic_notifier_chain_unregister(&panic_notifier_list, &mypanic_nb);
pr_info("Unregistered panic notifier\\n");
module_init(panic_notifier_init);
module_exit(panic_notifier_exit);
参考
https://course.0voice.com/v1/course/intro?courseId=2&agentId=0
以上是关于Linux内核中的panic的主要内容,如果未能解决你的问题,请参考以下文章
linux升级后重启出现kernel panic:attempted to kill init???
Linux内核升级导致无法启动,Kernel panic - not syncing Unable to mount root fs on unknown block(0,0)
linux系统进不去出现错误 Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100?