Linux 魔术系统请求键技巧

sysrq.c 文档

什么是魔术 SysRq 键?

它是一个“神奇”的组合键,无论内核当前正在做什么(除非它完全死锁),内核都会对它做出响应。

如何启用魔术 SysRq 键?

在配置内核时,你需要对“Magic SysRq key (CONFIG_MAGIC_SYSRQ)”选择“yes”。当运行编译了 SysRq 的内核时,/proc/sys/kernel/sysrq 控制着允许通过 SysRq 键调用的功能。该文件中的默认值由 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 配置符号设置,其默认值为 1。以下是 /proc/sys/kernel/sysrq 中可能的值列表:

  • 0 - 完全禁用 sysrq

  • 1 - 启用 sysrq 的所有功能

  • >1 - 允许的 sysrq 功能的位掩码(详细功能描述见下文)

      2 =   0x2 - enable control of console logging level
      4 =   0x4 - enable control of keyboard (SAK, unraw)
      8 =   0x8 - enable debugging dumps of processes etc.
     16 =  0x10 - enable sync command
     32 =  0x20 - enable remount read-only
     64 =  0x40 - enable signalling of processes (term, kill, oom-kill)
    128 =  0x80 - allow reboot/poweroff
    256 = 0x100 - allow nicing of all RT tasks
    

你可以通过以下命令设置该文件中的值

echo "number" >/proc/sys/kernel/sysrq

这里的数字既可以写成十进制,也可以写成带有 0x 前缀的十六进制。CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 必须始终以十六进制形式写入。

请注意,/proc/sys/kernel/sysrq 的值仅影响通过键盘的调用。通过 /proc/sysrq-trigger 调用任何操作始终是允许的(需要管理员权限的用户)。

如何使用魔术 SysRq 键?

在 x86 上

按下组合键 ALT-SysRq-<命令键>

注意

某些键盘可能没有标有“SysRq”的键。“SysRq”键也称为“Print Screen”(打印屏幕)键。此外,有些键盘无法同时处理这么多按键,因此你可以尝试以下操作以提高成功率:按下 Alt,按下 SysRq,释放 SysRq,按下 <命令键>,最后释放所有按键。

在 SPARC 上

据我所知,按下 ALT-STOP-<命令键>

在串行控制台(仅限 PC 风格的标准串口)上

发送一个 BREAK,然后在 5 秒内发送一个命令键。发送两次 BREAK 会被解释为普通的 BREAK。

在 PowerPC 上

按下 ALT - Print Screen(或 F13)- <命令键>。有时仅按 Print Screen(或 F13)- <命令键> 就足够了。

在其他架构上

如果你知道其他架构的组合键,请提交补丁以将其纳入本节。

在所有架构上

向 /proc/sysrq-trigger 写入单个字符。只有第一个字符会被处理,其余字符串将被忽略。但是,不建议写入任何多余的字符,因为其行为是未定义的,并且可能会在未来的版本中改变。例如:

echo t > /proc/sysrq-trigger

或者,写入以下划线前置的多个字符。这样,所有字符都将被处理。例如:

echo _reisub > /proc/sysrq-trigger

<命令键> 区分大小写。

什么是“命令”键?

命令

功能

b

将立即重启系统,而不同步或卸载磁盘。

c

将执行系统崩溃,如果已配置,将收集崩溃转储(crashdump)。

d

显示所有持有的锁。

e

向除 init 之外的所有进程发送 SIGTERM 信号。

f

将调用 OOM killer 来杀死一个大量占用内存的进程,但如果没有可杀死的进程也不会引发 panic。

g

由 kgdb(内核调试器)使用

h

将显示帮助(实际上除了这里列出的键之外的任何其他键都会显示帮助,但 h 很容易记住 :-)

i

向除 init 之外的所有进程发送 SIGKILL 信号。

j

强制“解冻”——通过 FIFREEZE ioctl 冻结的文件系统。

k

