linux文件系统初始化过程(5)---加载initrd(下)

简介: 一、目的     linux把文件分为常规文件、目录文件、软链接文件、硬链接文件、特殊文件(设备文件、管道文件、socket文件等)几种类型,分别对应不同的新建函数sys_open()、sys_mkdir()、sys_symlink()、sys_link()、sys_mknod()。

一、目的

    linux把文件分为常规文件、目录文件、软链接文件、硬链接文件、特殊文件(设备文件、管道文件、socket文件等)几种类型,分别对应不同的新建函数sys_open()sys_mkdir()sys_symlink()sys_link()sys_mknod()

    系统初始化阶段成功加载initrd后,调用这些接口函数创建各种文件,因此这些函数在linux文件系统初始化过程中起到了重要作用,本文将详细描述这些接口函数的实现过程。

    这些接口函数主要在fs/namei.cfs/open.c文件中实现,可以在这两个文件中找到对应的源代码。

 

二、快速路径查找

 

    在以上系统调用的实现中,需要解决一个关键问题:如何根据待新建文件的路径名,快速找到父目录的位置。得到父目录的位置后,才能创建待新建文件的目录,以及分配inode节点。

    例如:新建/tmp/test.txt文件,首先需要根据”/tmp/test.txt”路径名查找到test.txt父目录tmpVFS中的位置,然后基于tmp的位置才能为test.txt文件新建目录及分配inode节点。

 

    由于快速路径查找使用比较频繁,所以对查找效率要求较高,否则会影响系统性能。do_path_lookup(intdfs, const char *name, unsigned int flags, struct nameidata*nd)函数负责实现该功能,其中name参数是路径名,nd参数是structnameidata结构体,ndpath成员记录了父目录的位置,last成员记录了待新建文件的文件名。例如:path记录了tmpVFS中的位置,last记录”test.txt”文件名。

    该函数的实现比较复杂,不方便对照源代码讲述,因此下面重点描述了该函数的主要操作。但是为了读者方便阅读源代码,给出如下关键函数的调用关系:do_path_lookup()->path_lookupat()->path_init()->link_path_walk()->walk_component()->lookup_fast()->__d_look_rcu()->__follow_mount_rcu()

 

    do_path_lookup()在实现过程中,按照以下三种情形来操作:

    1、路径名在单文件系统中:从根目录或当前目录开始,根据目录拓扑结构,递归查找父目录;

    2、路径名在多文件系统中:在递归查找时,需要从当前文件系统的挂载点切换到最终文件系统的目录拓扑结构中,然后继续查找;

    3、路径名在挂载点重复挂载多文件系统的情况:在递归查找时,需要从当前文件系统的挂载点切换到最终文件系统的目录拓扑结构中,然后继续查找;

    为了理解以上三种情形的具体差异,举例说明:待新建文件路径名为”/usr/tmp/log/new.txt”。

 

情形1

    如下图所示,路径名只在单个文件系统ext3中存在,所以根据目录拓扑结构,递归查找父目录即可;查找完成后,使用nd.path记录父目录log的位置,nd.last记录了字符串常量”new.txt”


 

 

情形2

    在情形2中,路径名横跨了两个文件系统,minix挂载在ext3tmp目录上;当成功挂载minix后,设置挂载点tmp为已挂载状态,并且将tmp指向minix文件系统。

    路径查找程序根据路径名”/usr/tmp/log/new.txt”查找到tmp目录时,发现tmp为已挂载状态,所以从挂载点tmp切换到minix根目录;然后,确认minix根目录不是已挂载状态后,在minix文件系统中继续查找剩下的路径名”log/new.txt”;查找完成后,使用nd记录查找结果。


 

 

情形3

    在情形3中,ext3tmp目录重复挂载了两个文件系统minixnfs;当成功挂载minix后,设置挂载点tmp为已挂载状态;当在同一挂载点tmp挂载nfs时,发现tmp已经是挂载状态,所以从挂载点tmp切换到minix根目录,在该根目录挂载nfs文件系统,并且将minix根目录设置为已挂载状态。linux支持在同一挂载点挂载多个文件系统的操作,但是只有最后被挂载的文件系统才是可见的,所以使用ls命令只能看到nfs文件系统的内容。

    路径查找程序根据路径名”/usr/tmp/log/new.txt”查找到tmp目录时,发现tmp为已挂载状态,所以从挂载点tmp切换到minix根目录;然后发现minix根目录也是已挂载状态,所以继续切换到nfs根目录;最后,确认nfs根目录不是已挂载状态后,在nfs文件系统中继续查找剩下的路径名”log/new.txt”;查找完成后,使用nd记录查找结果。


 

    在以上操作中,由__follow_mount_rcu()函数负责目录挂载状态检测和切换操作。

 

 

