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


28

对于系统关闭时用户空间和init-system(经典的init sysV / upstart / systemd)如何工作,我有个大概的想法。(本质上是“ Stop!”,“请立即停止”,“我需要杀死您以停止的过程”并等待...的顺序。)

无论如何,我非常不知道内核中的系统关闭是如何工作的(肯定还有很多事情要做)?

我尝试查看内核文档https://www.kernel.org/doc/htmldocs/,甚至使用NSA的pal搜索工具为我提供了寻找其工作原理的开端。

我还搜索了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 void kernel_power_off(void)
177 {
(178)第178章
第179章
180 pm_power_off_prepare();
第181回
第182回
183 pr_emerg(“ Power down \ n”);
184 kmsg_dump(KMSG_DUMP_POWEROFF);
第185章
186}
第187章(二更)

8
愿独角兽与您同在
Kiwy 2014年

1
@Kiwy谢谢您的建议。经过一段时间后,我会接受潜在的更好答案。但是现在至少有一些答案。
humanityANDpeace

谢谢我,谢谢独角兽!
2014年

请注意,有/曾经有一个跳出窗口的选项,shutdown(8)即已弃用的 选项-n,我认为在旧的unix文档中,该选项用于读取“ 自行关闭系统-核心单元已着火! ”,这实际上是一个混乱的系统kill-switch,会/可能会使零碎散布在地板上(或至少是处于损坏状态的文件系统)-有人认为这将用于某人刚抓住冷却风扇的大型机系统。🕱–
SlySven

Answers:


26

了解Linux内核如何工作的主要资源是:

  1. 文档
  2. Linux每周新闻文章
  3. 来源。这是一个复杂的野兽,通过Linux交叉引用LXR可以更容易理解。在lxr.linux.no上运行的LXR变体比其他变体要好,但是通常会下降。

在这种情况下,我在文档或LWN中找不到任何与中心相关的东西,所以LXR就是。

用户区代码要做的最后一件事是调用reboot系统调用。它需要4个参数,因此请SYSCALL_DEFINE4(reboot在LXR上搜索,结果为kernel/reboot.c。检查调用者的特权和参数后,系统调用入口点调用的几个功能之一:kernel_restart重新启动,kernel_halt要在紧密的循环停止,kernel_poweroff以关闭系统电源,kernel_kexec通过更换一个新的内核(如编译),或hibernate在关闭电源之前将内存保存到磁盘。

kernel_restartkernel_halt并且 kernel_power_off非常相似:

  1. 通过reboot_notifier_list,这是内核组件可以注册以在断电时执行代码的钩子列表。在此阶段,只有少数驱动程序需要执行代码,其中大多数是看门狗。
  2. 设置system_state变量。
  3. 禁用 usermode-helper,以确保不再启动任何用户代码。(现阶段仍可能存在现有的过程。)
  4. 呼叫device_shutdown以释放或关闭系统上的所有设备。许多驾驶员都进入了这个阶段。
    请注意,此时仍在强制挂载的所有文件系统均已被强行卸载。系统调用的调用方负责所有干净的卸载。
  5. 仅对于断电,如果配置了ACPI,则可能执行代码以准备进入ACPI 状态S5(软断电)。
  6. 在多CP​​U机器中,代码可以在任何CPU上运行,无论哪个调用了系统调用。migrate_to_reboot_cpu请注意切换到一个特定的CPU,并防止调度程序在其他CPU上调度代码。此后,仅单个CPU在运行。
  7. syscore_shutdown调用注册的syscore操作shutdown方法。我认为这主要与禁用中断有关。很少有钩子的方法。shutdown
  8. 记录一条信息消息-天鹅的歌。
  9. 最后去调用一些机器相关的方式休息machine_restartmachine_haltmachine_power_off

冬眠代码经过以下步骤:

  1. 遍历电源管理挂钩
  2. 同步文件系统。
  3. 冻结所有用户代码
  4. 防止设备热插拔
  5. 将系统状态转储到交换空间。
  6. 如果一切成功,请使硬件休眠。这可能涉及调用kernel_restartkernel_haltkernel_power_off或某些特定于平台的休眠方法。

关闭系统的另一种方法是machine_emergency_restart。这由魔术SysRq调用B。在O关键的工作方式不同:它调用kernel_power_off

系统也可能会崩溃,即无法恢复的错误。Panicking尝试记录消息,然后重新启动系统(通过硬件监视程序或紧急重启)。


+1谢谢!@Gilles如果您想实现一些将擦拭/清理机器RAM的代码作为最后一步,则可以为syscore注册一个syscore操作syscore_shutdown(即可以解决我的其他问题unix.stackexchange.com/q/122540/24394) 。步骤(1)和步骤(7)都允许注册要在关机时执行的内容,而不是弄清楚什么是什么+我印象深刻的是,无法影响(1)和(7)中的那些回调的执行顺序!我会提及您提到的文档,但是如果您知道的话!谢谢!
humanityANDpeace

我很惊讶这个问题和答案没有更多的投票。

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)

无效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);

    //第五次调用arch特定的cpu-halt-code
    machine_halt();
}

整个过程都是通过sys_reboot系统调用来启动的,因为它不仅会重新引导,还会关闭,而不是直接与关闭过程建立连接的事物。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.