本文旨在查找相关资料的基础上梳理一下老师上课的内容,巩固学习。
一、定义概述
挂载
在 Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂载时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录及文件。
根文件系统
根文件系统是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,而且是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本和服务加载到内存中去运行。注:Linux中文件系统和内核是完全独立的两个部分。
根文件系统常用目录
- /bin目录
该目录下的命令可以被root与一般账号所使用,由于这些命令在挂接其它文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中。
- /sbin 目录
该目录下存放只有系统管理员能够使用的命令,系统命令还可以存放在/usr/sbin,/usr/local/sbin目录下,/sbin目录中存放的是基本的系统命令,它们用于启动系统和修复系统等,与/bin目录相似,在挂接其他文件系统之前就可以使用/sbin,所以/sbin目录必须和根文件系统在同一个分区中。
- /dev目录
该目录下存放的是设备与设备接口的文件,设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种设备,即通过读写某个设备文件操作某个具体硬件。例如通过"dev/ttySAC0"文件可以操作串口0。
- /etc目录
该目录下存放着系统主要的配置文件,例如人员的账号密码文件、各种服务的其实文件等。一般来说,此目录的各文件属性是可以让一般用户查阅的,但是只有root有权限修改。
- /lib目录
该目录下存放共享库和可加载驱动程序,共享库用于启动系统。运行根文件系统中的可执行程序,比如:/bin /sbin 目录下的程序。
- /mnt目录
用于临时挂载某个文件系统的挂接点,通常是空目录,也可以在里面创建一引起空的子目录,比如/mnt/cdram /mnt/hda1 。用来临时挂载光盘、移动存储设备等。
- /tmp目录
用于存放临时文件,通常是空目录,一些需要生成临时文件的程序用到的/tmp目录下,所以/tmp目录必须存在并可以访问
VFS
VFS(virtual File System)是一个为各类文件系统提供了一个统一的操作界面和应用编程的接口。它可以让open()、read()、write()等系统调用不用关心底层的存储介质和文件系统类型就可以工作的层。
二、根文件系统挂载过程
嵌入式Linux系统执行流程
BootLoader(引导加载程序)是在操作系统内核运行之前运行。在嵌入式系统中,通常并没有像BIOS那样的固件程序,因此整个系统的加载启动任务就完全由BootLoader来完成,它主要用来初始化处理器及外设,然后调用Linux内核。Linux内核在完成系统的初始化之后需要挂载根文件系统,然后加载必要的内核模块,启动应用程序。这就是嵌入式Linux系统启动过程Linux引导的整个过程。
根文件系统挂载
总体概括
- 内核挂载一个虚拟的rootfs作为初始文件系统 这一步的作用主要是形成一个根文件系统挂载点./
- 第二步: 挂载文件系统rootfs作为初始文件系统 这里的rootfs和上面有所区别(上面主要是提供挂载点和进程命名空间) 常见rootfs :initramfs:在内核镜像中包含cpio包,在内核启动时被解开,释放到rootfs ,cpio-initrd: cpio格式的rootfs; image-initrd: 传统格式的rootfs
- 第三步: 挂载一个真正的根文件系统替换rootfs;当然这一步不一定存在。 上面的rootfs也可以直接作为最终的文件系统
接下来详细分析上述过程。
- 准备一个虚拟的文件系统rootfs,并把它初始为根文件系统。其目的是形成一个根文件系统挂载点。
函数调用顺序
start_kernel()->vfs_caches_init() ->mnt_init()
mnt_init()挂载了一个空的rootfs文件系统,并把它的根目录作为内核当前进程的根目录,从而使得这个rootfs的根目录就是./。注:此时是虚拟的rootfs,后面还会指向具体的根文件系统。
mnt_init()源代码如下:
void __init mnt_init(void)
{
...........
init_rootfs(); //向内核注册rootfs
init_mount_tree();//rootfs文件系统的挂载;设置系统current根目录和根文件系统为rootfs, 也就是./挂载点的形成
}
2.initrd
intrid 的常见两种格式处理流程
- InitRamfs(cpio-initrd),使用根文件系统下的/init来作为init进程
- InitRamdisk(image-initrd),使用根文件系统下的/linuxrc来作为init进程
populate_rootfs函数负责加载initramfs(cpio-initrd) 到根文件系统rootfs,若不是将其释放到/initrd.image.。注:rootfs_initcall(populate_rootfs)
尝试访问ramdisk_execute_command,默认为/init,如果访问失败,说明根目录上不存在这个文件,则调用prepare_namespace() 。对于initramdisk(image-initrd)和cpio-initrd的情况,都会将虚拟根文件系统释放到根目录。
- 如果这些虚拟文件系统里有/init这个文件。就会转入到init_post()。
- 对于image-initrd或者是虚拟文件系统中没有包含 /init的情况,会由prepare_namespace()处理。
prepare_namespace()解释。用户可以用root=来指定根文件系统,它的值保存在saved_root_name中。
- 如果用户指定了以mtd(内存技术设备)开始的字串做为它的根文件系统。就会直接去挂载。这个文件是mtdblock的设备文件。
- 如果指定的根文件系统是 initrd其本身,直接挂载为根文件系统
- 如果不是进一步处理:调用initrd_load()
initrd_load() 函数解释
- 建立一个(ROOT_RAM)的设备节点,并将/initrd/.image释放到这个节点中,/initrd.image的内容,就是我们之前分析的image-initrd。
- 如果根文件设备号不是ROOT_RAM0( 用户指定的根文件系统不是/dev/ram0就会转入到handle_initrd()
- 如果当前根文件系统是/dev/ram0. 直接退出。
handle_initrd()先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后,再挂载具体的根文件系统.。