Rasdaemon存档diskerror错误
1.main函数
int main(int argc, char *argv[])
{
struct arguments args;
int idx = -1;
const struct argp_option options[] = {
{"enable", 'e', 0, 0, "enable RAS events and exit", 0},
{"disable", 'd', 0, 0, "disable RAS events and exit", 0},
#ifdef HAVE_SQLITE3
{"record", 'r', 0, 0, "record events via sqlite3", 0},
#endif
{"foreground", 'f', 0, 0, "run foreground, not daemonize"},
{ 0, 0, 0, 0, 0, 0 }
};
const struct argp argp = {
.options = options,
.parser = parse_opt,
.doc = TOOL_DESCRIPTION,
.args_doc = ARGS_DOC,
};
memset (&args, 0, sizeof(args));
user_hz = sysconf(_SC_CLK_TCK);
argp_parse(&argp, argc, argv, 0, &idx, &args);
if (idx < 0) {
argp_help(&argp, stderr, ARGP_HELP_STD_HELP, TOOL_NAME);
return -1;
}
if (args.enable_ras) {
int enable;
enable = (args.enable_ras > 0) ? 1 : 0;
toggle_ras_mc_event(enable);
return 0;
}
openlog(TOOL_NAME, 0, LOG_DAEMON);
if (!args.foreground)
if (daemon(0,0))
exit(EXIT_FAILURE);
handle_ras_events(args.record_events);
return 0;
}
使用ras-mc-ctl之前,总是会报错,需要先执行一下, rasdaemon --record 其实就是表示,错误会被记录在sqlite数据库中,否则ras-mc-ctl脚本是无法从db中导出错误日志的。
在解析完参数之后,就会调用到handle_ras_events函数,其中的record_events是错误事件的ID
2.handle_ras_events
(1)创建ras结构
struct ras_events {
char debugfs[MAX_PATH + 1];
char tracing[MAX_PATH + 1];
struct pevent *pevent;
int page_size;
/* Booleans */
unsigned use_uptime: 1;
unsigned record_events: 1;
/* For timestamp */
time_t uptime_diff;
/* For ras-record */
void *db_priv;
/* For the mce handler */
struct mce_priv *mce_priv;
/* For ABRT socket*/
int socketfd;
struct event_filter *filters[NR_EVENTS];
};
申请一个这样的结构体ras_events
(2)获取tracing目录
第一步获取debufs的目录,这个是记录在/proc/mount文件中,查找debugds字段,这里可以看到是
debugfs /sys/kernel/debug debugfs rw,seclabel,relatime 0 0
最终拼接出来的tracing目录就是/sys/kernel/debug/tracing/instances/rasdaemon
(3)获取tracing timestamp
这里会打开trace_clock文件查看内核是否支持uptime的,如果支持,就从/proc/uptime中读取uptime值。这里uptime_diff = now-uptime.
(4) 申请一个pevent结构
(5)从evets/header_page中获取pagesize,其实会获取timestamp,commit, overwrite, data四个值的长度
(6)add_event_handler
rc = filter_ras_mc_event(ras, "block", "block_rq_complete", "error != 0");
if (!rc) {
rc = add_event_handler(ras, pevent, page_size, "block",
"block_rq_complete", ras_diskerror_event_handler,
NULL, DISKERROR_EVENT);
if (!rc)
num_events++;
else
log(ALL, LOG_ERR, "Can't get traces from %s:%s\n",
"block", "block_rq_complete");
}
disk是这样子的
3. add_event_handler
第一步设置filter,这里会调用filter_ras_mc_event,把events/block/block_rq_complete/filter文件设置为“error!=0”.
第二步调用add_event_handler。读取events/block/block_rq_complete/format文件中的内容,分别解析出name,ID,format, print fmt字段。
第三步调用__toggle_ras_mc_event函数
这里会把block:block_rq_complete或者!block:block_rq_complete写在/sys/kernel/debug/tracing/instances/rasdaemon/set_event文件中。
4.read_ras_event_all_cpus
这个函数中会逐个打开events/per_cpu/下的所有CPU目录中的trace_pipe_raw文件。
然后会针对这个CPU起一个线程,调用handle_ras_event_cpu函数去处理。
5.handle_ras_event_cpu
这个函数里面回去读取trace_pipe_raw文件中的内容,调用read_ras_event。读取之后调用parse_ras_data函数