LV05-03-kernel-06-VFS-02-VFS的四大对象
本文主要是kernel——虚拟文件系统四大对象的相关笔记。若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
PC端开发环境 | Windows | Windows11 |
Ubuntu | Ubuntu20.04.2的64位版本 | |
VMware® Workstation 17 Pro | 17.6.0 build-24238078 | |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) | |
Win32DiskImager | Win32DiskImager v1.0 | |
Linux开发板环境 | Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04 | |
linux内核 | linux-4.19.71(NXP官方提供) |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
nxp-imx/linux-imx/releases/tag/v4.19.71 | NXP linux内核仓库tags中的v4.19.71 | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 | NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0 | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
Source Code | https://elixir.bootlin.com/linux/latest/source | linux kernel源码 |
https://elixir.bootlin.com/u-boot/latest/source | uboot源码 |
前面已经大概了解过VFS虚拟文件系统了,这里主要是深入了解一下虚拟文件系统的四大对象、
一、MINIX文件系统
这部分是在参考linux-0.12/docs/第12章-文件系统/第12章-文件系统.md at master · sumumm/linux-0.12 · GitHub,它是以minix文件系统来讲述的。先来简单了解一下这个文件系统。
如图所示,整个磁盘设备被分为以1kb为单位的磁盘块,上图中的每一方格表示一磁盘块(i节点块数可变)。
1 | MINIX1.0=inode结点+inode结点位图+磁盘块+磁盘块位图+超级块+引导块 |
- 引导扇区(boot sector)安装于硬盘的第一个扇区。引导块(boot block)包含一个非常小的引导记录和一个分区表。引导扇区本身512B,但是为了块对齐占用一块磁盘块也就是1KB。
- 每一个分区中的第一个块是超级块(superblock),它包含了定义其他文件系统结构的元数据,并将它们定位在分配给分区的物理磁盘上。占用一个磁盘块,每个超级块占用14字节。
- 节点位图块(inode bitmap block),它确定了哪个节点在使用以及哪个节点是空闲的。
- 节点(inodes),它们在磁盘上有它们自己的空间。每个节点包含了一个文件的信息,包括数据块的位置,即文件所属的区域。一个磁盘块可以表示1024*8=8192个i节点的使用情况。每个位代表一个磁盘块是否被占用。
- 区域位图(zone bitmap)跟踪记录数据区域的使用和释放。
- 数据区域(data zone),数据实际上存储的位置。
- 对于位图的两个类型来说,一个bit代表了一个特有的数据区域或者一个特有的节点。如果这个bit是0,这个区域或者节点是空闲的而且可供使用,但是如果这个bit是1,这个数据区域或者节点是在使用中的。
- 节点是什么?它是索引节点(index-node)的缩写,一个节点是在磁盘上的一个256字节的块,而且它存储文件相关的数据。这些数据包括文件的大小;文件的用户和所属组的用户ID;文件模式(即访问权限);以及三个时间戳具体说明了时间,包括:文件最后访问时间,最后修改时间,以及节点中的数据最后修改时间。节点也包含了:指向硬盘上文件数据所在的位置。在Minix和EXT1-3文件系统中,它是一个数据区域和块的列表。Minix文件系统节点支持9个数据块,7个直接指针和2个间接指针。
二、Linux虚拟文件系统的四大对象
1. 回顾一下
Linux为了对超级块,i节点,逻辑块这三部分进行高效的管理,Linux创建了几种不同的数据结构,分别是超级块、索引节点inode、目录项dentry等几种。再加上文件对象(file),就构成了VFS的四大对象。
2. 超级块(super block)
一个超级块对应一个文件系统(已经安装的文件系统类型,如ext2,此处是实际的文件系统,不是VFS)。之前我们已经了解了文件系统用于管理文件的数据格式和操作之类的,系统文件有系统文件自己的文件系统,同时对于不同的磁盘分区也有可以是不同的文件系统。那么一个超级块对于一个独立的文件系统。保存文件系统的类型、大小、状态等等。
Tips:
“文件系统”和“文件系统类型”不一样!一个文件系统类型下可以包括很多文件系统,即很多的super_block。
超级块反映了文件系统整体的控制信息。例如:硬盘分区中每个block的大小、硬盘分区上一共有多少个block group、以及每个block group中有多少个inode。
超级块能够以多种的方式存在,对于基于磁盘的文件系统,它以特定的格式存在于磁盘的固定区域(取决于文件系统类型)上。在挂载文件系统时,该超级块中的内容被读入磁盘中,从而构建出位于内存中的新的超级块。
3. 索引节点inode
索引节点inode则反映了文件系统对象中的一般元数据信息。
文件一般是由 inode 以及 inode指向的数据块构成,Inode记录了文件的管理信息,数据块记录文件的具体内容。
目录也是由 inode 以及inode指向的数据块构成 ,但目录的数据块 记录的是该目录下的 子目录/文件的 inode 以及 子目录名/文件名 等信息。
4. 目录项dentry
目录项dentry则是反映出某个文件系统对象在全局文件系统树中的位置。dentry中包含了文件名,文件的inode号等信息。
它只存在于内存中,更确切的说是存在于内存的目录项缓存,为了提高查找性能而设计。注意不管是文件夹还是最终的文件,都是属于目录项,所有的目录项在一起构成一颗庞大的目录树。例如:open一个文件 /home/xxx/yyy.txt ,那么 /、home、xxx、yyy.txt 都是一个目录项,VFS在查找的时候,根据一层一层的目录项找到对应的每个目录项的inode,那么沿着目录项进行操作就可以找到最终的文件。
dentry结构是一种含有指向父节点和子节点指针的双向结构,多个这样的双向结构构成一个内存里面的树状结构,也就是文件系统的目录结构在内存中的缓存了。有了这个缓存,我们在访问文件系统时,通常都非常快捷。
Tips
**目录也是一种文件(所以也存在对应的inode)**。打开目录,实际上就是打开目录文件。
举个文件的例子:/home/user/Desktop/a.txt ,假设 a.txt和 / 在同一个文件系统,那么,只需要读 / inode读到 home并找到找到home 的inode 并读取,这样步步跳转,最后会读取a.txt这文件对应的 inode,好了,我们打开 a.txt 这个文件并读取内容 时,VFS会调用 ext3 的 read() 去 读此inode对应的数据块。
5. 文件对象file
注意文件对象描述的是进程已经打开的文件。因为一个文件可以被多个进程打开,所以一个文件可以存在多个文件对象。但是由于文件是唯一的,那么inode就是唯一的,目录项也是定的!
进程其实是通过文件描述符来操作文件的,注意每个文件都有一个32位的数字来表示下一个读写的字节位置,这个数字叫做文件位置。一般情况下打开文件后,打开位置都是从0开始,除非一些特殊情况。Linux用file结构体来保存打开的文件的位置,所以file称为打开的文件描述。file结构形成一个双链表,称为系统打开文件表。
file只是对一个文件而言,对于一个进程(用户)来说,可以同时处理多个文件,所以需要另一个结构来管理所有的files
上面的file和files_struct记录的是与进程相关的文件的信息,但是对于进程本身来说,自身的一些信息用什么表示,这里就涉及到fs_struct结构体。
三、进程与这四大对象的关系
内核中用于管理进程的结构体是task_struct。进程打开文件就涉及到上述4个重要的数据结构:
Tips:f_dentry is gone; use f_path.dentry。
在这里有说明porting « filesystems « Documentation - kernel/git/stable/linux.git - Linux kernel stable tree
每个进程都有自己的namespace。fs_struct用于表示进程与文件系统之间的结构关系,比如当前的工作目录,进程的根目录等等。files_struct 用于表示当前进程打开的文件。而对于每一个打开的文件,由file对象来表示。
Linux中,常常用文件描述符(file descriptor)来表示一个打开的文件,这个描述符的值往往是一个大于或等于0的整数。而这个整数,其实就是在files_struct中file数组fd_array的下标。对于所有打开的文件, 这些文件描述符会存储在open_fds的位图中。
从图中可以看出:
(1)进程通过task_struct中的一个域files→files_struct 来了解它当前所打开的文件对象;而我们通常所说的文件描述符其实是进程打开的文件对象数组的索引值。
(2)文件对象通过域f_path.dentry找到它对应的dentry对象,再由dentry对象的域d_inode找到它对应的索引节点(通过索引节点又可以得到超级块的信息,也就可以得到最终操作文件的方法,在open文件的时候就是使用这样一个过程),这样就建立了文件对象与实际的物理文件的关联。
(3)文件对象所对应的文件操作函数列表是通过索引节点的域i_fop得到的,而i_fop最终又是通过struct super_operations *s_op来初始化的。
VFS文件系统中的inode和dentry与实际文件系统的inode和dentry有一定的关系,但不能等同。
真实磁盘文件的inode和dentry是存在于物理外存上的,但VFS中的inode和dentry是存在于内存中的,系统读取外存中的inode和dentry信息进行一定加工后,生成内存中的inode和dentry。
虚拟的文件系统也具有inode和dentry结构,只是这是系统根据相应的规则生成的,不存在于实际外存中。
参考资料:
【1】Linux 虚拟文件系统四大对象:超级块、inode、dentry、file之间关系 - 一口Linux - 博客园
【2】linux_kernel_wiki/文章/文件系统/虚拟文件系统.md at main · 0voice/linux_kernel_wiki · GitHub
【3】Linux内核完全注释(修正版v5.0)-CSDN博客
【4】【文件】VFS四大struct:file、dentry、inode、super_block 是什么?区别?关系?–编辑中 - bdy - 博客园