linux内核之文件系统

摘要:
对于通过mount命令连接到Linux系统的每个存储设备,如磁盘、光盘等,每个设备对应的文件系统必须根据VFS的要求提供一组统一的接口。当Linux启动时,用户必须指定一个“根设备”。内核在初始化阶段将“根设备”安装在“根安装点”上,从而拥有一个根文件系统。这样,文件系统就准备好了。

本文主要是基于百度文库的《Linux2.4.30内核文件系统学习(多图).doc》和360doc的《Linux内核虚拟文件系统》修改而来,当然还参考了其他的一些文档,在此就不一一列出了。本来在看到这些文章后,都没有勇气再写点文件系统方面的东西了,这些文章实在太精彩了。最后还是鼓足勇气决定把整理的资料增加了一点自己的理解写下来,主要目的是让各位高手看看我的理解是否正确,另外就是备忘。

1、如何描述一个文件

       我们先看看一个文件在内存和磁盘上是如何描述的。每个文件至少要有一个数据结构存放该文件的信息,包括uidgidflag、文件长度、文件内容存放位置的数据结构等。在Linux中这个数据结构被称为inode,本来inode中也应该包括文件名称等信息,但是由于符号链接的存在,导致一个文件可能存在多个文件名称,因此把和文件名称相关的信息从inode中提出,专门放到dentry 结构中。dentry通过其成员变量d_inode 指向对应的inode数据结构。如下图所示

linux内核之文件系统第1张

1

另外,inode结构中还包括了成员i_fop,其类型是struct file_operations,其中包括的针对该文件的一些操作接口,如上图所示。

2、根据路径名寻找目标文件

       Linux中目录也被作为文件看待,只是目录是一种比较特殊的文件。其特殊之处在于文件的内容是该目录中文件和子目录的dentry的描述符,通过这些dentry的描述符可以找到文件或子目录的dentry,进而找到相应的inode

      

下面我们看看如果根据绝对路径寻找一个文件/tmp/temp/abc的。

1 首先找到根文件系统的根目录文件的 dentry inode

2、由这个 inode 提供的操作接口 i_op->lookup(),找到下一层节点tmp dentry inode

3、由tmp inode 找到temp dentry inode

4、最后由temp inode 找到 ‘abc’ dentry inode

可以看到,整个寻找过程是一个递归的过程。

我们再看看如何通过相对路径寻找文件/tmp/temp/abc,假如我们目前的工作目录为/tmp/temp/dir_a 中,比如我们通过拷贝命令拷贝该文件:cp ../abc ./

如何通过相对路径寻找文件呢?我们来看看dentry这个数据结构的成员,其中有一个是d_parent数据结构定义如下

struct dentry { 删除了无关的成员

       struct dentry *d_parent; /* parent directory */

       struct inode *d_inode;           /* Where the name belongs to - NULL is      * negative */

       unsigned char d_iname[DNAME_INLINE_LEN];       /* small names */

}

d_parent指向了本目录的父目录的dentry,这样就在通过“..”时就是通过该指针找到的父目录dentry,找到父母inode,进而找到父目录下的所有文件的信息。

3、进程中打开的文件

一个文件可以被多次打开,并且多个进程对一个文件的访问权限可能不同,因此打开方式就会不同(只读、读写、可执行)。而dentry inode 只能描述一个物理的文件,无法描述“打开”这个概念。

因此有必要引入 file 结构,来描述一个“被打开的文件”。每打开一个文件,就创建一个 file 结构。

file 结构中包含以下信息:

打开这个文件的进程的 uid,pid

打开的方式

读写的方式

当前在文件中的位置

实际上,打开文件的过程正是建立file, dentry, inode 之间的关联的过程。如下图

linux内核之文件系统第2张

2

 

       在进程中如何和打开的文件相关联呢?我们来看看进程的数据结构

struct task_struct { 只保留了相关信息

       struct files_struct *files; /* open file information */

}

每个进程包括“files”成员,其类型为files_struct。如下图所示

