Kernelcrash dump
1. 在系统运行过程中,如果系统发生了crash, 那么开发人员需要通过crash信息来进行debug. 并进一步定位问题。而crash信息存在于内核ring buffer中,系统重启后就丢失了,所以需要一种方法,可以在系统发生crash时,将crash info保存于非易失存储器中,那么下面就来介绍一种方法实现这种功能。
2. 预备:
a) 当kernel crash发生时,crash dump info会被flush 到kernel ring buffer中,这个是kernel主动的行为。
b) 当kernel crash发生时, 可以主动调用do_sysinfo(),将系统的一些内存与进程信息flush至kernel ring buffer,(即利用printk(),将获取的信息打印出来)。
c) 当kernel crash 发生时,可以主动的将进程的调用栈信息flush到kernel ring buffer, 这样很有利于调试和定位问题。
Notice: b,c 属于一个主动的行为,也可以不做。
3.kernel ring buffer?
Kernel为系统打印kmalloc了一块内存,一般大小为128K, 即将所有的printk的打印信息输出这个buffer, 在console,可能通过dmesg来查看这个ring buffer的所有内容,可以用dmesg –c将这个ring buffer全部清空。
执行dmesg命令,你可以看到,系统从启动到现在完整的log信息。一般来说128k,足够保存所有的log信息,如果你在内存中打印很多信息,那么也有可能比较的信息会被覆盖掉。
4.下面写了一个框架来保存ring buffer信息。(存储设备:nor flash, 其他类弄的设备都很类似)
static int apanic(struct notifier_block *this, unsigned long event,
void *ptr)
{
...
...
/*
* 打印系统内存相关信息
*/
do_sysinfo(&si);
printk(si);
...
/*其他相的打印的信息......*/
...
/*
* 打印线程调用栈信息
*/
show_state_filter(0);
/*
* 最后一步,也是最重要的一步,保存所有信息到flash
*/
/* Return log buffer address */
start = log_buf_addr_get();
/* Return log buffer size */
len = log_buf_len_get();
/*这个是最简单的一种方法,直接把ring buffer拷贝到flash
* 如果想要实现更好的,那么可以调用syslog_print_all(),即
* 自己kmalloc一个buffer,所翻译之后的内容写入到flash.具体
* 自行分析printk运行机制。
*/
mtd->_write(mtd, off, len, &wlen, start);
}
static void mtd_panic_notify_remove(struct mtd_info *mtd)
{
/*这里并没有什么特别的操作,如果分配的特别的资源,那么需要进行释放*/
}
static void mtd_panic_notify_add(struct mtd_info *mtd)
{
if (strcmp(mtd->name, "crash"))
return;
获取crash 分区的mtd信息。
/*
* 这里可以做一些实始化的操作,比如erase crash 分区。识别并
* 标志这个分区。等等,所有设计及功能,都可以来设计。
*/
}
/*panic notifier callback*/
static struct notifier_block panic_blk = {
.notifier_call = apanic,
};
/*mtd notifier callback*/
static struct mtd_notifier mtd_panic_notifier = {
.add = mtd_panic_notify_add,
.remove = mtd_panic_notify_remove,
};
int __init apanic_init(void)
{
/*
* 注册mtd 通知链回调,目的为了获取保存kernel crash info的分区信息。
* 比如分区名为"crash"
* (kernel 创建一个分区,就会调用mtd_notifier.add回调。
* 删除一个分区,就会调用mtd_notifier.remove回调)
*/
register_mtd_user(&mtd_panic_notifier);
/*
* 注册panic 回调。目的是为了在发生panic时,可以做一些想做的操作。
* 比如保存信息到flash,做一些恢复操作。。。
* panic_blk是一个回调函数,所有操作可以在这个函数里做。
*/
atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
return 0;
}
Notice:
echo c > /proc/sysrq-trigger //这个命令可以让kernel crash