root_fs文件系统结构分析和内核加载流程

目录

概述

1 根文件系统下目录介绍

2 文件系统内容分析

2.1 etc/inittab代码分析

2.2 /etc/init.d/rcS 代码分析

2.3 /etc/mdev.conf代码分析

2.3.1 功能概述

2.3.2 /etc/mdev.conf的详细代码

2.4 /etc/init.d/rcS的源代码文件

3 分析内核中加载root_fs的流程

3.1 调用入口一:vfs_caches_init

3.1.1 init_rootfs

3.1.2 init_mount_tree

3.1.2.1 vfs_kern_mount

3.1.2.2 配置root path

3.2 调用入口二: rest_init函数

3.2.1 函数调用关系

3.2.2 kernel_init函数


概述

本文主要详细分析了root_fs文件系统结构,对该文件目录下的每个类型的文件做了详细的介绍,并讲述各个文件的作用,其在内核中主要实现了什么功能,还介绍了内核加载root_fs的过程,详细跟踪了整个的加载流程,介绍每一个函数的调用关系。

1 根文件系统下目录介绍

嵌入式 Linux 中都需要构建根文件系统,构建根文件系统的规则在 FHS(Filesystem Hierarchy Standard)文档中,下面是根文件系统顶层目录。

目录名称内容
bin所有用户都可以使用的、基本的命令。
sbin基本的系统命令,它们用于启动系统、修复系统等。
usr共享、只读的程序和数据。
proc这是个空目录,常作为 proc 文件系统的挂载点。
dev该目录存放设备文件和其它特殊文件。
etc系统配置文件,包括启动文件。
lib存放共享库和可加载块(即驱动程序),共享库用于启动系统、运行根文件系统中的可执行程序。
boot引导加载程序使用的静态文件
home用户主目录,包括供服务账号锁使用的主目录,如 FTP
mnt临时挂接某个文件系统的挂接点,通常是空目录。也可以在里面创建空的子目 录。
opt给主机额外安装软件所摆放的目录
rootroot 用户的主目录
tmp存放临时文件,通常是空目录。
var存放可变的数据。

2 文件系统内容分析

默认的内核命令行上有 init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程序是根目录下的 linuxrc。 这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的第一个程序也就是 busybox 本身。

busybox首先将试图解析/etc/inittab 来获取进一步的初始化配置信息(参考 busybox 源代码 init/init.c 中)parse_inittab()函数。而事实上, root_qtopia 中并没有/etc/inittab 这个配置文件,根据 busybox 的逻辑,它将生成默认的配置 。

2.1 etc/inittab代码分析

查看busybox-1.13.3/init/init.c文件中parse_inittab()函数的源码:

代码第701行: new_init_action(SYSINIT, INIT_SCRIPT, ""),也就决定了接下去初始化的脚本是 INIT_SCRIPT 所定义的值。这个宏的默认值是"/etc/init.d/rcS".

#define INITTAB        "/etc/inittab"   /* inittab file location */
#ifndef INIT_SCRIPT
#define INIT_SCRIPT   "/etc/init.d/rcS" /* Default sysinit script. */
#endif

parse_inittab() 函数的源代码

2.2 /etc/init.d/rcS 代码分析

该文件的路径: /etc/init.d/rcS。详细分析代码如下:

代码第3~5行: 为启动环境设置必要的环境变量

代码第13行: 设置机器的名称

代码第15~18行:

挂载“虚拟”文件系统“/proc”和“/sys”,并且在/dev 目录上挂载一个 ramfs,相当于把原本 NAND Flash 上的只读的/dev 目录“覆盖”上一块可写的空的 SDRAM。

/sys 和挂载了 ramfs 的/dev 是正确创建设备节点的关键。对于 2.6.29 内核来说,已经没有了 devfs 的支持,创建设备节点只有通过两种办法由文件系统完成:

1) 制作文件系统镜像前用 mknod 手动创建好系统中所有的(包括可能有的)设备节点, 并把这些节点文件一起做进文件系统镜像中;

