linux创建init进程的3种实现方式原理分析【转】
转自:https://blog.csdn.net/weixin_43644245/article/details/121562388
1. 概述
Linux系统启动过程中通过init_task创建0号idle进程。然后通过kernel_thread创建1号init进程。创建该进程时通过系统调用,在内核空间执行用户空间的/sbin/init程序,通过该程序产生出shell,并依赖init衍生出其他进程。通过top命令查看当前系统环境下的进程列表,可以发现1号进程的为{linuxrc} init
[root@iTOP-4412]# top
Mem: 26404K used, 948572K free, 0K shrd, 3199543672K buff, 0K cached
CPU: 0.0% usr 6.0% sys 0.0% nic 94.0% idle 0.0% io 0.0% irq 0.0% sirq
Load average: 0.00 0.00 0.00 1/78 162
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
162 132 root R 3264 0.3 0 4.5 top
3 2 root IW 0 0.0 0 1.5 [kworker/0:0]
132 1 root S 3268 0.3 2 0.0 -/bin/sh
1 0 root S 3264 0.3 2 0.0 {linuxrc} init
...
我们在kernel代码中会发现,创建1号init进程,主要包括以下3种,如下图所示:
2. 创建init进程的方式
2.1 ramdisk方式
在ramdisk环境下创建init进程时,需要在kernel CMDLINE中设置init程序的路径位置,如下所示:
CONFIG_CMDLINE="...root=/dev/ram rdinit=/sbin/init..."
1
在kernel代码中通过rdinit_setup()解析kernel CMDLINE中rdinit=字符串,赋值给全局变量ramdisk_execute_command。
static int __init rdinit_setup(char *str)
{
unsigned int i;
ramdisk_execute_command = str;
/* See "auto" comment in init_setup */
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("rdinit=", rdinit_setup);
当完成ramdisk_execute_command赋值后,在kernel_init_freeable()对ramdisk_execute_command进行检查,若未检查到有效的字符串,则将ramdisk_execute_command赋值为/init。然后,对ramdisk_execute_command进行访问权限检查,若失败,则进行rootfs挂载。
static noinline void __init kernel_init_freeable(void)
{
...
if (!ramdisk_execute_command)
ramdisk_execute_command = "/init";
if (ksys_access((const char __user *)
ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}
...
}
若ramdisk_execute_command检查成功,则进入kernel_init()中,执行指定的init程序。
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
...
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)\n",
ramdisk_execute_command, ret);
}
...
}
2.2 execute_command方式
通过kernel CMDLINE可以设定执行的init程序,例如:
CONFIG_CMDLINE="root=/dev/mmcblk1p2 rw console=ttySAC2,115200 init=/linuxrc rootwait"
1
在kernel代码中通过init_setup()解析命令行参数"init=",并赋值给execute_command。
static int __init init_setup(char *str)
{
unsigned int i;
execute_command = str;
...
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("init=", init_setup);
最后,在kernel_init()中执行execute_command所指定的init程序。
static int __ref kernel_init(void *unused)
{
...
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}
...
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
2.3 默认方式
若以上两种指定init程序的方式均以失败告终,那么内核代码kernel_init()会执行如下4个默认的init程序,若也失败,则内核上报panic。
static int __ref kernel_init(void *unused)
{
...
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
————————————————
版权声明:本文为CSDN博主「Linux与SoC」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43644245/article/details/121562388
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
2017-04-08 一张图让你学会Python【转】
2016-04-08 Vim中的键映射【转】
2016-04-08 通过call_usermodehelper()在内核态执行用户程序【转】
2015-04-08 linux 串口0x03,0x13的问题【转】