kmsg_dump

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中获得的.
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值