Linux 内核的系统关闭内部是如何工作的?

Linux 内核的系统关闭内部是如何工作的?

我对用户空间和 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 内核工作原理的主要资源有:

  1. 文档
  2. Linux 每周新闻文章
  3. 来源。这是一个复杂的野兽,通过它更容易理解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_haltkernel_power_off非常相似:

  1. 经过reboot_notifier_list,这是内核组件可以使用的钩子列表登记在断电时执行代码。此阶段只有少数驱动程序需要执行代码,其中大部分是看门狗。
  2. 设置system_state多变的。
  3. 禁用 用户模式助手,以确保不再启动任何用户代码。 (此阶段仍可能存在现有流程。)
  4. 称呼device_shutdown释放或关闭系统上的所有设备。很多司机都陷入了这个阶段。
    请注意,此时仍挂载的任何文件系统都会被有效地强制卸载。系统调用的调用者负责任何干净的卸载。
  5. 仅对于关闭电源,如果配置了 ACPI,可能会执行代码准备进入 ACPI 状态S5(软关机)。
  6. 在多 CPU 计算机中,代码可以在任何 CPU 上运行,无论哪个 CPU 调用了系统调用。migrate_to_reboot_cpu注意切换到一个特定的 CPU 并防止调度程序在其他 CPU 上分派代码。此后,只有一个 CPU 正在运行。
  7. syscore_shutdown调用shutdown方法注册的 syscore 操作。我认为这主要是关于禁用中断;很少有钩子有shutdown方法。
  8. 记录一条信息消息——天鹅之歌。
  9. 最后通过调用以某种依赖于机器的方式休息machine_restart,machine_halt或者machine_power_off

冬眠代码经过以下步骤:

  1. 迭代通过电源管理挂钩
  2. 同步文件系统。
  3. 冻结所有用户密码
  4. 防止设备热插拔
  5. 将系统状态转储到交换空间。
  6. 如果一切顺利的话休眠硬件。这可能涉及调用kernel_restartkernel_haltkernel_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系统调用启动的,考虑到它不仅会重新启动而且还会关闭,无论如何都不是与关闭过程连接的直接事情。

相关内容