linux内核之文件系统第3张

3

 

进程中所有打开的文件的指针都存在了fd_arrary[]数组中。

 

 

4、虚拟文件系统

Linux 通过虚拟文件系统(VFS)来支持不同的具体的文件系统,那么 VFS 到底是什么?

从程序员的角度看,VFS 就是一套代码框架(framework,它将用户与具体的文件系统隔离开来。每个要通过mount 命令挂接到Linux系统的存储设备,如磁盘、光盘等(它们各自对应具体的文件系统),每个设备对应的文件系统都要按照VFS的要求提供一套统一的接口。这样,用户就可以使用这些统一的接口在不同的文件系统中拷贝数据了。参考下图

linux内核之文件系统第4张

图4

 

安装一个文件系统,除了需要“被安装设备”外,还要指定一个“安装点”。“安装点”是已经存在的一个目录节点。例如把 /dev/sda1 安装到 /mnt/win 下,那么 /mnt/win 就是“安装点”。

可是文件系统要先安装后使用。因此,要使用 /mnt/win 这个“安装点”,必然要求它所在文件系统已也经被安装。

也就是说,安装一个文件系统,需要另外一个文件系统已经被安装。

这是一个鸡生蛋,蛋生鸡的问题:最顶层的文件系统是如何被安装的?

答案是,最顶层文件系统的时候是被安装在“根安装点”上的,而根安装点不属于任何文件系统,它对应的 dentry inode 是由内核在初始化阶段凭空构造出来的。

最顶层的文件系统叫做“根文件系统”。Linux 在启动的时候,要求用户必须指定一个“根设备”,内核在初始化阶段,将“根设备”安装到“根安装点”上,从而有了根文件系统。这样,文件系统才算准备就绪。此后,用户就可以通过 mount 命令来安装新的设备。

5mount 设备(文件系统)

我们通过mount命令向Linux系统mount了一个设备。其实该命令触发了两个过程,一个是文件系统注册过程(当然,如果文件系统已注册过的话,就不需要该步骤了),另一个才是真正意义上的mount设备的过程。

文件系统注册过程

Linux内核是可加载的,许多模块式可选的,只有真正需要使用时才加载他们。文件系统注册过程就是把对应某类型文件系统相关的模块加载到内核,并创建相关的数据结构。每个文件系统模块都有一个初始化例程,它的作用就是VFS中进行注册,即填写一个叫做file_system_type的数据结构。所有已注册的文件系统的file_system_type结构形成一个链表,我们把这个链表称为注册链表。

linux内核之文件系统第5张

图5

每个设备在mount时都要搜索该注册链表,选择适合自己设备文件系统的一项,并从中取出read_super()函数获取设备的超级块(存储在具体设备上,记录存储设备各种信息的一个存储块),并解析其内容。因为每种类型文件系统的超级块的格式不同,并且各自有特定的信息,每种文件系统必须使用对应的解析函数,否则内核就因为不认识该文件系统而无法完成安装。这就是注册文件系统的意义所在。

设备真正mount过程

总体数据结构,参考下图

linux内核之文件系统第6张linux内核之文件系统第5张

图6

1 创建一个设备的 vfsmount

2、为“被安装设备”创建一个 super_block,并由具体的文件系统来设置这个 super_block。在super_block中包含了该类型设备操作的各种接口的结构成员s_op,类型为super_operations

3 为被安装设备的根目录节点创建 dentry

4 为被安装设备的根目录节点创建 inode,并由 super_block->s_op->read_inode() 来设置此 inode

5  super_block 与“被安装设备“根目录节点 dentry 关联起来

6  super_block中的s_root与“被安装设备”的根目录节点 dentry 关联起来

如图6所示,在linux2.4.30中有三条链表,文件系统类型结构file_system_type的链表头为file_systems,超级块结构super_block的链表头为super_blocks,挂接点结构vfsmount的链表头为vfsmntlist。

在Linux3.3.5中只有两条链表结构,文件系统类型结构file_system_type的链表头为file_systems,超级块结构super_block的链表头为super_blocks。数据结构vfsmount 的结构定义还存在,但已经没有了mnt_list成员了。

6、挂接设备中查找文件的过程

下面的流程参考了linux3.3.5中的数据结构。

例如要打开 /mnt/win/dir1/abc 这个文件,就是根据这个路径,找到目标节点 ‘abc’ 对应的 dentry ,进而得到 inode 的过程。

寻找过程大致如下:

1、 首先找到根文件系统的根目录节点 dentry 和 inode

2、 由这个 inode 提供的操作接口 i_op->lookup(),找到下一层节点 ‘mnt’ 的 dentry 和 inode

3、 由 ‘mnt’ 的 inode 找到 ‘win’ 的 dentry 和 inode

4、 由于 ‘win’ 是个“安装点”,因此需要找到“被安装设备”/dev/sda1 根目录节点的 dentry 和 inode。“win”的dentry中有d_sb(超级块成员),d_sb中有“struct dentry       *s_root;”,s_root就是指向“/dev/sda1的dentry

5、 然后由 /dev/sda1 根目录节点的 inode 负责找到下一层节点 ‘dir1’ 的 dentry 和 inode

6、 由于 dir1 是个“安装点”,因此需要借助dir1的dentry->d_sb->s_root找到 /dev/sda2 的根目录节点 dentry 和 inode

7、 最后由这个 inode 负责找到 ‘abc’ 的 dentry 和 inode

可以看到,整个寻找过程是一个递归的过程。

完成寻找后,内存中结构如下,其中红色线条是寻找目标节点的路径

转自http://blog.chinaunix.net/uid-27052262-id-3259907.html

免责声明:文章转载自《linux内核之文件系统》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MySQL导入utf8编码的CSV文件Python中利用os模块创建目录文件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

test命令

test命令:判断文件类型,判断文件权限,判段表达式,判断字符串,判断整数大小/相等,判断两文件新旧,inode号是否一样 判断文件类型 命令 功能 -b 文件 判断是块设备文件 -c 文件 判断是字符设备文件 -d 文件 判断是目录文件 -f 文件 判断是普通文件 -L 文件 判断是符号链接文件 -p 文件 判断是管道文...

Linux普通用户执行提示权限不够,sudo提示找不到命令

问题源于使用哈工大老师操作系统课程的环境时,运行run这个shell文件出现这样的情况: song@ubuntu:~/workspace/oslab$ ./run -bash: ./run: 权限不够 song@ubuntu:~/workspace/oslab$ sudo ./run sudo: ./run:找不到命令 搜索网上有这样的解决过程 1.编辑文...

C中的栈区&堆区

1、栈区(stack segment):由编译器自动分配释放,存 放函数的参数的值,局部变量的值等。在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量 是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示...

Linux编程 | 使用 make

目录 简单的 makefile 文件常规的 makefile 文件常用参数make 内置规则后缀和模式规则make 管理函数库 在Linux 环境中,make 是一个非常重要的编译命令。不管是自己进行项目还是安装应用软件,用户经常会用到 make 或 make install 命令。 make 与 makefile 文件 make 工具,可以将大型的...

redis list结构

一个功能肯定有其应用场景: PUSH和POP操作,其实是队列的基本操作。Redis的list就是一个极其强大的队列系统。我们在哪些地方会用到队列呢?下面,我们说两个例子: a,评论系统 逛过微博的筒子们应该都对评论系统有了解。我们在看完一条微博之后,常常会评论一番,或者看看其他人的吐槽。每条评论的记录都是按照时间顺序排序的。我们读的时候也是这个顺序。这时,...

mac终端常用命令

mac 终端 常用命令 基本命令1、列出文件ls 参数 目录名        例: 看看驱动目录下有什么:ls /System/Library/Extensions参数 -w 显示中文,-l 详细信息, -a 包括隐藏文件2、转换目录      cd    例:想到驱动目录下溜达一圈   cd /System/Library/Extensions 3...