安全访问密钥 (SAK) 杀死当前虚拟控制台上的所有程序。注意:请参阅下文 SAK 部分的重要说明。

l

显示所有活动 CPU 的栈回溯。

m

将当前内存信息转储到控制台。

n

用于调整实时(RT)任务的 nice 值

o

将关闭你的系统(如果已配置并受支持)。

p

将当前的寄存器和标志转储到控制台。

q

将转储所有已启动的高精度定时器(hrtimer)的每个 CPU 列表(但不是常规的 timer_list 定时器)以及有关所有 clockevent 设备的详细信息。

r

关闭键盘原始模式(raw mode)并将其设置为 XLATE。

s

将尝试同步所有已挂载的文件系统。

t

将当前任务及其信息列表转储到控制台。

u

将尝试把所有已挂载的文件系统重新挂载为只读。

v

强制恢复帧缓冲控制台

v

导致 ETM 缓冲区转储 [ARM 专用]

w

转储处于不可中断(阻塞)状态的任务。

x

在 ppc/powerpc 平台上由 xmon 接口使用。在 sparc64 上显示全局 PMU 寄存器。在 MIPS 上转储所有 TLB 条目。

y

显示全局 CPU 寄存器 [SPARC-64 专用]

z

转储 ftrace 缓冲区

0-9

设置控制台日志级别,控制哪些内核消息会打印到你的控制台。(例如,0 可以使只有像 PANIC 或 OOPS 这样的紧急消息才能输出到你的控制台。)

R

在控制台上重放内核日志消息。

好的,那么我可以用它们来做什么?

嗯,当你的 X 服务或 svgalib 程序崩溃时,unraw(r) 非常方便。

当你想确保控制台上没有运行在你尝试登录时可能窃取你密码的特洛伊木马程序时,sak(k)(安全访问密钥)非常有用。它将杀死给定控制台上的所有程序,从而使你能够确保看到的登录提示符实际上来自 init,而不是某些木马程序。

重要提示

从其本意来看,它并不是符合 c2 标准系统中的那种真正 SAK,不应将其误认为是那样的 SAK。

其他人似乎也发现它作为(系统注意键 System Attention Key)很有用,当你想要退出不允许你切换控制台的程序时(例如 X 或 svgalib 程序),它非常有用。

当你无法关机时,reboot(b) 非常好用,它相当于按下“reset(重置)”按钮。

当系统挂起时,可以使用 crash(c) 手动触发 crashdump。请注意,如果没有可用的转储机制,这只会触发崩溃。

在拔出可移动介质之前或在使用不提供优雅关机的救援 shell 之后,sync(s) 非常方便——它将确保你的数据安全写入磁盘。请注意,直到你在屏幕上看到“OK”和“Done”出现时,同步才算真正完成。

可以用 umount(u) 将文件系统标记为正确卸载。从正在运行的系统的角度来看,它们将被重新挂载为只读。直到你在屏幕上看到“OK”和“Done”消息出现,重新挂载才算完成。

当你的控制台充斥着你不想看到的内核消息时,日志级别 0-9 非常有用。选择 0 将阻止除了最紧急的内核消息之外的所有消息到达你的控制台。(不过,如果 syslogd/klogd 仍在运行,它们仍会被记录到日志中。)

如果你有一些无法用其他方法杀死的失控进程,特别是当它还在派生其他进程时,term(e)kill(i) 会非常有用。

如果你的系统由于通过 FIFREEZE ioctl 冻结的文件系统(可能是根文件系统)而变得无响应,“just thaw it(j)”(解冻它)会非常有用。

当系统挂起或无法使用 dmesg 命令查看 printk 缓冲区中的消息时,Replay logs(R)(重放日志)可用于查看内核日志消息。如果控制台系统繁忙,用户可能需要多次按下组合键。如果它完全死锁,则不会打印消息。输出消息取决于当前的控制台日志级别,可以使用 sysrq[0-9] 修改该级别(见上文)。