三、新建文件系统调用

 

    do_path_lookup()函数返回的structnameidata *nd数据结构,记录了待新建文件父目录的位置,所以根据nd记录的信息,在VFS树中新建文件就变得相对简单了。

    由于文件系统的操作比较复杂,因此不对源代码进行详解,主要介绍系统调用的主要功能(图中绿色部分),但是给出了关键函数调用路径,便于读者查阅细节内容。

 

3.1、新建常规文件系统调用sys_open()

    注:这里重点介绍sys_open()的新建功能,忽略打开功能(打开功能比较复杂也与主题不符),所以读者不能片面认为sys_open()的功能只是新建文件。

 

    关键函数调用路径如下:

 

    主要功能总结:

    1get_unused_fd_flags()新建文件描述符;

    2do_filp_open()创建常规文件的file结构体、目录项、inode节点,并将三者关联起来;

       2.1get_empty_filp()创建常规文件的file结构体;

       2.2lookup_open()调用lookup_dcache()创建常规文件的目录项目;

       2.3lookup_open()调用vfs_create()创建常规文件的inode节点;

    3fd_install()将文件描述符指向file结构体。

    具体操作流程如下图所示:

 

 

3.2、新建硬链接文件系统调用sys_link()

    关键函数调用路径如下:

 

    主要功能总结:

1user_path_at()返回硬链接目标文件的目录项位置;

2user_path_create()创建硬链接文件的目录项;

2.1do_path_lookup()返回硬链接文件的父目录位置

2.2lookup_hash()根据父目录位置,创建硬链接文件的目录项;

3vfs_link()将硬链接文件指向硬链接目标文件的inode节点。

    具体操作流程如下图所示:

 

 

3.3、新建目录文件系统调用sys_mkdir()

    关键函数调用路径如下:

 

    主要功能总结:

    1user_path_create()创建目录文件的目录项

       1.1do_path_lookup()返回目录文件的父目录位置;

       1.2lookup_hash()根据父目录位置,创建目录文件的目录项;

    2vfs_mkdir()创建目录文件的inode节点;

    具体操作流程如下图所示:

 

 

3.4、新建软链接文件系统调用sys_symlink()

    关键函数调用路径:

 

    主要功能总结:

    1user_path_create()创建软链接文件的父目录位置;

       1.1do_path_lookup()返回软链接文件的父目录位置;

       1.2lookup_hash()根据父目录位置,创建软链接文件的目录项;

    2vfs_symlink()创建软链接文件的inode节点,并且inode节点记录了软链接目标文件的位置;简单来说,软链接文件的内容就是软链接目标文件的路径。

    具体操作流程如下图所示:

 

 

3.5、新建特殊文件系统调用sys_mknod()

    关键函数调用路径:

 

    主要功能总结:

    1user_path_create()创建特殊文件的父目录位置;

       1.1do_path_lookup()返回特殊文件的父目录位置;

       1.2lookup_hash()根据父目录位置,创建特殊文件的目录项;

    2vfs_mknod()创建特殊文件的inode节点,初始化inodei_rdev成员,并且将i_fop成员指向默认文件操作;

    注:当用户使用sys_open()打开特殊文件时,会调用默认文件操作的open成员,把设备文件挂接到inode的设备链表中,并且将i_fop成员重新指向该设备的文件操作(即设备驱动)。

    具体操作流程如下图所示:

 

    通过以上介绍,可以看出快速路径查找函数do_path_lookup()在新建文件系统调用中起到了基础性的作用,因此有必要掌握该函数的用法。

 