2)在文件系统初始化过程中,通过/sys 目录所输出的信息,在/dev 目录下动态的创建 系统中当前实际有的设备节点

代码第20~22行:

1)通过 mdev -s 在/dev 目录下建立必要的设备节点;

2)设置内核的 hotplug handler 为 mdev, 即当设备热插拔时,由 mdev 接收 来自内核的消息并作出相应的回应, 比如挂载 U 盘。

对于 mdev,需要注意的是,文件系统里存在/etc/mdev.conf 文件,它包含了 mdev 的配置信息。

代码第24~35行:用来挂载其他一些常用的文件系统,并在/var 目录下(同样是ramfs,可写的)新建必要的目录。

代码第36行:用来设定系统时间的,从硬件 RTC 中获取,要获取正确的时间,必须先设置好正确的时间(如何设置 RTC 见用户手册说明)。

代码第39~54行:启动一系列服务:

服务类型说明
syslog用于记录内核和应用程序 debug 信息
netd - inetd一个挂载启动各种网络相关服务的看守进程
httpd - http server进程
leds跑马灯看守进程

代码47~48行:配置网络设备(网卡): 设定本机回环地址为 127.0.0.1 2)运行网卡设置脚本/etc/init.d/ifconfig-eth0

查看/etc/init.d/ifconfig-eth0 文件的内容:

#!/bin/sh
​
echo -n Try to bring eth0 interface up......>/dev/ttySAC0
​
if [ -f /etc/eth0-setting ] ; thensource /etc/eth0-setting
​if grep -q "^/dev/root / nfs " /etc/mtab ; thenecho -n NFS root ... > /dev/ttySAC0elseifconfig eth0 downifconfig eth0 hw ether $MACifconfig eth0 $IP netmask $Mask uproute add default gw $Gatewayfi
​echo nameserver $DNS > /etc/resolv.conf
else
​if grep -q "^/dev/root / nfs " /etc/mtab ; thenecho -n NFS root ... > /dev/ttySAC0else/sbin/ifconfig eth0 192.168.1.230 netmask 255.255.255.0 upfi
fi
​
echo Done > /dev/ttySAC0
查看/etc/eth0-setting,源码如下:

2.3 /etc/mdev.conf代码分析

2.3.1 功能概述

/etc/mdev.conf文件查看源码:

1)原本串口驱动注册的设备名是 s3c2410_serial0, s3c2410_serial1 和s3c2410_serial2,而 mdev 则会在/dev 目录下对应生成 ttySAC0, ttySAC1 和 ttySAC2 以符合应用程序对于串口设备名称的习惯。

2) /dev/sdcard 和/dev/udisk 永远分别指向 SD 卡和U 盘的第一个分区。

3) 当 SD 卡或者 U 盘插入/拔出时,将这个消息传递给自定义的热插拔 handler, /bin/hotplug. 这个程序用于自动挂载可移动设备的,目前是 SD卡和 U 盘。它的逻辑很简单,将 SD 卡或者 U 盘的第一个分区作为 FAT/FAT32 挂载到/sdcard或者/udisk.

注意的问题:

当 SD 卡或者 U 盘上没有分区表或者第一个分区不是 FAT/FAT32 格式的时候,它就不能正常工作

2.3.2 /etc/mdev.conf的详细代码

# system all-writable devices
full        0:0 0666
null        0:0 0666
ptmx        0:0 0666
random      0:0 0666
tty     0:0 0666
zero        0:0 0666
​
# console devices
tty[0-9]*   0:5 0660
vc/[0-9]*   0:5 0660
​
# serial port devices
s3c2410_serial0 0:5 0666    =ttySAC0
s3c2410_serial1 0:5 0666    =ttySAC1
s3c2410_serial2 0:5 0666    =ttySAC2
s3c2410_serial3 0:5 0666    =ttySAC3
​
# loop devices 
loop[0-9]*  0:0 0660    =loop/
​
# i2c devices
i2c-0       0:0 0666    =i2c/0
i2c-1       0:0 0666    =i2c/1
​
# frame buffer devices
fb[0-9]     0:0 0666
​
# input devices
mice        0:0 0660    =input/
mouse.*     0:0 0660    =input/
event.*     0:0 0660    =input/
ts.*        0:0 0660    =input/
​
# rtc devices
rtc0        0:0 0644    >rtc
rtc[1-9]    0:0 0644
​
# misc devices
mmcblk0p1   0:0 0600    =sdcard */bin/hotplug.sh
sda1        0:0 0600    =udisk * /bin/hotplug.sh
 

