【openwrt】Openwrt系统的reboot流程

news/2024/11/23 16:57:00/

reboot流程


当我们在openwrt系统的终端中敲下 reboot指令后,系统需要进行一系列动作后,才会真正的进行硬件重启。而这一系列的动作可以分为——应用程序的停止和内核的停止。在Openwrt系统中,应用程序的停止是1号进程(也就是 procd)完成的,应用程序全部停止后才会进入内核的重启流程。下面我们将分别来介绍应用程序和内核停止的流程。

首先,我们注意到reboot指令是busybox提供的,而且reboot指令支持传入不同的参数来执行不同的重启模式。

# ls /sbin/reboot -alh
lrwxrwxrwx    1 root     root          14 Apr 17 13:15 /sbin/reboot -> ../bin/busybox/# reboot --help
BusyBox v1.36.1 (2024-05-10 17:21:49 UTC) multi-call binary.
Usage: reboot [-d DELAY] [-nf]
Reboot the system-d SEC  Delay interval  -n      Do not sync  -f      Force (don't go through init) 

下面是reboot指令的参数解释。

参数说明
-d SEC Delay interval延时几秒之后重启
-n不执行sync
-f强制重启,跳过应用层直接走内核重启流程

关于reboot指令的具体实现可以参考busybox源码:halt.c

int halt_main(int argc UNUSED_PARAM, char **argv)if (!(flags & 4)) { /* 不带 -f 参数 */
//TODO: I tend to think that signalling linuxrc is wrong
// pity original author didn't comment on it...if (rc) {/* talk to init */if (!ENABLE_FEATURE_CALL_TELINIT) {/* bbox init assumed */rc = kill(1, signals[which]);// 发送信号给1号进程if (init_was_not_there())rc = kill(1, signals[which]);} }} else {rc = reboot(magic[which]); // reboot -f }

reboot_43">应用层reboot流程

根据前面reboot的源码,如果执行的是不带 -f选项的reboot,那么busybox就会发送信号给1号进程,由1号进程来执行重启流程。在openwrt系统中,1号进程就是procd.

# psPID USER       VSZ STAT COMMAND1 root      1868 S    /sbin/procd  

下面就是procd执行reboot的流程图:
在这里插入图片描述

  • procd_signal()是在procd启动时执行的,里面对SIGTERM,SIGINT,SIGUSR1 这些信号都注册了同一个回调函数——sa_shutdownsa_shutdown 其实是一个指向 struct sigaction 的指针,该结构体定义了如何处理上述信号.
  • procd收到如上信号后,sa_shutdown里面的回调函数会被调用,也就是signal_shutdown()
  • signal_shutdown 里面会根据不同的信号类型设置不同的event,然后将event传入procd_shutdown()
  • procd_shutdown()里面设置state = STATE_SHUTDOWN,随后调用state_enter()进入STATE_SHUTDOWN对应的状态处理流程
  • procd_inittab_run()会遍历整个handlers[],找到name=shutdown的handler,然后执行其cb函数,也就是runrc()
  • runrc()->rcS()->_rc(),_rc()会依次执行/etc/rc.d/ 下面所有K开头的脚本,也是所有应用程序的停止脚本,这一步完成后,rcdone()会被调用。
  • rcdone() 会继续将STATE_SHUTDOWN 状态推进到 STATE_HALT状态,进入STATE_HALT状态后,会执行reboot系统调用进行内核阶段的重启,并且会带上前面的event参数,event参数也会被传递到内核,我们将在后续内核重启流程中继续介绍这个参数的具体作用。
  • 至此,所有的应用程序都已经停止(但1号进程未停止)

reboot_62">内核reboot流程

书接上回,前面提到应用层重启流程的最后一步是执行reboot()函数,其中reboot函数携带的参数可能是RB_AUTOBOOT或者RB_POWER_OFF,在musl libc中(openwrt系统默认使用musl libc而不是glibc)reboot函数的实现以及RB_AUTOBOOTRB_POWER_OFF的定义如下:

//openwrt/build_dir/toolchain-aarch64_cortex-a53_gcc-12.3.0_musl/musl-1.2.4/include/sys/reboot.h
#define RB_AUTOBOOT     0x01234567
#define RB_HALT_SYSTEM  0xcdef0123
#define RB_ENABLE_CAD   0x89abcdef
#define RB_DISABLE_CAD  0
#define RB_POWER_OFF    0x4321fedc
#define RB_SW_SUSPEND   0xd000fce2
#define RB_KEXEC        0x45584543//openwrt/build_dir/toolchain-aarch64_cortex-a53_gcc-12.3.0_musl/musl-1.2.4/src/linux/reboot.c
#include <sys/reboot.h>
#include "syscall.h"int reboot(int type)
{//type=RB_AUTOBOOT or RB_POWER_OFFreturn syscall(SYS_reboot, 0xfee1dead, 672274793, type);
}

我们暂时只关注重启流程,所以type=RB_AUTOBOOT ,上面的reboot函数并没有过多操作,直接就执行了reboot系统调用,root系统调用的整体流程如下:
在这里插入图片描述

  • 进入内核reboot系统调用的处理函数中,用户层传入的参数 RB_AUTOBOOT 对应内核层的参数LINUX_REBOOT_CMD_RESTART,所以后续会调用kernel_restart()函数进行系统重启之前准备工作以及最后的重启动作(其他参数会对应其他动作,请自行参考源码)
  • kernel_restart_prepare()调用device_shutdown()关闭所有注册的device
  • 接下来console应该可以看到reboot: Restarting system的打印信息
  • machine_restart()在不同的平台实现可能不一样,在ARM64平台是调用do_kernel_restart()通知具体的驱动进行重启,通常是通知看门狗驱动来进行最终的物理重启。

参考

openwrt reboot流程
记一个openwrt reboot异步信号处理死锁问题


http://www.ppmy.cn/news/1549327.html

相关文章

C++ 并发专题 - 线程安全的单例模式

一&#xff1a;概述&#xff1a; 在C编程中&#xff0c;call_once 是一种机制&#xff0c;用于确保某个函数或代码段在多线程环境下仅被调用一次。这种机制常用于初始化资源、配置全局变量或执行只需执行一次的逻辑。在 C11 标准中&#xff0c;std::call_once 是由标准库提供的…

Java SE 与 Java EE:基础与进阶的探索之旅

在编程世界中&#xff0c;Java语言以其跨平台、面向对象、丰富的类库等特点&#xff0c;成为了众多开发者和企业的首选编程语言。而Java SE与Java EE&#xff0c;作为Java平台的两个重要组成部分&#xff0c;各自承载着不同的使命&#xff0c;同时又紧密相连&#xff0c;共同构…

Elasticsearch客户端在和集群连接时,如何选择特定的节点执行请求的?

大家好&#xff0c;我是锋哥。今天分享关于【Elasticsearch客户端在和集群连接时&#xff0c;如何选择特定的节点执行请求的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Elasticsearch客户端在和集群连接时&#xff0c;如何选择特定的节点执行请求的&#xff1f; 100…

前端知识点---rest(javascript)

文章目录 前端知识点---rest(javascript)rest的用法基本语法特点使用场景与扩展运算符&#xff08;spread&#xff09;区别小练习 前端知识点—rest(javascript) rest出现于ES2015 function doSum(a,b, ...args) //示例中的args就是一个rest参数 //它会将后续的所有参数存储…

AI技术在电商行业中的应用面临哪些挑战?

AI技术在电商行业的应用尽管具有巨大潜力&#xff0c;但也面临以下主要挑战&#xff1a; 挑战 1. 数据质量与隐私问题 数据量与质量不均&#xff1a;电商平台需要大量高质量数据来训练AI模型&#xff0c;但数据可能不完整、不准确&#xff0c;或存在偏差&#xff0c;影响AI预…

概率论和数理统计知识点汇总——第二章随机变量的分布与数字特征

2.1 随机变量及其分布 1.随机变量的概念 定义2.1 定义在概率空间(Ω,P)上,取值为实数的函数xx(ω)(w∈Ω)称为(Ω,P)上的一个随机变量.) 基本事件:Xa 复合事件:X 2.离散型随机变量的概率分布 定义&#xff1a;X的全部可能取值只有有限个或可数无穷多个 性质&#xff1a; 3…

shell编程(8) until循环以及函数基本创建调用

声明!!! 学习视频来自B站UP主泷羽sec&#xff0c;如涉及侵权马上删除文章 视频链接&#xff1a;泷羽sec 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 # until循环 脚本代码&#xff1a; i0 until [ ! $i -lt 1…

Hello-Go

Hello-Go 环境变量 GOPATH 和 GOROOT &#xff1a;不同于其他语言&#xff0c;go中没有项目的说法&#xff0c;只有包&#xff0c;其中有两个重要的路径&#xff0c;GOROOT 和 GOPATH Go开发相关的环境变量如下&#xff1a; GOROOT&#xff1a;GOROOT就是Go的安装目录&…