扩展小知识
https://blog.csdn.net/gatieme/article/details/51577479
initcall机制分析
https://www.cnblogs.com/downey-blog/p/10486653.html
rootfs的挂载过程
https://www.xuebuyuan.com/725955.html
详细文件系统初始化过程2
https://www.cnblogs.com/wuchanming/p/3769727.html
文件系统学习
https://www.cnblogs.com/zhiliao112/p/4067833.html
文件系统各数据结构之间的关系
https://blog.csdn.net/sunna346867721/article/details/84950355
Linux内核中current指针作为全局变量
kernel4.14/include/asm-generic/current.h
#include <linux/thread_info.h>
#define get_current() (current_thread_info()->task)
#define current get_current()
kernel4.14/arch/arc/include/asm/thread_info.h
static inline __attribute_const__ struct thread_info *current_thread_info(void)
{
register unsigned long sp asm("sp");
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}
struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => BUG */
struct task_struct *task; /* main task structure */
mm_segment_t addr_limit; /* thread address space */
__u32 cpu; /* current CPU */
unsigned long thr_ptr; /* TLS ptr */
};
- 在linux内核中进程以及线程(多线程也是通过一组轻量级进程实现的)都是通过task_struct结构体来描述的,我们称它为进程描述符,而thread_info则是一个与进程描述符相关的小数据结构,它同进程的内核态栈stack存放在一个单独为进程分配的内存区域,由于这个内存区域同时保存了thread_info和stack,所以使用了联合体来定义,相关数据结构如下(基于4.4.87版本内核):
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};
Linux内核中current指针作为全局变量
-
current宏是一个全局指针,指向当前进程的struct task_struct结构体,即表示当前进程,在进程上下文中获取当前进程ID、任务调度,以及open等文件系统调用中路径搜索等。
-
current其实一个struct task_struct指针,指向当前进程
struct task_struct *task又是struct thread_info的一个成员变量。
thread_info可以从sp寄存器得到
根文件系统(rootfs)梳理
init启动
initramfs和initramdisk方式异同?
initramf方式加载rootfs宏定义修改含义?
kernel启动参数选择?
9.0为什么没有ramdisk?
-
Linux–根文件系统的挂载过程分析
https://blog.csdn.net/guopeixin/article/details/5962482 -
Linux–根文件系统的挂载过程分析
https://blog.csdn.net/LEON1741/article/details/78159754
rootfs 相关基础概念
VFS/ROOTFS initrd/ramdisk initramfs/rootfs
VFS & ROOTFS
VFS
- 在Linux中,普通文件、目录、字符设备、块设备、套接字等都以文件被对待;他们具体的类型及其操作不同,但需要向上层提供统一的操作接口。
- 虚拟文件系统VFS就是Linux内核中的一个软件层,向上给用户空间程序提供文件系统操作接口;向下允许不同的文件系统共存。所以,所有实际文件系统都必须实现VFS的结构封装
- VFS是一种机制、是Linux下每一种文件系统(包括刚才说的rootfs,还有常见的ext3、yaffs等)都必须按照这个机制去实现的一种规范
ROOTFS
- Linux系统中任何文件系统的挂载必须满足两个条件:挂载点和文件系统,挂载点必须属于某个文件系统。
- ROOTFS之所以存在,是因为需要在VFS机制下给系统提供最原始的挂载点,是一种具体实现的文件系统。
- rootfs仅仅是符合VFS规范的,
- 1.是系统自己创建并加载的第一个文件系统;
- 2.该文件系统的挂载点就是它自己的根目录项对象;
- 3.该文件系统仅仅存在于内存中。
initrd & initramfs
- Initramfs/initrd 是填充(仅仅是释放文件到rootfs根目录)/扩充(通过挂载其他文件系统类型到rootfs指定目录)rootfs的关键,以保证Linux系统的后续启动
initrd/ramdisk
- initrd是传递给内核用于挂载根文件系统的文件,现在它分为两种,一种是image格式zip压缩包,这是最原始的作用,传入的是ramdisk,另一种是cpio格式,传入的是initramfs,内核在解析时会自动解析它的格式,从而按照不同的方式进行处理。
- 系统启动时,bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,执行根目录中的/linuxrc脚本(cpio格式的initrd为/init,而image格式的initrd为/initrc),您就可以在这个脚本中加载realfs(真实文件系统)存放设备的驱动程序以及在/dev目录下建立必要的设备节点。这样,就可以mount真正的根目录,并切换到这个根目录中来。
initrd/initramfs
- initrd是传递给内核用于挂载根文件系统的文件,另一种是cpio格式,传入的是initramfs,内核在解析时会自动解析它的格式,从而按照不同的方式进行处理。
initramfs/rootfs
-
initramfs,和initrd类似,只是和内核编译成一个文件(该initramfs是经过gzip压缩后的cpio格式的数据文件),该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上,其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压,然后使用它作为临时的根文件系统。
-
为什么把他们放在一起呢?因为实际上他们指的是同一个东西,kernel 2.6版本之后引入了rootfs的功能,这个功能就是在kernel代码中实现一个很小的rootfs,这个rootfs中除了一些必须的file list,其他都是空的。系统启动时会直接先加载这个rootfs,既然它是空的,那么怎么填充它呢,initramfs就是填充到rootfs中的内容。如果系统启动时检测到rootfs根目录下填充的有init程序,那么就把系统交给这个init程序接管,由它进行后面的初始化行为。如果检测没有,那么就认为这个rootfs不可用,而按照旧的方式挂载根分区,也就是从cmdline中读取root=xxx这种参数去挂载。initramfs可以是一个cpio格式的压缩文件,也可以是一个目录。可以在defconfig中指定,这样就能直接编译到内核中,也可以通过cmdline传参数。
-
- initrd是启动时加载的,initramfs是编译到内核中的
- initramfs只支持cpio格式,initrd支持cpio格式和传统的image-initrd格式
- initramfs被解析处理后原始的cpio包(压缩或非压缩)所占的空间 (&__initramfs_start - &__initramfs_end)是作为系统的一部分直接保留在系统中,不会被释放掉,而对于initrd镜像文件,如果没有在命令行中设置"keepinitd"命令,那么initrd镜像文件被处理后其原始文件所占的空间 (initrd_end - initrd_start)将被释放掉。
- cpio-initrd的处理和initramfs极其相似,cpio-initrd就是相当于把initramfs处理机制用initrd机制加载。
-
initramfs文件生效的过程大致分为四步:
第一步:Kernel首先要注册一个RAMFS文件系统类型(实际注册的类型名称是"ROOTFS",后续我们可以看到它实际上就是"RAMFS"); 第二步:然后加载(mount)一个空的rootfs文件系统,类型就是上面提到的RAMFS(ROOTFS); 第三步:寻址initramfs文件“XXX.cpio.gz”并解压到已mount的rootfs文件系统中; 第四步:寻址用户空间的init,并执行init进程
init/main.c: start_kernel() -> fs/dcache.c: vfs_caches_init() ->
init_rootfs()”函数中,注册了"ROOTFS"文件系统类型。通过阅读inode.c源码,发现"ROOTFS"就是"RAMFS",几乎没有区别
跟文件系统理解
根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。文件系统和内核是完全独立的两个部分。
根文件系统包含系统启动时所必须的目录和关键性的文件,以及使其他文件系统得以挂载(mount)所必要的文件
一套linux体系,只有内核本身是不能工作的,必须要rootfs(上的etc目录下的配置文件、/bin /sbin等目录下的shell命令,还有/lib目录下的库文件等···)相配合才能工作
- init进程的应用程序必须运行在根文件系统上;
- 根文件系统提供了根目录“/”;
- linux挂载分区时所依赖的信息存放于根文件系统/etc/fstab这个文件中;
- shell命令程序必须运行在根文件系统上,譬如ls、cd等命令
- Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在 Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录和文件。
重要文件路径
bsp/kernel/kernel4.14/usr/Makefile
bsp/kernel/kernel4.14/scripts/gen_initramfs_list.sh
bsp/kernel/kernel4.14/fs/dcache.c
bsp/kernel/kernel4.14/init/initramfs.c
编译生成 initramfs文件至kernel中。
CONFIG_INITRAMFS_SOURCE=“”
CONFIG_INITRAMFS_FORCE=y
通过CONFIG_INITRAMFS_FORCE设定目标源码路径,经过编译最终和内核编译成ZImage,并将地址数据赋值给\ _initramfs_start&end变量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YTer0Qev-1579690876632)(…/…/0_picture/initramfs编译参数1.png)]
编译源码
bsp/kernel/kernel4.14/usr/Makefile
CONFIG_INITRAMFS_SOURCE="/home/guoqi.cui/busybox-1.23.2/_install/"
CONFIG_INITRAMFS_FORCE=y
CONFIG_INITRAMFS_ROOT_UID=0
CONFIG_INITRAMFS_ROOT_GID=0
将制作的rootfs源码目录编译成initramfs下cpio格式的数据文件。
_initramfs_start,_initramfsend,两个全局变量只在init进程中有效.
//bsp/kernel/kernel4.14/scripts/gen_initramfs_list.sh
initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh
ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \
$(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d)
ramfs-args := \
$(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
$(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
- gen_initramfs_list.sh以cpio格式对目标root目录压缩生成XXX.cpio
- initramfs_data.S只做一件事情,创建一个Section,包含XXX.cpio
- INIT_RAM_FS
- 如果在配置时指定的是一个目录而不是一个描述文件,内核编译时将从这个目录生成一个配置/描述文件(usr/Makefile 调用scripts/gen_initramfs_list.sh),并使用该配置文件来对该目录进行打包(该配置文件作为/usr/gen_init_cpio.c的输入,而usr/gen_init_cpio由usr/gen_init_cpio.c 生成)
.init.data : {
166 INIT_DATA
167 INIT_SETUP(16)
168 INIT_CALLS
169 CON_INITCALL
170 SECURITY_INITCALL
171 INIT_RAM_FS
172 *(.init.rodata.* .init.bss)
173 KUNIT_TEST_MODULES
174 }
//bsp/kernel/kernel4.14/include/asm-generic/vmlinux.lds.h
781 #ifdef CONFIG_BLK_DEV_INITRD
782 #define INIT_RAM_FS \
783 . = ALIGN(4); \
784 VMLINUX_SYMBOL(__initramfs_start) = .; \
785 KEEP(*(.init.ramfs)) \
786 . = ALIGN(8); \
787 KEEP(*(.init.ramfs.info))
788 #else
挂载磁盘文件系统
init程序负责挂载磁盘文件系统,并将文件系统的根目录从rootfs切换到磁盘文件系统
在linux初始化阶段的后期会跳转到init程序,由该程序负责加载驱动程序和挂载磁盘文件系统以及其他的初始化工作。
参考理解博文:
https://blog.csdn.net/armmfc/article/details/51320056
/kernel/init/(main.c、do_mount_initrd.c、do_mounts.c)
https://blog.csdn.net/tankai19880619/article/details/12093239
8 系统构建–根文件系统的挂载
https://blog.csdn.net/rikeyone/article/details/88378085
7 Linux内核启动及根文件系统加载过程
https://blog.csdn.net/guofengdidai/article/details/52184429
6 虚拟根文件系统与真实根文件系统
https://blog.csdn.net/armmfc/article/details/51320056
5《Linux启动过程分析》内核挂载根文件系统
https://blog.csdn.net/tankai19880619/article/details/12093239
0 从linux启动到rootfs的挂载分析
https://blog.csdn.net/kevin_hcy/article/details/17663341
1 Linux INITRAMFS 与 INITRD
http://blog.chinaunix.net/uid-26969690-id-3207839.html
https://blog.csdn.net/yuesichiu/article/details/8601244
initramfs加载的完整流程
http://blog.chinaunix.net/uid-26728868-id-4285932.html
2 Initrd 机制解析
https://www.ibm.com/developerworks/cn/linux/l-k26initrd/
3 InitRamdisk & InitRamfs 介绍和使用
https://blog.csdn.net/ooonebook/article/details/52624481
4 ramdisk配置、解压、创建rootfs、启动简单分析
https://blog.csdn.net/ds1130071727/article/details/93076649
5 http://blog.chinaunix.net/uid-26728868-id-4285932.html
https://blog.csdn.net/xiehaihit/article/details/91959216
linux 文件系统常用目录
Linux文件系统中一般有如下几个目录:
-
/bin目录
该目录下存放所有用户都可以使用的、基本的命令,这些命令在挂接其它文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中。
/bin目录下常用的命令有:cat,chgrp,chmod,cp,ls,sh,kill,mount,umount,mkdir,mknod,test等,我们在利用Busybox制作根文件系统时,在生成的bin目录下,可以看到一些可执行的文件,也就是可用的一些命令。 -
/sbin 目录
该目录下存放系统命令,即只有管理员能够使用的命令,系统命令还可以存放在/usr/sbin,/usr/local/sbin目录下,/sbin目录中存放的是基本的系统命令,它们用于启动系统,修复系统等,与/bin目录相似,在挂接其他文件系统之前就可以使用/sbin,所以/sbin目录必须和根文件系统在同一个分区中。
/sbin目录下常用的命令有:shutdown,reboot,fdisk,fsck等,本地用户自己安装的系统命令放在/usr/local/sbin目录下。 -
/dev目录
该目录下存放的是设备文件,设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种设备,即通过读写某个设备文件操作某个具体硬件。比如通过”dev/ttySAC0”文件可以操作串口0,通过”/dev/mtdblock1”可以访问MTD设备的第2个分区。 -
/etc目录
该目录下存放着各种配置文件,对于PC上的Linux系统,/etc目录下的文件和目录非常多,这些目录文件是可选的,它们依赖于系统中所拥有的应用程序,依赖于这些程序是否需要配置文件。在嵌入式系统中,这些内容可以大为精减。 -
/lib目录
该目录下存放共享库和可加载(驱动程序),共享库用于启动系统。运行根文件系统中的可执行程序,比如:/bin /sbin 目录下的程序。 -
/home目录
用户目录,它是可选的,对于每个普通用户,在/home目录下都有一个以用户名命名的子目录,里面存放用户相关的配置文件。 -
/root目录
根用户的目录,与此对应,普通用户的目录是/home下的某个子目录。 -
/usr目录
/usr目录的内容可以存在另一个分区中,在系统启动后再挂接到根文件系统中的/usr目录下。里面存放的是共享、只读的程序和数据,这表明/usr目录下的内容可以在多个主机间共享,这些主要也符合FHS标准的。/usr中的文件应该是只读的,其他主机相关的,可变的文件应该保存在其他目录下,比如/var。/usr目录在嵌入式中可以精减。 -
/var目录
与/usr目录相反,/var目录中存放可变的数据,比如spool目录(mail,news),log文件,临时文件。 -
/proc目录
这是一个空目录,常作为proc文件系统的挂接点,proc文件系统是个虚拟的文件系统,它没有实际的存储设备,里面的目录,文件都是由内核临时生成的,用来表示系统的运行状态,也可以操作其中的文件控制系统。 -
/mnt目录
用于临时挂载某个文件系统的挂接点,通常是空目录,也可以在里面创建一引起空的子目录,比如/mnt/cdram /mnt/hda1 。用来临时挂载光盘、硬盘。 -
/tmp目录
用于存放临时文件,通常是空目录,一些需要生成临时文件的程序用到的/tmp目录下,所以/tmp目录必须存在并可以访问。
initramfs —|
cpio-intrd —|
|
释放vfs带vfs的根目录-----|
直接将MTD设备挂载并且欢vfs根目录文件系统到真实跟文件系统
image-initrd—|
来源:CSDN
作者:Linux渣神
链接:https://blog.csdn.net/u010971180/article/details/104071977