文章目录
- sysrq模块初始化流程图
- sysrq模块代码详解
- sysrq产生kernel crash事件流程
- sysrq 整体框架图
- sysrq 框架中添加自定义实例
Linux 版本:Linux version 3.18.24
sysrq模块初始化流程图
sysrq模块源码路径:linux-3.18.24.x/drivers/tty/sysrq.c
编译开启:CONFIG_MAGIC_SYSRQ=y
sysrq模块代码详解
1、sysrq模块初始化
static int __init sysrq_init(void)
{
sysrq_init_procfs(); // 创建sysrq在proc下节点
if (sysrq_on()) // 每个linux版本不一样,红帽企业版Linux是需要控制的
sysrq_register_handler(); // 注册sysrq的处理函数
return 0;
}
module_init(sysrq_init);
2、创建sysrq在proc下节点:sysrq_init_procfs
static const struct file_operations proc_sysrq_trigger_operations = {
.write = write_sysrq_trigger, // 写回调函数
.llseek = noop_llseek,
};
static void sysrq_init_procfs(void)
{
if (!proc_create("sysrq-trigger", S_IWUSR, NULL, // 在proc下创建sysrq-trigger节点,并注册文件操作结构体
&proc_sysrq_trigger_operations))
pr_err("Failed to register proc interface\n");
}
3、本linux系统内,proc下sysrq事件的回调函数注册始终是打开的:sysrq_on()
static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; // #define CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 0x1
static bool sysrq_on(void)
{
return sysrq_enabled || sysrq_always_enabled; // sysrq始终都是打开的
}
static int __init sysrq_always_enabled_setup(char *str)
{
sysrq_always_enabled = true; // sysrq_always_enabled始终都是打开的
pr_info("sysrq always enabled.\n");
return 1;
}
__setup("sysrq_always_enabled", sysrq_always_enabled_setup); // 系统启动时自动执行
4、注册sysrq事件的回调函数:sysrq_register_handler
static inline void sysrq_register_handler(void)
{
unsigned short key;
int error;
int i;
// 首先检查是否实例化了_weak接口。
for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
key = platform_sysrq_reset_seq[i];
if (key == KEY_RESERVED || key > KEY_MAX)
break;
sysrq_reset_seq[sysrq_reset_seq_len++] = key;
}
// DT构型优先于任何已经通过弱接口定义。
sysrq_of_get_keyreset_config();
// 注册input回调
error = input_register_handler(&sysrq_handler);
if (error)
pr_err("Failed to register input handler, error %d", error);
else
sysrq_handler_registered = true;
}
sysrq产生kernel crash事件流程
在串口终端上,能直接将CommandKey写入/proc/sysrq-trigger文件流程
如:echo ‘c’ > sysrq-trigger 产生一个kernel crash
当执行命令之后,会调用proc写回调函数:write_sysrq_trigger
static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count) {
char c;
if (get_user(c, buf)) // 从用户端获取传入的字符串
return -EFAULT;
__handle_sysrq(c, false); // 调用处理函数
}
return count;
}
处理函数__handle_sysrq解析:
void __handle_sysrq(int key, bool check_mask)
{
struct sysrq_key_op *op_p;
int orig_log_level;
int i;
rcu_sysrq_start();
rcu_read_lock();
orig_log_level = console_loglevel; // 使用默认等级#define CONSOLE_LOGLEVEL_DEFAULT 7 /* anything MORE serious than KERN_DEBUG */
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; // 输出到终端
printk(KERN_INFO "SysRq : ");
op_p = __sysrq_get_key_op(key); // 找到sysrq_key_table表中对应结构体
-> i = sysrq_key_table_key2index(key); // 通过传入的key值(例中为'c')转为sysrq_key_table表中索引值
-> op_p = sysrq_key_table[i]; // 获取对应结构体(sysrq_key_table表在下个函数解析)(例中'c'对应为sysrq_crash_op)
if (op_p) {
if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
printk("%s\n", op_p->action_msg);
console_loglevel = orig_log_level;
op_p->handler(key); // 执行结构体中的处理函数
} else {
printk("This sysrq operation is disabled.\n");
}
} else {
......
}
rcu_read_unlock();
rcu_sysrq_end();
}
sysrq_key_table表包含36个sysrq_key_op结构体指针(对应传入key值为‘0’ — ‘9’,‘a’ — ‘z’)
struct sysrq_key_op {
void (*handler)(int); // 处理函数
char *help_msg; // 帮助信息
char *action_msg; // 相关动作信息
int enable_mask; // 使能掩码
};
static struct sysrq_key_op *sysrq_key_table[36] = {
&sysrq_loglevel_op, /* 0 */
&sysrq_loglevel_op, /* 1 */
&sysrq_loglevel_op, /* 2 */
&sysrq_loglevel_op, /* 3 */
&sysrq_loglevel_op, /* 4 */
&sysrq_loglevel_op, /* 5 */
&sysrq_loglevel_op, /* 6 */
&sysrq_loglevel_op, /* 7 */
&sysrq_loglevel_op, /* 8 */
&sysrq_loglevel_op, /* 9 */
/*
* a: Don't use for system provided sysrqs, it is handled specially on
* sparc and will never arrive.
*/
NULL, /* a */
&sysrq_reboot_op, /* b */
&sysrq_crash_op, /* c & ibm_emac driver debug */
&sysrq_showlocks_op, /* d */
&sysrq_term_op, /* e */
......
&sysrq_showstate_blocked_op, /* w */
NULL, /* x */
NULL, /* y */
&sysrq_ftrace_dump_op, /* z */
};
例子中,用户层传入‘c’ 对应的结构体是sysrq_crash_op
// 触发一个系统crash的处理函数
static void sysrq_handle_crash(int key)
{
char *killer = NULL;
panic_on_oops = 1; /* force panic */
wmb();
*killer = 1;
}
static struct sysrq_key_op sysrq_crash_op = {
.handler = sysrq_handle_crash,
.help_msg = "crash(c)",
.action_msg = "Trigger a crash",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
sysrq 整体框架图
sysrq 框架中添加自定义实例
diff --git a/linux-3.18.24.x/drivers/tty/sysrq.c b/linux-3.18.24.x/drivers/tty/sysrq.c
index 42bad18c6..a156551d3 100755
--- a/linux-3.18.24.x/drivers/tty/sysrq.c
+++ b/linux-3.18.24.x/drivers/tty/sysrq.c
@@ -408,6 +408,18 @@ static struct sysrq_key_op sysrq_unrt_op = {
.enable_mask = SYSRQ_ENABLE_RTNICE,
};
+static void sysrq_handle_dwb(int key)
+{
+ console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
+ printk("sysrq_handle_dwb test ok. \n");
+}
+static struct sysrq_key_op sysrq_dwb_op = {
+ .handler = sysrq_handle_dwb,
+ .help_msg = "dwb test",
+ .action_msg = "dwb",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+};
+
/* Key Operations table and lock */
static DEFINE_SPINLOCK(sysrq_key_table_lock);
@@ -451,7 +463,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
&sysrq_showmem_op, /* m */
&sysrq_unrt_op, /* n */
/* o: This will often be registered as 'Off' at init time */
- NULL, /* o */
+ &sysrq_dwb_op, /* o */
&sysrq_showregs_op, /* p */
&sysrq_show_timers_op, /* q */
&sysrq_unraw_op, /* r */