linux文件系统实现浅析

简介:

之前有两篇文章整理过linux虚拟文件系统的结构,和linux文件读写的流程。其中一些由具体文件系统类型来实现的地方并没有深入叙述,只是说这是由具体的文件系统来实现的。比如,读写文件的时候,文件的读写位置怎么对应到实际的磁盘块呢?这是由具体的文件系统来实现的;再比如,寻找一个文件路径的时候,怎么知道XXX目录下是否有YYY文件存在呢?这也是由具体的文件系统来实现的。
前些天同事问起linux下inode的含义,我也就此整理一下自己的思路,看看具体的文件系统大致需要实现什么样的功能,并且可以怎样去实现。

inode
先从inode说起。文件系统中的文件形成了一个树型结构,其中的每一个结点就是一个文件(目录也是文件),对应一个inode。inode的具体结构因文件系统类型的不同而异,但是大体上应该包含如下信息:文件所有者(包括uid、gid)、权限位、文件大小、时间(创建时间、修改时间等)、文件内容。其中最值得一说的是文件内容。
文件有目录和普通文件之分,这两者的内容有着不同的含义,其内容的组织也可能有着不同的结构。

对于普通文件来说,其内容就是用户能够看到的文件内容。当用户程序通过系统调用读写文件时,需要通过某种索引结构来知道文件中某个offset的数据应该在哪个磁盘块上,然后转换成对该块的读写请求。当文件的内容很小时,文件内容的索引信息可以完全存放在inode结点中;如果文件很大,索引也会很大,inode结点可能装不下,就需要分配新的块来存放这些索引信息。而文件的内容则多半是放在inode结点之外的,依靠inode里面的索引信息来找到它们。
比如ext2文件系统中,文件内容的索引结构如下(摘自《ULK3》):
3946560648477210811.jpg
文件内容小于12个块的部分,其块号直接存放在inode中的i_block结构中;从第13块开始,使用一级间接索引,之后随偏移的增大又扩展到二级、三级间接索引。

对于目录,其内容一般是结构化的信息,描述了该目录下的文件的情况(主要包括每个文件的名字、inode号、等)。这是需要由具体的文件系统来解释的,用户看到这些原始内容是没有意义的。只有由具体文件系统将其解释为文件列表后,对用户才有意义。当用户程序寻找一个文件路径时,通过当前目录的inode,就能遍历到目录中的每一个结点(文件名+inode号)。匹配了下一级文件的名字以后,就能得到其对应的inode号,从而找到下一级文件的inode。这些下一级文件的信息也是因为其信息大小的不同,而直接存放在inode结点中,或另外的块中。
比如ext2文件系统中,目录信息结构如下(摘自《ULK3》):
4568620347007748542.jpg
对于每一个下一级文件,记录了它的inode号、文件名、以及文件类型。

符号链接是一种特殊的文件。作为对另一个文件的代指,符号链接文件的内容就是它所代指的文件的路径。这个文件路径信息保存在inode或被inode引用的块中。具体的文件系统类型会实现其特定的读符号链接的方法。用户也可以通过readlink系统调用读到符号链接指向的文件路径。
在打开一个符号链接时,它代指的文件路径(也就是符号链接文件的内容)一般并不被用户程序所关心。内核会对此做一层包装,让用户程序自动访问到它所代指的文件的路径上去。

说了符号链接,也顺便提一下硬链接。硬链接并不会生成新的inode,而是同一个inode被包含在多个目录结点中,从而存在多个文件路径可以找到该文件。

super_block
前面描述了通过一个目录结点找到下一级文件的问题,那么文件系统中的第一个目录结点(也就是根目录)从哪里来呢?
每一个文件系统的实例中都有一个super_block(超级块),这就是该文件系统实例的源头。super_block里面主要有如下信息:根目录inode结点的结点号、inode号与块的对应信息、块的分配信息(总共有多少块、哪些已使用、等等)。
利用inode号与块的对应信息,就能知道一个结点号所对应的inode保存在什么地方。(这种对应信息也可以是某种约定,比如号码为N的inode,存放在M*N块上。)
通过super_block中的根目录inode号,在文件系统被挂载时就能得到其根目录结点。(根目录inode号也可以是具体文件系统约定的,比如约定1号inode就是根目录。)
此外,一个文件被创建之后,其大小是随时可能改变的。利用super_block中记录的块的分配信息,就能在文件增大时为其分配新的块、在文件减小只回收已经不需要使用的块。(这些信息并不是直接存放在super_block中,但是可以通过super_block找到它们,或者作为某种约定。比如约定super_block之后的块是某种结构化信息,块的分配信息就保存于其中。)

那么,这个super_block又从哪里来呢?这一般就只能是约定的了(比如约定第0个块就是super_block)。
我们知道,在使用一个磁盘之前,需要将它格式化一下,格式化成某种具体文件系统所支持的格式。这就包括在磁盘上生成super_block、根目录inode、以及一些必要的文件。并且按照该文件系统的约定,正确摆放它们的位置。

最后,以上提到的块号,实际上都是虚拟的块号。当一块磁盘被划分成若干分区时,每个分区都被当作一个设备,都拥有各自独立的块号。所以,如果super_block固定存放在0号块上,那么同一磁盘的分区0和分区1都有自己的0号块(它们分别对应到实际磁盘的两个不同的块上),从而都有自己的super_block。