有时使用 SysRq 后它似乎会“卡住”,我该怎么办?

当发生这种情况时,尝试轻敲键盘两侧的 shift、alt 和 control 键,然后再次输入一个无效的 sysrq 序列(例如 alt-sysrq-z 之类的东西)。

切换到另一个虚拟控制台(ALT+Fn)然后再切换回来也应该会有所帮助。

我按下了 SysRq,但似乎没有任何反应,是怎么回事?

有些键盘产生的 SysRq 键码与预定义的值 99 不同(参见 include/uapi/linux/input-event-codes.h 中的 KEY_SYSRQ),或者根本没有 SysRq 键。在这些情况下,运行 showkey -s 找到合适的扫描码序列,并使用 setkeycodes <sequence> 99 将此序列映射到通常的 SysRq 代码(例如 setkeycodes e05b 99)。最好将此命令放入启动脚本中。哦,顺便说一下,你可以通过十秒钟不输入任何内容来退出 showkey

我想向模块添加 SysRQ 键事件,它是如何工作的?

为了在表中注册一个基本函数,你必须首先包含头文件 include/linux/sysrq.h,这将定义你需要的所有其他内容。接下来,你必须创建一个 sysrq_key_op 结构体,并为其填充:A)你将使用的按键处理函数,B)当 SysRQ 打印帮助时会打印的 help_msg 字符串,以及 C)在调用你的处理函数之前会打印的 action_msg 字符串。你的处理函数必须符合 ‘sysrq.h’ 中的原型。

创建 sysrq_key_op 后,你可以调用内核函数 register_sysrq_key(int key, const struct sysrq_key_op *op_p);,如果表中的该槽位为空,这会将 op_p 指向的操作注册到表键 ‘key’。在模块卸载时,你必须调用函数 unregister_sysrq_key(int key, const struct sysrq_key_op *op_p),当且仅当该槽位当前注册的正是 ‘op_p’ 指向的键操作时,它才会将其从键 ‘key’ 中移除。这是为了防止自你注册以来该槽位已被覆盖。

Magic SysRQ 系统的运作原理是将按键操作注册到在 ‘drivers/tty/sysrq.c’ 中定义的按键操作查找表中。这个按键表在编译时注册了许多操作,但它是可变的,并且导出了 2 个函数用于与其进行接口交互:

register_sysrq_key and unregister_sysrq_key.

当然,切勿在表中留下无效指针。也就是说,当调用了 register_sysrq_key() 的模块退出时,它必须调用 unregister_sysrq_key() 来清理它所使用的 sysrq 键表项。表中的空指针始终是安全的。 :)

如果由于某种原因你觉得需要在由 handle_sysrq 调用的函数内部再调用 handle_sysrq 函数,你必须意识到你正处于锁中(你还处于中断处理程序中,这意味着不能睡眠!),因此你必须改用 __handle_sysrq_nolock

当我按下 SysRq 组合键时,为什么控制台上只显示了标题?

Sysrq 输出受制于与所有其他控制台输出相同的控制台日志级别控制。这意味着如果内核是以“quiet”启动的(这在发行版内核中很常见),输出可能不会出现在实际控制台上,尽管它会出现在 dmesg 缓冲区中,并且可以通过 dmesg 命令以及 /proc/kmsg 的消费者访问。作为一项特定的例外,来自 sysrq 命令的标题行会被传递给所有控制台消费者,就像当前日志级别为最高一样。如果只发出了标题,几乎可以肯定是内核日志级别太低了。如果你需要在控制台通道上输出,则需要使用 alt-sysrq-8 临时提高控制台日志级别,或者

echo 8 > /proc/sysrq-trigger

在触发你感兴趣的 sysrq 命令后,记得将日志级别恢复正常。

我还有更多问题,可以向谁咨询?

直接在 linux-kernel 邮件列表上提问即可

linux-kernel@vger.kernel.org

致谢