2.4 /etc/init.d/rcS的源代码文件

#! /bin/sh
​
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
​
#
#   Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
#
trap ":" INT QUIT TSTP
/bin/hostname FriendlyARM
​
/bin/mount -n -t proc none /proc
/bin/mount -n -t sysfs none /sys
/bin/mount -n -t usbfs none /proc/bus/usb
/bin/mount -t ramfs none /dev
​
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
/bin/hotplug
# mounting file system specified in /etc/fstab
mkdir -p /dev/pts
mkdir -p /dev/shm
/bin/mount -n -t devpts none /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs /dev/shm
/bin/mount -n -t ramfs none /tmp
/bin/mount -n -t ramfs none /var
mkdir -p /var/empty
mkdir -p /var/log
mkdir -p /var/lock
mkdir -p /var/run
mkdir -p /var/tmp
​
/sbin/hwclock -s
​
syslogd
/etc/rc.d/init.d/netd start
echo "                        " > /dev/tty1
echo "Starting networking..." > /dev/tty1
/etc/rc.d/init.d/leds start
echo "                        " > /dev/tty1
echo "Starting leds service..." > /dev/tty1
echo "                        "
​
/sbin/ifconfig lo 127.0.0.1
/etc/init.d/ifconfig-eth0
​
soundplayer /root/testsound.mp3&
/bin/rtm&
​
echo "                                  " > /dev/tty1
echo "Starting MiniTest, please waiting..." > /dev/tty1

3 分析内核中加载root_fs的流程

内核的启动时从start_kernel()开始的,在该函数中调用vfs_caches_init() 和rest_init函数。其具体函数调用关系如下图所示:

3.1 调用入口一:vfs_caches_init

文件地址: \init\main.c

vfs_caches_init()所在的文件地址: \fs\dcache.c

在vfs_caches_init()函数中调用mnt_init()函数

mnt_init()函数所在文件地址:\fs\namespace.c

在mnt_init()函数中调用 init_rootfs()init_mount_tree()初始化和挂载文件系统

函数调用关系如下:

3.1.1 init_rootfs

该函数所在的文件地址:fs\namespace.c

查看init_rootfs()的源码:

在init_rootfs函数中初始化RAM fs,函数调用关系:

3.1.2 init_mount_tree

在函数中匹配root_fs的类型;init_mount_tree()所在的文件地址:\fs\namespace.c

函数调用关系:

3.1.2.1 vfs_kern_mount

init_mount_tree()函数调用vfs_kern_mount()函数挂载文件系统

在vfs_kern_mount()函数中调用mount_fs(),函数中的调用关系

3.1.2.2 配置root path

在init_mount_tree()中还调用两个重要的函数:

代码3090行: set_fs_pwd()

代码3091行: set_fs_root()

3.2 调用入口二: rest_init函数

3.2.1 函数调用关系

函数调用关系:

函数rest_init中的细节如下:

代码394行: 该线程调用kernel_init,初始化root_fs其他的参数

3.2.2 kernel_init函数

函数调用关系:

kernel_init()的详细代码如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/578598.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos7配置阿里云的镜像站点作为软件包下载源

目录 1、备份 2、下载新的 CentOS-Base.repo 到 /etc/yum.repos.d/ 3、测试 阿里镜像提供的配置方法:centos镜像_centos下载地址_centos安装教程-阿里巴巴开源镜像站 1、备份 [rootlocalhost ~]# mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentO…

