Sysrq 诊断系统故障

1. 典型应用场景如:
    1)系统进入了挂死状态(如调度出现异常、或系统负荷过重),但仍能响应中断,此时可以通过Sysrq魔术键(c)手工触发panic,结合kdump,就能收集到vmcore信息,用于问题的后续分析定位,非常有用。
    2)当系统中某进程出现挂死(可能是D状态,或是死锁),此时需要确认该进程具体挂在什么地方,可以使用Sysrq魔术键(t)打印出系统中所有进程的堆栈信息。
    3)当系统出现反应迟钝、交互困难时,难以通过shell或终端交互获取到有用信息,此时可以使用Sysrq魔术键(m,p)打印出系统中内存使用的详细信息和CPU运行上下文信息等。

Linux进程状态:R (TASK_RUNNING),可执行状态。
只有在该状态的进程才可能在CPU上运行, 而同一时刻可能有多个进程处于可执行状, 这些进程的task_struct结构(进程控制块)被放入对 应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中).

Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状态。
处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中.

Linux进程状态:D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。
与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。

Linux进程状态:T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态。
向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于 TASK_UNINTERRUPTIBLE状态而不响应信号)。

Linux进程状态:Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。
进程在退出的过程中,处于TASK_DEAD状态。

Linux进程状态:X (TASK_DEAD - EXIT_DEAD),退出状态,进程即将被销毁。
而进程在退出过程中也可能不会保留它的task_struct。

2、使用
1)编译
    在Kernel hacking中,选中Magic SysRq key (CONFIG_MAGIC_SYSRQ) 。

启用 SysRq

内核的支持

要启用 SysRq 功能,首先必须确保内核已经加入 CONFIG_MAGIC_SYSRQ 支持。在现今 Linux 发行版中,无一例外的均已加入该功能的支持,验证如下:

# grep "CONFIG_MAGIC_SYSRQ" /boot/config-`uname -r`
 CONFIG_MAGIC_SYSRQ=y

2)使用方法    通常有两种方式:a、通过/proc接口;  b、通过键盘输入组合键。  
    通过/proc接口的使用方法为:echo ‘command’ > /proc/sysrq-trigger
    其中command是一个字符,可以是’1 – 9’或者’a-z’或者’A-Z’,字母不区分大小写。
    常用的命令有:
    0-9 设置printk的打印级别。和/proc/sys/kernel/printk的第一个参数意思相同
    b 立即重启单板,不进行磁盘同步等操作;调用内核的函数为emergency_restart
    c 进行kexec reboot,需要KEXC支持。调用内核的函数为crash_kexec
    d 显示此有的锁,需要配置CONFIG_LOCKDEP,调用函数为debug_show_all_locks。
    e 向所有进程(init除外)发送SIGTERM信号,发送信号调用force_sig函数
    f 进入out-of-memory流程,杀死一个进程,调用out_of_memory函数
    i 向所有进程(init除外)发送SIGKILL信号
    m 显示当前内存信息,调用内核show_mem函数
    P 显示当前寄存器的值
    q 显示当前的timer,调用timer_list_show
    s 同步当前所有的文件系统,调用emergency_sync函数
    t 显示当前系统上所有的进程信息,调用函数为show_state
    u 重新mount所有文件系统,调用函数为emergency_remount
    w 显示系统中所有处于uninterruptable状态的进程,调用函数为show_state
    通过键盘组合键输入的规则是:
         串口:按住break键,然后5秒内输入command字符
         键盘:alt + sysrq +command键
    详细使用规则可以参考linux内核文档:Documentation/sysrq.txt。

  

