Linux关机重启停机(shutdown reboot halt)流程分析
来源:互联网 发布:sql 2008 sa 密码 编辑:程序博客网 时间:2024/05/18 02:22
由于本人水平相当有限,不当之处还望大家多多指教。
涉及的内核源码,基于linux-3.10.102。
首先,对于用户态发起的这类操作请求,最终都是通过sys_reboot系统调用(源码在kernel/sys.c)实现的。
其代码如下。如其注释所言,他除了可以重启关机停机,还可以修改ctrl-alt-del组合键的含义。
另外,注释还说到此系统调用不会做sync。即sync需要用户在调用此系统调用之前自己完成。
/* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers * so that some mistake won't make this reboot the whole machine. * You can also set the meaning of the ctrl-alt-del-key here. * * reboot doesn't sync: do that yourself before calling this. */SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,void __user *, arg){struct pid_namespace *pid_ns = task_active_pid_ns(current);char buffer[256];int ret = 0;/* We only trust the superuser with rebooting the system. */if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))return -EPERM;/* For safety, we require "magic" arguments. */if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C))return -EINVAL;/* * If pid namespaces are enabled and the current task is in a child * pid_namespace, the command is handled by reboot_pid_ns() which will * call do_exit(). */ret = reboot_pid_ns(pid_ns, cmd);if (ret)return ret;/* Instead of trying to make the power_off code look like * halt when pm_power_off is not set do it the easy way. */if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)cmd = LINUX_REBOOT_CMD_HALT;mutex_lock(&reboot_mutex);switch (cmd) {case LINUX_REBOOT_CMD_RESTART:kernel_restart(NULL);break;case LINUX_REBOOT_CMD_CAD_ON:C_A_D = 1;break;case LINUX_REBOOT_CMD_CAD_OFF:C_A_D = 0;break;case LINUX_REBOOT_CMD_HALT:kernel_halt();do_exit(0);panic("cannot halt");case LINUX_REBOOT_CMD_POWER_OFF:kernel_power_off();do_exit(0);break;case LINUX_REBOOT_CMD_RESTART2:if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {ret = -EFAULT;break;}buffer[sizeof(buffer) - 1] = '\0';kernel_restart(buffer);break;#ifdef CONFIG_KEXECcase LINUX_REBOOT_CMD_KEXEC:ret = kernel_kexec();break;#endif#ifdef CONFIG_HIBERNATIONcase LINUX_REBOOT_CMD_SW_SUSPEND:ret = hibernate();break;#endifdefault:ret = -EINVAL;break;}mutex_unlock(&reboot_mutex);return ret;}
从上述代码来看,相关的操作分别是由函数kernel_restart, kernel_power_off, kernel_halt完成的。
另外,对于修改ctrl-alt-del组合键含义的操作(LINUX_REBOOT_CMD_CAD_ON和LINUX_REBOOT_CMD_CAD_OFF),
内核只是简单修改一下变量C_A_D的值,然后就返回了。
而kernel_restart, kernel_power_off, kernel_halt这几个函数的实现也很相似:
先是通知reboot_notifier_list中的模块,系统要重启了。
然后将调用此系统调用的线程迁移到CPU 0上面。
然后执行syscore_ops_list中的各种关机操作。
最后,将系统转入restart/halt/power_off流程。
再看看用户态触发sys_reboot系统调用的C库函数reboot(man 2 reboot)的说明,对于重启关机停机类的操作,其中全都提到If not preceded by a sync(2), data will be lost.。可见,如果在调用reboot库函数前,没有调用sync(2),会导致未保存的文件数据丢失。
同时,说明中还提到对于成功的关机重启停止操作,reboot函数将不会返回。
通常,比较完善的关机重启停机流程,是通过用户态工具reboot实现的。
如果查看此工具的帮助,会发现一共有3个工具,分别是reboot, halt, poweroff。
但他们实际上对应于同一个可执行程序/sbin/reboot。
[root@localhost ~]# ls -l /sbin/reboot -rwxr-xr-x. 1 root root 13932 Jun 25 2013 /sbin/reboot[root@localhost ~]# ls -l /sbin/halt lrwxrwxrwx. 1 root root 6 Aug 7 2016 /sbin/halt -> reboot[root@localhost ~]# ls -l /sbin/poweroff lrwxrwxrwx. 1 root root 6 Aug 7 2016 /sbin/poweroff -> reboot
这三个工具,分别实现他们的名字对应的功能。
如果使用时,加了--force选项,则他们将直接调用C库函数reboot。这会导致未保存的文件数据丢失。
如果未加--force,则他们会执行用户态工具shutdown。由此可见,完善的操作流程是由shutdown程序完成的。
shutdown具体是如何组织流程的,可以参考其手册页 (man 8 shutdown)。
实际上,主要工作是shutdown向init进程发起了一个改变系统运行级别(runlevel)的请求,然后由init进程将系统降到相应的运行级别。
最后,感觉sys_reboot似乎并没有对可能存在着的大量的用户态进程进行妥善处理。而且他的注释也说明了,需要用户自己调用sync保存数据。
sys_reboot只管重启关机停机。
因此,完善的结束用户态的所有上下文的任务,就留给了用户态自己。而从前面的分析来看,正常的流程,最终就是init进程负责清空所有的用户态上下文。
这样一来,内核与用户态的关系就极其简单清晰。内核就是以系统调用为界面,为用户提供服务。用户空间的各种复杂关系,是用户空间自己的事。
系统启动时,内核在后期,拉起init进程。然后init进程通过各种系统调用,建立起用户态的一切。
最后系统正常关闭时,同样由init进程通过各种系统调用,清空用户态的一切,最后通过sys_reboot关闭系统。
当然,对于非正常关机,例如某个进程直接触发了sys_reboot,那么用户态的上下文就没有妥善结束,因此就可能丢失未保存的数据。
最后,再额外提一下,内核自身(例如,软件看门狗)在紧急情况下,想重启系统,可能会通过直接调用emergency_restart函数来实现。
下面是其代码
/** *emergency_restart - reboot the system * *Without shutting down any hardware or taking any locks *reboot the system. This is called when we know we are in *trouble so this is our best effort to reboot. This is *safe to call in interrupt context. */void emergency_restart(void){kmsg_dump(KMSG_DUMP_EMERG);machine_emergency_restart();}EXPORT_SYMBOL_GPL(emergency_restart);void machine_emergency_restart(void){__machine_emergency_restart(1);}static void __machine_emergency_restart(int emergency){reboot_emergency = emergency;machine_ops.emergency_restart();}
- Linux关机重启停机(shutdown reboot halt)流程分析
- 【LINUX】Linux 关机/重启 shutdown、halt、reboot和init
- Linux常用关机重启命令shutdown\halt\reboot\init
- Android6.0 关机shutdown & 重启reboot流程分析
- linux下常用的关机/重启命令shutdown、halt、reboot、init
- linux下常用的关机/重启命令shutdown、halt、reboot、init
- Linux/Unix关机、重启(shutdown\reboot\halt\init)等命令
- Linux关机命令:halt shutdown reboot init
- linux常用关机命令及其区别-Shutdown halt reboot init
- linux 关机命令-shutdown、halt、reboot、及init
- Linux 关机命令 shutdown halt reboot init telinit poweroff
- linux命令--关机命令shutdown、halt、poweroff、reboot
- linux 关机重启 shutdown和reboot的区别
- Linux 关机重启命令 shutdown reboot init
- Linux 关机重启命令(logout/shutdown/reboot)
- 【转载】关于shutdown halt reboot poweroff init 0几种关机和重启命令的理解
- Linux下关机命令的区别 (halt,poweroff,reboot,shutdown,init)
- Linux下关机命令的区别 (halt,poweroff,reboot,shutdown,init)
- 比特币解决方法推荐
- 常见对象-StringBuffer和String的相互转换
- 进程间通信方法一:匿名管道
- Scala中的数组、映射、元组、集合
- 创世纪
- Linux关机重启停机(shutdown reboot halt)流程分析
- tensorflow:fully_connected_feed.py代码详细中文注释
- 模板方法模式【Template Method Pattern】
- 应届生/初级数据库开发笔面试汇总
- 关于main函数的第二个参数
- selenium+testng+gitblit+jenkins+ant自动化测试系列九:ant的build.xml文件详解及运用
- 基于JAVA对象流写的图书进销存系统管理
- java 求最大数
- Effective C++ 读书笔记五