【linux kernel】linux内核panic分析

linux内核panic分析


(注:本文源码均出自linux 内核版本:4.1.15

panic在内核中功能强大,作为内核紧急出错并及时停止系统的有效方式之一,该函数具有以下三个特点:

(1)halt the system——停止系统

(2)Display a message, then perform cleanups——显示一条信息,然后执行清理

(3)never returns——永不返回

panic的定义在(/kernel/panic.c)文件中

void panic(const char *fmt, ...)
{
	static DEFINE_SPINLOCK(panic_lock);
	static char buf[1024];
	va_list args;
	long i, i_next = 0;
	int state = 0;

	local_irq_disable();

	if (!spin_trylock(&panic_lock))
		panic_smp_self_stop();

	console_verbose();
	bust_spinlocks(1);
	va_start(args, fmt);
	vsnprintf(buf, sizeof(buf), fmt, args);
	va_end(args);
	pr_emerg("Kernel panic - not syncing: %s\n", buf);
#ifdef CONFIG_DEBUG_BUGVERBOSE
	if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)
		dump_stack();
#endif

	if (!crash_kexec_post_notifiers)
		crash_kexec(NULL);

	smp_send_stop();

	/*
	 * Run any panic handlers, including those that might need to
	 * add information to the kmsg dump output.
	 */
	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);

	kmsg_dump(KMSG_DUMP_PANIC);

	/*
	 * If you doubt kdump always works fine in any situation,
	 * "crash_kexec_post_notifiers" offers you a chance to run
	 * panic_notifiers and dumping kmsg before kdump.
	 * Note: since some panic_notifiers can make crashed kernel
	 * more unstable, it can increase risks of the kdump failure too.
	 */
	crash_kexec(NULL);

	bust_spinlocks(0);

	if (!panic_blink)
		panic_blink = no_blink;

	if (panic_timeout > 0) {
		pr_emerg("Rebooting in %d seconds..", panic_timeout);

		for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
			touch_nmi_watchdog();
			if (i >= i_next) {
				i += panic_blink(state ^= 1);
				i_next = i + 3600 / PANIC_BLINK_SPD;
			}
			mdelay(PANIC_TIMER_STEP);
		}
	}
	if (panic_timeout != 0) {
		emergency_restart();
	}

	pr_emerg("---[ end Kernel panic - not syncing: %s\n", buf);
	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);
	}
}

第9行代码使用local_irq_disable()禁用本地中断,避免出现死锁,因为无法防止中断处理程序(在获得panic锁后运行)再次被调用panic

第11~12行代码用于保证:只允许一个CPU执行该代码。对于SMP,可能会对panic进行多个并行调用,这里使用panic_smp_self_stop()函数(注:该函数与具体架构相关)保证当一个CPU执行panic时,其他CPU处于停止,或者等待状态。

第28行代码smp_send_stop()是通用的smp shutdown功能。在Arm架构下,如下定义(/arch/arm/kernel/smp.c):

void smp_send_stop(void)
{
	unsigned long timeout;
	struct cpumask mask;

	cpumask_copy(&mask, cpu_online_mask);
	cpumask_clear_cpu(smp_processor_id(), &mask);
	if (!cpumask_empty(&mask))
		smp_cross_call(&mask, IPI_CPU_STOP);

	/* Wait up to one second for other CPUs to stop */
	timeout = USEC_PER_SEC;
	while (num_online_cpus() > 1 && timeout--)
		udelay(1);

	if (num_online_cpus() > 1)
		pr_warn("SMP: failed to stop secondary CPUs\n");
}

第52~63行代码,判断超时时间panic_timeout是否大于0,并根据超时时间长短执行信息输出,并打印出相关时间信息。 接着在64~66行代码中,如果超时时间panic_timeout不等于0,则调用emergency_restart()函数执行紧急重启操作,emergency_restart()最终会调用架构接口APImachine_restart()实现具体架构下的系统重启操作。该重启操作需要等待系统中所有的东西都关闭了,然后内核会找机会重新启动系统。

panic()函数中,都是使用pr_emerg()来打印出紧急消息。实际上是调用了printk()来实现,如下定义:(/include/linux/printk.h)

#define pr_emerg(fmt, ...) \
	printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)

panic中还使用到了crash_kexec()函数。该函数的目的是:如果kdump在有些情况下不能正常工作,根据crash_kexec_post_notifiers布尔变量值可以打印出一些panic通知,并且可以在kdump之前转储kmsg消息。(注意:由于一些panic通知程序会使崩溃的内核更加不稳定,同时也会增加kdump失败的风险)


本文完!

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

iriczhao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值