3、基本原理
    Sysrq实现的基本原理为:在键盘或串口驱动中(如果是/proc接口方式,则直接定义/proc的相关写入接口即可),对按键进行判断过滤,然后根据不同的按键进行相应的处理。普通键盘和串口的流程不尽相同,主要差别在键盘和串口驱动的具体实现上,总体流程一致。
    对于普通键盘来说 ,其底层的处理(从硬件中断到键盘驱动)过程依赖于内核中的输入(input)子系统。键盘处理的大致流程如下:
    1)键盘中断调用中断服务程序
    2)键盘中断服务程序调用输入子系统
    3)输入子系统调用键盘设备对应的键盘事件处理器
    4)键盘事件处理器完成键码的转换分类工作,根据按键类型的不同,执行不同的操作。对于输入类按键,先将按键值存放到临时缓冲区,激活临时缓冲区的工作队列,然后结束。对于控制类按键,激活对应此次控制操作的工作队列,然后结束。
    5)系统在适当的时机调度工作队列执行,完成剩下的操作
    而Sysrq魔术键的处理比较特殊,在内核主分支的代码中,在上述步骤4中的键盘事件处理器中进行相应的处理,不依赖于工作队列,相当于直接在硬件中断中处理。而在3.10内核版本的分支代码中,处理流程不太一样,其合入了相应的补丁,使sysrq的处理剥离出来,放在input子系统进行处理,而脱离了键盘事件的处理流程,其还是在中断上下文中处理的,不依赖于工作队列等。主要是通过注册input_handler实现,具体见后面的代码分析。
    另一方面,对于串口设备来说,其sysrq的处理流程根据各串口驱动的实现而稍有不同,但基本都是直接在硬件中断中直接处理的。
    所以,总的来说,sysrq魔术键基本都在中断上下文中处理,优先级很高,能在关键时刻发挥重要作用。

4、代码分析
    Sysrq功能使用结构体sysrq_key_op定义了一个键盘键码所对应的行为,
struct sysrq_key_op {
    void (*handler)(int);
    char *help_msg;
    char *action_msg;
    int enable_mask;
};
    其中:
    handler表示相应键码所对应的处理函数;
    action_msg是执行处理函数前打印的信息;
    help_msg指相应键码的帮助信息;
    enable_mask指该功能是否打开,仅限于键盘输入方式。

   另外,sysrq还定义了一个静态全局数组sysrq_key_table,共有36个元素,其中0~9用于命令字0~9,10到36用于命令字a~z。当从/proc/得到输入的命令字后,可以根据这个规则计算出他在sysrq_key_table中的index,然后判断对应handler是否为空,如果不为空的话,则调用handler函数处理。
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_moom_op,            /* f */
    /* g: May be registered for the kernel debugger */
    NULL,                /* g */
    NULL,                /* h - reserved for help */
    &sysrq_kill_op,            /* i */
#ifdef CONFIG_BLOCK
    &sysrq_thaw_op,            /* j */
#else
    NULL,                /* j */
#endif
    &sysrq_SAK_op,            /* k */
#ifdef CONFIG_SMP
    &sysrq_showallcpus_op,        /* l */
#else
    NULL,                /* l */
#endif
    &sysrq_showmem_op,        /* m */
    &sysrq_unrt_op,            /* n */
    /* o: This will often be registered as ‘Off‘ at init time */
    NULL,                /* o */
    &sysrq_showregs_op,        /* p */
    &sysrq_show_timers_op,        /* q */
    &sysrq_unraw_op,        /* r */
    &sysrq_sync_op,            /* s */
    &sysrq_showstate_op,        /* t */
    &sysrq_mountro_op,        /* u */
    /* v: May be registered for frame buffer console restore */
    NULL,                /* v */
    &sysrq_showstate_blocked_op,    /* w */
    /* x: May be registered on ppc/powerpc for xmon */
    /* x: May be registered on sparc64 for global PMU dump */
    NULL,                /* x */
    /* y: May be registered on sparc64 for global register dump */
    NULL,                /* y */
    &sysrq_ftrace_dump_op,        /* z */
};
如之前所说,3.10版本内核代码中使用了input_handler来实现Sysrq魔术键的单独处理。
相应的input_handler定义:
static struct input_handler sysrq_handler = {
    .filter        = sysrq_filter,/*相应的filter处理函数,在input子系统中调用,其中调用了Sysrq的处理函数*/
    .connect    = sysrq_connect,
    .disconnect    = sysrq_disconnect,
    .name        = “sysrq”,
    .id_table    = sysrq_ids,
};

注册input_handler,函数调用流程:sysrq_init()–>sysrq_register_handler()–>input_register_handler()
static int __init sysrq_init(void)
{
 sysrq_init_procfs();
 if (sysrq_on())
  sysrq_register_handler();
 return 0;
}
static inline void sysrq_register_handler(void)
{
 unsigned short key;
 int error;
 int i;
 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;
 }
 error = input_register_handler(&sysrq_handler);
 if (error)
  pr_err(“Failed to register input handler, error %d”, error);
 else
  sysrq_handler_registered = true;
}
Sysrq魔术键处理代码流程:
atkbd_interrupt()  //键盘中断ISR
    input_event() //输入子系统相关处理
        input_handle_event()
            input_pass_values()
                input_to_handler()
                    handler->filter() //sysrq预先注册好的handler(sysrq_handler)的filter接口(sysrq_filter)
                        sysrq_filter()
                            sysrq_handle_keypress()
                                __handle_sysrq()  //sysrq魔术键具体处理