[Linux]基础IO(上)--理解文件系统调用、文件描述符、万物皆文件

一、文件的理解 每种语言都有进行文件操作的函数接口,例如C语言的fopen、fwrite、fprintf等等,但是进行文件操作的前提是代码已经跑起来,因为文件的打开与关闭要通过CPU来运行程序代码,所以打开文件的本质是进程打开文件&#xff…

2024 ccfcsp认证打卡 2021 12 01 序列查询

2021 12-1 序列查询 题解1题解2区别第一种算法:第二种算法: 题解1 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);// 输入n表示商品数目,N表示总数int n sc.n…

ChatGPT如何升级为GPT-4在国内

通过 WildCard 可以把ChatGPT升级为GPT-4 地址 1: 2155 Bailey Hill Rd 城市: Eugene 邮编: 97405 州: Oregon ChatGPT Plus/Team 一键升级,几分钟即可自动升级到 ChatGPT Plus。 选择我的邮箱账号符合要求 复制这个页面的链接即可 复制上面的link 到请在…

Harbor部署

Harbor部署 下载和安装 github下载地址:https://github.com/goharbor/harbor/releases 解压和配置 # 解压tgz包 tar -zxvf harbor-offline-installer-v2.10.1.tgz # 进入目录后进行复制配置文件 cd harbor/ # 创建一个配置文件 cp harbor.yml.tmpl harbor.yml …

Oracle利用BBED恢复崩溃实例(ORA-01092,ORA-00704,ORA-01578)

BBED修复数据损坏引起的数据库崩溃(ORA-01092,ORA-00704,ORA-01578)(2021年某苏州国企的案例) 1.Symptom 用户一个边缘系统出现数据文件损坏,且没有备份,数据库无法启动 报错如下,发现是oracle bootstra…

pnpm、monorepo分包管理、多包管理、npm、vite、前端工程化、保姆级教程

浅尝pnpm monorepo 多包管理方案 💡tips: 创建pnpm monorope多包管理框架流程 初始化 mkdir taurus & cd taurus pnpm init创建基础文件 创建文件pnpm-workspace.yaml packages:- packages/**创建文件夹packages/ -packages/ -package.json -pnpm-workspace…

Net8 ABP VNext完美集成FreeSql、SqlSugar,实现聚合根增删改查,完全去掉EFCore

没有基础的,请参考上一篇 彩蛋到最后一张图里找 参考链接 结果直接上图,没有任何业务代码 启动后,已经有了基本的CRUD功能,还扩展了批量删除,与动态查询 动态查询截图,支持分页,排序 实现原理…

《让你的时间多一倍》逃离时间陷阱,你没有自己想的那么懒 - 三余书屋 3ysw.net

让你的时间多一倍 今天我们来阅读法比安奥利卡尔的作品《让你的时间多一倍》。或许你会心生疑虑,这本书是否又是一本沉闷的时间管理指南?但我要告诉你的是,尽管时间管理这个话题已经为大众所熟知,这本书却为我们揭示了一个全新的…

SpringBoot实现RabbitMQ的定向交换机(SpringAMQP 实现Direct定向交换机)

文章目录 Direct 交换机特点实战声明交换及其队列(以注解方式)发消息 应用 上一篇文章中的 Fanout 模式,一条消息,会被所有订阅其交换机的队列都消费。 但是,在某些场景下,我们希望不同的消息被不同的队列消费。这时就要用到 Dir…

RabbitMQ 延时消息实现

1. 实现方式 1. 设置队列过期时间:延迟队列消息过期 死信队列,所有消息过期时间一致 2. 设置消息的过期时间:此种方式下有缺陷,MQ只会判断队列第一条消息是否过期,会导致消息的阻塞需要额外安装 rabbitmq_delayed_me…

实时语音识别(Python+HTML实战)

项目下载地址:FunASR 1 安装库文件 项目提示所需要下载的库文件:pip install -U funasr 和 pip install modelscope 运行过程中,我发现还需要下载以下库文件才能正常运行: 下载:pip install websockets,pi…