本文共 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/