最终在__handle_sysrq()函数中完成Sysrq魔术键的具体处理。

键盘其它按键的处理
键盘其它按键的处理也是通过注册相应的input_handler(kbd_handler)来实现的,相应的event接口kbd_event()也在input子系统中调用:
/*键盘按键相应的input_handler*/
static struct input_handler kbd_handler = {
    .event        = kbd_event,
    .match        = kbd_match,
    .connect    = kbd_connect,
    .disconnect    = kbd_disconnect,
    .start        = kbd_start,
    .name        = “kbd”,
    .id_table    = kbd_ids,
};
kbd_handler注册:kbd_init()–>input_register_handler()int __init kbd_init(void)
{
    int i;
    int error;
    for (i = 0; i < MAX_NR_CONSOLES; i++) {
        kbd_table[i].ledflagstate = kbd_defleds();
        kbd_table[i].default_ledflagstate = kbd_defleds();
        kbd_table[i].ledmode = LED_SHOW_FLAGS;
        kbd_table[i].lockstate = KBD_DEFLOCK;
        kbd_table[i].slockstate = 0;
        kbd_table[i].modeflags = KBD_DEFMODE;
        kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
    }
    error = input_register_handler(&kbd_handler);
    if (error)
        return error;
    tasklet_enable(&keyboard_tasklet);
    tasklet_schedule(&keyboard_tasklet);
    return 0;
}
键盘其它按键的处理代码流程:
atkbd_interrupt()  //键盘中断ISR
    input_event() //输入子系统相关处理
        input_handle_event()
            input_pass_values()
                input_to_handler()
                    handler->events() //键盘初始化是预先注册好的handler(kbd_handler)的event接口(kbd_event)
                        kbd_event()
                            kbd_keycode()
                                put_queue()
                                    tty_insert_flip_char()  //将键盘键值对应的编码数据写入缓冲区
                                    tty_schedule_flip()  //激活工作队列处理,处理函数为flush_to_ldisc
最终在kbd_keycode()函数进行相应的键码处理,主要完成键码的转换分类工作,根据按键类型的不同,执行不同的操作。对于输入类按键,先将按键值存放到临时缓冲区,激活临时缓冲区的工作队列,然后结束。对于控制类按键,激活对应此次控制操作 的工作队列,然后结束。

通过/proc接口触发Sysrq魔术键的主要函数流程(write_sysrq_trigger()为/proc/sysrq-trigger接口的write接口):
write_sysrq_trigger()
    __handle_sysrq()

串口驱动(以8250串口为例)中对Sysrq魔术键的支持:
按照sysrq的设计,通过标准串口链接,按下break键后5秒内,再按住command字符,会触发command对应的sysrq流程。
相关的处理流程如下(从串口驱动的接收函数serial8250_rx_chars()开始,此函数在中断上下文中执行):
serial8250_rx_chars()
     /*
      * 判断是否按下了break键,用于判断Sysrq。当按住break键时,在uart_handle_break中判断port->sysrq是否为0,如果为0,
      * 则将port->sysrq置为5秒后的jiffies数。
      */
    uart_handle_break()
        /*
         * 对于每一个接收的字符,都会调用uart_handle_sysrq_char。如果当前jiffies数值比port->sysrq小,
         * 则说明当前字符是在按住了break后5秒内输入的,因此调用handle_sysrq处理该命令。
         */
        uart_handle_sysrq_char()

  

时间: 2024-10-13 05:17:41

Sysrq 诊断系统故障的相关文章

Linux运维常用命令

Linux运维常用的150个命令 命令 功能说明 线上查询及帮助命令(2个) man 查看命令帮助,命令的词典,更复杂的还有info,但不常用. help 查看Linux内置命令的帮助,比如cd命令. 文件和目录操作命令(18个) ls 全拼list,功能是列出目录的内容及其内容属性信息. cd 全拼change directory,功能是从当前工作目录切换到指定的工作目录. cp 全拼copy,其功能为复制文件或目录. find 查找的意思,用于查找目录及目录下的文件. mkdir 全拼mak

Google GFS文件系统深入分析

