博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
kmsg_dump
阅读量:4212 次
发布时间:2019-05-26

本文共 3886 字,大约阅读时间需要 12 分钟。

kmsg_dump提供一种机制在系统挂掉的时候将log转存到其他介质如ramoos或者mtd等.我们以mtd中的使用为例来分析kmsg_dump机制.
使用kmsg_dump之前要先使用kmsg_dump_register来注册一个dumper,用于实际的log写函数.
我们先来看看kmsg_dump_register的定义,只定义了一个dump_list,将系统中所有注册的dump都挂在同一个list下,这就说明系统可以注册多个dumper
kernel/printk/printk.c
2819 int kmsg_dump_register(struct kmsg_dumper *dumper)
2820 {
2821         unsigned long flags;
2822         int err = -EBUSY;
2823 
2824         /* The dump callback needs to be set */
2825         if (!dumper->dump)
2826                 return -EINVAL;
2827 
2828         spin_lock_irqsave(&dump_list_lock, flags);
2829         /* Don't allow registering multiple times */
2830         if (!dumper->registered) {
2831                 dumper->registered = 1;
2832                 list_add_tail_rcu(&dumper->list, &dump_list);
2833                 err = 0;
2834         }
2835         spin_unlock_irqrestore(&dump_list_lock, flags);
2836 
2837         return err;
2838 }
2839 EXPORT_SYMBOL_GPL(kmsg_dump_register);
下来我们看一个实际中定义的dumper
static void mtdoops_notify_add(struct mtd_info *mtd)
325 {
360         cxt->dump.max_reason = KMSG_DUMP_OOPS;
361         cxt->dump.dump = mtdoops_do_dump;
362         err = kmsg_dump_register(&cxt->dump);
}
361 很给dump.dump赋值。362行注册dump。我们看看mtdoops_do_dump的实现
303 static void mtdoops_do_dump(struct kmsg_dumper *dumper,
304                             enum kmsg_dump_reason reason)
305 {
306         struct mtdoops_context *cxt = container_of(dumper,
307                         struct mtdoops_context, dump);
308 
309         /* Only dump oopses if dump_oops is set */
310         if (reason == KMSG_DUMP_OOPS && !dump_oops)
311                 return;
312 
313         kmsg_dump_get_buffer(dumper, true, cxt->oops_buf + MTDOOPS_HEADER_SIZE,
314                              record_size - MTDOOPS_HEADER_SIZE, NULL);
315 
316         /* Panics must be written immediately */
317         if (reason != KMSG_DUMP_OOPS)
318                 mtdoops_write(cxt, 1);
319 
320         /* For other cases, schedule work to write it "nicely" */
321         schedule_work(&cxt->work_write);
322 }
可见在dump中通过kmsg_dump_get_buffer来获取错误信息,再调用mtdoops_write来写到mtd 设备中。
我们重点看看kmsg_dump_get_buffer 是从哪里得到错误信息的呢?
3010 bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
3011                           char *buf, size_t size, size_t *len)
3012 {
3013         unsigned long flags;
3014         u64 seq;
3015         u32 idx;
3016         u64 next_seq;
3017         u32 next_idx;
3018         enum log_flags prev;
3019         size_t l = 0;
3020         bool ret = false;
3021 
3022         if (!dumper->active)
3023                 goto out;
3024 
3025         raw_spin_lock_irqsave(&logbuf_lock, flags);
3026         if (dumper->cur_seq < log_first_seq) {
3027                 /* messages are gone, move to first available one */
3028                 dumper->cur_seq = log_first_seq;
3029                 dumper->cur_idx = log_first_idx;
3030         }
3031 
3032         /* last entry */
3033         if (dumper->cur_seq >= dumper->next_seq) {
3034                 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
3035                 goto out;
3036         }
3037 
3038         /* calculate length of entire buffer */
3039         seq = dumper->cur_seq;
3040         idx = dumper->cur_idx;
3041         prev = 0;
3042         while (seq < dumper->next_seq) {
3043                 struct printk_log *msg = log_from_idx(idx);
3044 
3045                 l += msg_print_text(msg, prev, true, NULL, 0);
3046                 idx = log_next(idx);
3047                 seq++;
3048                 prev = msg->flags;
3049         }
3050 
3051         /* move first record forward until length fits into the buffer */
3052         seq = dumper->cur_seq;
3053         idx = dumper->cur_idx;
3054         prev = 0;
3055         while (l > size && seq < dumper->next_seq) {
3056                 struct printk_log *msg = log_from_idx(idx);
3057 
3058                 l -= msg_print_text(msg, prev, true, NULL, 0);
3059                 idx = log_next(idx);
3060                 seq++;
3061                 prev = msg->flags;
3062         }
3063 
3064         /* last message in next interation */
3065         next_seq = seq;
3066         next_idx = idx;
3067 
3068         l = 0;
3069         while (seq < dumper->next_seq) {
3070                 struct printk_log *msg = log_from_idx(idx);
3071 
3072                 l += msg_print_text(msg, prev, syslog, buf + l, size - l);
3073                 idx = log_next(idx);
3074                 seq++;
3075                 prev = msg->flags;
3076         }
3077 
3078         dumper->next_seq = next_seq;
3079         dumper->next_idx = next_idx;
3080         ret = true;
3081         raw_spin_unlock_irqrestore(&logbuf_lock, flags);
3082 out:
3083         if (len)
3084                 *len = l;
3085         return ret;
3086 }
3087 EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
从这个函数中 log_from_idx可知,dump转存的错误信息是从prink的log_buf中获得的.

转载地址:http://pvcmi.baihongyu.com/

你可能感兴趣的文章
C++构造函数详解及显式调用构造函数
查看>>
Windows脚本 - %~dp0的含义
查看>>
lua垃圾回收机制
查看>>
Cocos2d-X之游戏存储Sqlite基础篇(四)
查看>>
findlibrary returned null产生的联想,Android ndk开发打包时我们应该如何注意平台的兼容(x86,arm,arm-v7a)
查看>>
AndroidDevTools简介
查看>>
Mac10.9.3仅安装Nginx
查看>>
Cocos2dx 3.6.1运行html5的测试例子
查看>>
MAC下安装多版本JDK和切换几种方式
查看>>
Mac OS X 下安装 Ant
查看>>
mac : Java开发环境的设置
查看>>
COCOS2D-X 3.0坐标系详解
查看>>
让Mac OS X的终端多姿多彩
查看>>
Mac添加命令别名
查看>>
mac下安装 android模拟器GenyMotion
查看>>
定制以及彩色化自己的 Mac OS X 终端
查看>>
How the Internet works
查看>>
Web工作方式
查看>>
Xcode 插件管理工具 Alcatraz
查看>>
Xcode调试技巧
查看>>