四、VFS全景图

 

    到目前为止,initrd的加载过程就全部结束了;最后,为了更清晰的理解VFS此时的全貌,给出如下VFS全景图。

    从图中看出以下特点:

    1sysfs文件系统目前还没有挂载到rootfs的某个挂载点上,后续init程序会把sysfs挂载到rootfssys挂载点上;

    2、系统打开了/dev/console设备,说明系统已经可以使用该设备,打印信息也可以正常输出;

    3rootfs文件系统的根目录下已经准备好了init程序,内核后续会启动该程序完成剩下的初始化操作。


 

 

五、总结

    目前为止,linux成功加载了initrd文件后,在内核中构建了一个基于内存的文件系统rootfsVFS再也不是只有根目录、结构简单的小树苗了;现在,它已经成长为拥有目录、常规文件、链接文件、设备文件等多种文件类型、结构复杂的参天大树了。

相关文章
|
8天前
|
存储 缓存 数据管理
深入理解 Linux 文件系统的层次结构
【4月更文挑战第30天】 本文旨在探讨和解析 Linux 操作系统中文件系统的结构与原理。不同于通常的摘要,我们将直接深入到文件系统的核心概念,包括其目录结构、关键组件以及它们如何相互作用以支持 Linux 操作系统的功能。通过剖析文件系统的层次性设计,我们能够更好地理解其在数据管理、用户权限控制和系统安全性方面的重要性。
|
1天前
|
存储 Linux 编译器
【探索Linux】P.13(文件系统 | 软硬链接 | 动态库和静态库)
【探索Linux】P.13(文件系统 | 软硬链接 | 动态库和静态库)
5 0
|
2天前
|
存储 Linux Shell
Linux文件系统
Linux文件系统
11 2
|
3天前
|
安全 Linux 数据安全/隐私保护
深入理解 Linux 文件系统的权限控制
【5月更文挑战第5天】本文旨在详细解析 Linux 操作系统中文件系统权限的核心机制。通过分析用户、组和其他人在文件及目录上拥有的读、写、执行权限,我们探讨了如何实现对系统资源的精确控制。文章还将介绍如何使用命令行工具来修改和管理这些权限,以及权限如何在安全策略和系统管理中扮演关键角色。
|
9天前
|
Unix Linux
Linux 常用命令汇总(六):磁盘与文件系统命令
Linux 常用命令汇总(六):磁盘与文件系统命令
|
9天前
|
存储 Linux
深入探索Linux文件系统:属性、路径与隐藏之谜
深入探索Linux文件系统:属性、路径与隐藏之谜
23 1
|
14天前
|
存储 缓存 监控
Linux 文件系统目录结构详解
本文介绍了Linux文件系统的目录结构,包括`/bin`、`/boot`、`/dev`、`/etc`、`/home`、`/lib`、`/media`、`/mnt`、`/opt`、`/proc`、`/root`、`/sbin`、`/tmp`、`/usr`和`/var`等目录的用途和重要性。每个目录都有其特定的功能,例如`/bin`存放基本用户命令,`/boot`存储启动相关文件,`/home`是用户主目录,`/lib`包含共享库,`/proc`提供进程信息,`/usr`存储用户程序资源,而`/var`则用于可变数据如日志文件。理解这些目录的用途有助于更好地管理和使用Linux系统。
Linux 文件系统目录结构详解
|
15天前
|
存储 缓存 Linux
【linux基础I/O(二)】文件系统讲解以及文件缓冲区的概念
【linux基础I/O(二)】文件系统讲解以及文件缓冲区的概念
|
16天前
|
Ubuntu Linux 芯片
Linux(2)ubuntu rootfs根文件系统制作
Linux(2)ubuntu rootfs根文件系统制作
24 0
|
16天前
|
安全 Unix Linux
深入理解 Linux 文件系统的权限管理
【4月更文挑战第22天】 在多用户操作系统如Linux中,文件系统权限管理是维护系统安全与数据完整性的基石。本文将深入探讨Linux下基于POSIX标准的权限模型,包括用户(User)、组(Group)和其他(Others)三个层级的读(Read)、写(Write)和执行(Execute)权限。文章旨在为读者提供一套全面的权限管理策略,涵盖基础命令操作、权限掩码设置以及特殊权限位的概念和应用,以帮助系统管理员或开发人员在日常工作中实现对文件系统访问控制的精细管理。