Linux内核中的panic

目录

一、内核配置

二、程序触发panic

三、命令行执行触发panic

四、panic源码

解析panic

五、系统收到收到panic处理方式

六、编写自定义内核panic处理程序例程

1、内核中的使用

2、自定义处理函数示例

七、实例代码


一、内核配置

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

  1. 代码尽其所能避免复杂性和可能的死锁
  2. KERN_EMERG 内核打印信息 “Kernel panic - not syncing”
  3. panic_print_sys_info();确定并显示更多系统信息–例如所有任务信息、内存、计时器、锁、ftrace信息和所有内核打印。具体取决于panic_print的bitmask
  4. 函数所做的最后一件事就是在单个启用的处理器核上无限循环;在循环中,它重置非屏蔽中断(NMI),然后定期调用一个名为架构依赖的panic_blink函数;在x86上,该事件会引起键盘LED会闪烁,驱动drivers/input/serio/i8042.c:i8042_panic_blink().

五、系统收到收到panic处理方式

  1. 当内核kexec/kdump使能,进入dump-capture kernel状态
  2. 定制panic处理函数,除了常规的紧急处理代码之外,还会调用处理函数
  3. 当内核参数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);
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值