我对用户空间和 init 系统(无论是经典的 init sysV /upstart/systemd)在系统关闭时如何工作有一个粗略的了解。 (本质上有一个连续的命令“停止!”,“请现在停止”,“我需要杀死你才能停止”并等待......事情正在发生)。
无论如何,我非常不知道系统关闭在内核中是如何工作的(其中肯定还有很多事情要做)?
我尝试查看内核文档https://www.kernel.org/doc/htmldocs/甚至使用了NSA 的好友搜索工具让我先了解它是如何工作的。
我还搜索了SE U+L,但什么也没找到(我是否忽略了它?)
无论如何,这个问题虽然可能有点挑战性,但值得在这个问答网络中得到答案,因为我认为更多的人有兴趣了解 Linux 内核在关闭时发生的情况。
可能还会发生一些更改,以链接到一些更详细的解释。
答案可能包括使用哪些系统调用和哪些内核信号?
https://github.com/torvalds/linux/blob/b3a3a9c441e2c8f6b6760de9331023a7906a4ac6/arch/x86/kernel/reboot.c 似乎是 x86 使用的与重新启动相关的文件(已经接近关闭,是吗?)
也许在这里找到的片段http://lxr.free-electrons.com/source/kernel/reboot.c#L176 可以用来给出解释
176 无效kernel_power_off(无效) 177 { 第178章 179 如果(pm_power_off_prepare) 180 pm_power_off_prepare(); 第181章 182 syscore_shutdown(); 183 pr_emerg("断电\n"); 第184章 [第 185 章] 186} 187 EXPORT_SYMBOL_GPL(内核电源关闭);
答案1
了解 Linux 内核工作原理的主要资源有:
- 文档。
- Linux 每周新闻文章。
- 来源。这是一个复杂的野兽,通过它更容易理解LXR,Linux 交叉引用。 LXR 变体运行于lxr.linux.no比别人好,但经常低落。
在这种情况下,我在文档或 LWN 上找不到任何中心相关的内容,所以是 LXR。
用户态代码所做的最后一件事是调用reboot
系统调用。它需要 4 个参数,因此在 LXR 上搜索SYSCALL_DEFINE4(reboot
,结果是kernel/reboot.c
。检查调用者的权限和参数后,系统调用入口点调用以下几个函数之一:kernel_restart
重新启动、kernel_halt
在紧密循环中停止、kernel_poweroff
关闭系统电源kernel_kexec
、更换新内核(如果已编译),或hibernate
在断电前将内存保存到磁盘。
kernel_restart
,kernel_halt
和
kernel_power_off
非常相似:
- 经过
reboot_notifier_list
,这是内核组件可以使用的钩子列表登记在断电时执行代码。此阶段只有少数驱动程序需要执行代码,其中大部分是看门狗。 - 设置
system_state
多变的。 - 禁用 用户模式助手,以确保不再启动任何用户代码。 (此阶段仍可能存在现有流程。)
- 称呼
device_shutdown
释放或关闭系统上的所有设备。很多司机都陷入了这个阶段。
请注意,此时仍挂载的任何文件系统都会被有效地强制卸载。系统调用的调用者负责任何干净的卸载。 - 仅对于关闭电源,如果配置了 ACPI,可能会执行代码准备进入 ACPI 状态S5(软关机)。
- 在多 CPU 计算机中,代码可以在任何 CPU 上运行,无论哪个 CPU 调用了系统调用。
migrate_to_reboot_cpu
注意切换到一个特定的 CPU 并防止调度程序在其他 CPU 上分派代码。此后,只有一个 CPU 正在运行。 syscore_shutdown
调用shutdown
方法注册的 syscore 操作。我认为这主要是关于禁用中断;很少有钩子有shutdown
方法。- 记录一条信息消息——天鹅之歌。
- 最后通过调用以某种依赖于机器的方式休息
machine_restart
,machine_halt
或者machine_power_off
。
这冬眠代码经过以下步骤:
- 迭代通过电源管理挂钩。
- 同步文件系统。
- 冻结所有用户密码。
- 防止设备热插拔。
- 将系统状态转储到交换空间。
- 如果一切顺利的话休眠硬件。这可能涉及调用
kernel_restart
、kernel_halt
、kernel_power_off
、 或某些特定于平台的休眠方法。
关闭系统的另一种方法是machine_emergency_restart
。这是由魔法系统请求钥匙B。按键O的作用不同:它调用kernel_power_off
。
系统还可以关闭至恐慌,即不可恢复的错误。恐慌尝试记录消息,然后重新启动系统(通过硬件看门狗或紧急重新启动)。
答案2
这只是部分答案,我肯定会邀请其他答案,这可能会更详尽和清晰。
这个答案的内容取自3.13 linux内核的kernel/reboot.c
文件(这可能不是第一个猜测,因为名称不是shutdown.c而是reboot.c)
无论如何,我们基本上有三个函数来描绘关闭系统的过程
void kernel_halt(void)
// 以系统处于停止状态结束void kernel_power_off(void)
// 以系统关闭结束void kernel_restart(char *cmd)
// 结束系统并重新启动它
这些函数非常简短,因此可以完整地粘贴到此处。他们的代码最好地展示了内核关闭过程中所采取的步骤。 (这些评论是我写的,可能不是100%理想和正确,请自己检查一下是否确定。这很简单,尝试一下。
void kernel_halt(void)
无效内核停止(无效) { // 第一步: // a) 调用函数/回调注册为在重新启动/关闭时运行 // b) 将 system_sate 设置为 SYSTEM_HALT // c) 停止 userspacetool 交互 // d) 调用 device_shutdown() 函数 kernel_shutdown_prepare(SYSTEM_HALT); // 第二步:我认为这对于多CPU系统来说是必需的 migrate_to_reboot_cpu(); // 第三步: // syscore_shutdown - 执行所有已注册的系统核心关闭回调 syscore_shutdown(); // 第四条消息 pr_emerg("系统停止\n"); kmsg_dump(KMSG_DUMP_HALT); // 第 5 个调用架构特定的 cpu-halt-code machine_halt(); }
整个事情是通过sys_reboot
系统调用启动的,考虑到它不仅会重新启动而且还会关闭,无论如何都不是与关闭过程连接的直接事情。