Google GFS文件系统深入分析 现在云计算渐成潮流,对大规模数据应用.可伸缩.高容错的分布式文件系统的需求日渐增长.Google根据自身的经验打造的这套针对大量廉价客户机的Google GFS文件系统已经广泛的在Google内部进行部署,对于有类似需求的企业而言有相当的参考价值. AD:51CTO移动APP安全沙龙!马上要爆满,手慢没座位! 51CTO编辑注:本文是一篇论文,英文原文标题为The Google File System,在Google Labs上公布,由blademaster

linux重要命令行总结

线上查询及帮助命令(2个) man              查看命令帮助,命令的词典,更复杂的还有info,但不常用 help              查看linux内置命令的帮助,比如cd命令 文件和目录操作命令(18个) ls                  全拼list,功能是列出目录的内容及其内容属性信息 cd                 全拼change directory,功能是从当前工作目录切换到指定的工作目录 cp                 全拼是copy,其功能

Linux企业运维人员最常用150个命令汇总

命令 功能说明 线上查询及帮助命令(2个) man 查看命令帮助,命令的词典,更复杂的还有info,但不常用. help 查看Linux内置命令的帮助,比如cd命令. 文件和目录操作命令(18个) ls 全拼list,功能是列出目录的内容及其内容属性信息. cd 全拼change directory,功能是从当前工作目录切换到指定的工作目录. cp 全拼copy,其功能为复制文件或目录. find 查找的意思,用于查找目录及目录下的文件. mkdir 全拼make directories,其功能

常用命令回顾

man 查看命令帮助,命令的词典,更复杂的还有info,但不常用. help 查看Linux内置命令的帮助,比如cd命令. 文件和目录操作命令(18个) ls 全拼list,功能是列出目录的内容及其内容属性信息. cd 全拼change directory,功能是从当前工作目录切换到指定的工作目录. cp 全拼copy,其功能为复制文件或目录. find 查找的意思,用于查找目录及目录下的文件. mkdir 全拼make directories,其功能是创建目录. mv 全拼move,其功能是移

Windows下DLL查找顺序

Windows下DLL查找顺序 作者:Tocy    时间:2014-10-18 一.写作初衷 在Windows下单个DLL可能存在多个不同的版本,若不特别指定DLL的绝对路径或使用其他手段指定,在应用程序加载DLL时可能会查找到错误的版本,进而引出各种莫名其妙的问题.本文主要考虑以下两个方面: a. 参考MSDN,给出Windows下DLL查找顺序 b. 简单使用ProcessMonitor来验证DLL查找顺序 二.DLL查找顺序 (本部分多数内容是参考MSDN上的Dynamic-Link L

The Google File System

摘要 我们设计并实现了Google GFS文件系统,一个面向大规模数据密集型应用的.可伸缩的分布式文件系统.GFS虽然运行在廉价的普遍硬件设备上,但是它依然了提供灾难冗余的能力,为大量客户机提供了高性能的服务. 虽然GFS的设计目标与许多传统的分布式文件系统有很多相同之处,但是,我们的设计还是以我们对自己的应用的负载情况和技术环境的分析为基础 的,不管现在还是将来,GFS和早期的分布式文件系统的设想都有明显的不同.所以我们重新审视了传统文件系统在设计上的折衷选择,衍生出了完全不同的设计 思路.

谷歌三大核心技术(一)Google File System中文版

The Google File System中文版 译者:alex 摘要 我们设计并实现了Google GFS文件系统,一个面向大规模数据密集型应用的.可伸缩的分布式文件系统.GFS虽然运行在廉价的普遍硬件设备上,但是它依然了提供灾难冗余的能力,为大量客户机提供了高性能的服务. 虽然GFS的设计目标与许多传统的分布式文件系统有很多相同之处,但是,我们的设计还是以我们对自己的应用的负载情况和技术环境的分析为基础 的,不管现在还是将来,GFS和早期的分布式文件系统的设想都有明显的不同.所以我们重新审

老男孩:Linux企业运维人员最常用150个命令汇总

近来老男孩发现新手学习Linux记不住命令,不会分类.不会筛选重点,胡子眉毛一把抓当然记不住了. 特别整理Linux运维最常用150个命令和大家分享,大家学习命令不用在盲目了,根据分类,然后逐步学习! 命令 功能说明 线上查询及帮助命令(2个) man 查看命令帮助,命令的词典,更复杂的还有info,但不常用. help 查看Linux内置命令的帮助,比如cd命令. 文件和目录操作命令(18个) ls 全拼list,功能是列出目录的内容及其内容属性信息. cd 全拼change director