块的缓存
在《linux文件读写浅析》中提到,存在一个磁盘高速缓存层,把文件的内容缓存在内存中。那么,文件内容以外的信息(比如inode)存在类似的缓存吗?

在linux上,设备也被当作是文件。读一个磁盘设备文件,能够读出磁盘上的原始数据。这些原始数据是什么呢?里面有super_block、inode、文件内容、还有一些脏数据(它们一般被文件系统理解为空闲空间)。同样,磁盘设备文件也像普通文件一样,拥有与之对应的磁盘高速缓存。当内核需要读磁盘上的某某块时(比如想读出存储在某块上的inode),实际上也是先在这个磁盘高速缓存上去寻找对应的内容,如果找不到再发起磁盘请求,并在读取到数据后更新磁盘高速缓存。
然而,类似inode的块读写与文件内容的读写还是不大一样。文件内容是连续的,具体文件系统在将文件内容存储在磁盘上时,也会尽量分配连续的块。这样,一次磁盘DMA,就可以读取若干个块,有益于效率。但像inode这样的东西却是孤立的,如果N号块是一个inode,N+1号块则很可能与之毫不相干。对一个inode的读写基本上是针对一个块的,不需要拥有像文件内容缓存那样的预读特性。
这两种缓存有着不同的名字,文件内容的缓存叫cache,inode之类的块缓存叫buffer(在linux下查看内存使用情况时,一般会分别看到buffer和cache的大小)。

在磁盘高速缓存中,缓存的单位是页(因为缓存是内存)。而一个内存页的大小往往是块大小的若干倍(常见值是:page为4K、block为1K),所以需要在磁盘高速缓存的内存页上再做一些细分,才能精确到块。在作为磁盘高速缓存页面的page结构上,附加buffer_head信息,如图(摘自《ULK3》):
5783466347273921753.jpg
然后,在向通用块层发起磁盘读写请求时(参见《linux文件读写浅析》),bio的构造将是基于buffer_head的(而对于文件内容的读写,bio基于page来构造)。


目录
相关文章
|
2天前
|
存储 缓存 算法
【linux】认识“文件”的本质,理解“文件系统”的设计逻辑,体会linux优雅的设计理念
【linux】认识“文件”的本质,理解“文件系统”的设计逻辑,体会linux优雅的设计理念
|
29天前
|
存储 Linux 数据处理
探索Linux操作系统的内核与文件系统
本文深入探讨了Linux操作系统的核心组件,包括其独特的内核结构和灵活的文件系统。文章首先概述了Linux内核的主要功能和架构,接着详细分析了文件系统的工作原理以及它如何支持数据存储和检索。通过比较不同的文件系统类型,本文旨在为读者提供一个关于如何根据特定需求选择合适文件系统的参考框架。
|
1天前
|
存储 缓存 固态存储
Linux操作系统之文件系统详解
Linux操作系统之文件系统详解
|
6天前
|
存储 Unix 数据管理
深入探讨Linux文件系统:从传统到现代
深入探讨Linux文件系统:从传统到现代
8 0
|
2月前
|
Linux Windows 存储
|
2月前
|
运维 安全 Linux
深入理解 Linux 文件系统的权限管理
【5月更文挑战第30天】 在 Linux 操作系统中,文件系统权限管理是维护系统安全与数据完整性的基石。本文旨在深入探讨 Linux 权限模型的核心概念、实现机制及其对系统安全性的影响。通过对用户身份、文件权限和访问控制列表(ACL)等关键元素的剖析,揭示权限管理在实际操作中的应用细节。文章还将讨论如何有效配置权限来优化系统性能和提升安全性,以及解决常见的权限问题的策略。
|
2月前
|
Linux PHP 数据安全/隐私保护
深入理解PHP7的返回值类型声明深入理解 Linux 文件系统的权限管理
【5月更文挑战第30天】在PHP7中,引入了返回值类型声明的特性。这一特性使得开发者可以在函数定义时指定函数应返回的值的类型。本文将详细解析返回值类型声明的用法,以及它在实际开发中的应用,帮助读者更好地理解和使用这一特性。
|
14天前
|
存储 JSON Linux
探索Linux文件系统的奥秘:`lsblk`命令详解
`lsblk`是Linux下用于列出块设备详情的命令,显示设备名、大小、类型、挂载点等信息,尤其适合查看磁盘分区和挂载状态。它以树形结构展示设备间的依赖,且支持多种输出格式。常用参数如`-a`显示所有设备,`-f`显示文件系统信息,`-o`定制输出列。结合其他命令使用能有效管理文件系统。注意权限和输出格式选择。
|
2月前
|
安全 Linux 数据安全/隐私保护
深入理解Linux文件系统的权限管理
【5月更文挑战第24天】 在Linux操作系统中,文件系统权限管理是维护系统安全和用户数据隔离的关键机制。本文将深入探讨Linux文件系统中的权限模型,包括用户、组和其他类别的读、写、执行权限。我们将分析权限位的具体含义,如何通过命令行工具修改权限,以及权限掩码(umask)的作用。此外,我们还将讨论文件系统权限在实际应用中的常见问题及其解决方案,帮助读者构建更为安全且高效的Linux工作环境。
|
2月前
|
存储 Linux vr&ar
Linux文件系统
Linux文件系统
40 4