linux虚拟文件系统

一.虚拟文件系统

引入虚拟文件系统的原因

Linux系统中存在很多的文件系统,例如常见的ext2,ext3,ext4,sysfs,rootfs,proc…很多很多。。。我们知道每个文件系统是独立的,有自己的组织方法,操作方法。那么对于用户来说,不可能所有的文件系统都了解,用户怎么能透明使用它们呢?那么这个时候就需要VFS作为中间一层!

对于它们的目录文件结构各不相同,即不同文件系统的不同组织方法,可以在保留原目录文件结构的基础上,再构建一个新的统一的目录文件结构,而这个新目录文件中的信息是通过提取原系统目录文件信息进行重新组织来建立的。这样,用户面对的就不再是五花八门的目录文件,而是一个统一的目录文件。

为了让不同文件系统操作函数实现一个统一的操作界面,VFS利用函数指针,因为函数指针实质上就是对函数的一次抽象,用户直接和VFS打交道。例如read,write,那么映射到VFS中就是sys_read,sys_write,那么VFS可以根据你操作的是哪个“实际文件系统”(哪个分区)来进行不同的实际的操作!其实就是VFS中提供一个抽象的数据结构,然后对于每一个具体的文件系统要把自己的字段和函数填充进去。

从上述内容可知,虚拟文件系统既没有文件,也不直接管理文件,它只是用户与实际文件系统之间的接口。因此,它并不需要保存在永久存储介质中,只是在需要时由内核在内存中创建起来的一个文件系统,所以叫做虚拟文件系统。

组成

Linux虚拟文件系统由超级块对象,索引节点对象,目录项对象,文件对象组成。他们之间的关系如下

关系

超级块对象

一个超级块对于一个独立的文件系统。保存文件系统的类型、大小、状态等等。这个超级块实质上也就是系统把实际文件系统超级块的相关信息提取出来(如Ext2的ext2_sb_info),再与虚拟系统所需要的通用信息拼接起来而形成的一个格式统一的超级块,它相当于一个实际文件系统在虚拟文件系统中的身份证。

dentry与inode

“文件”, 就是按一定的形式存储在介质上的信息,所以一个文件其实包含了两方面的信息,一是存储的数据本身,二是有关该文件的组织和管理的信息。

在内存中, 每个文件(包括常规的文件和目录文件,文件夹)都有一个dentry(目录项)和inode(索引节点)结构.

dentry是存在于内存的目录项缓存,为了提高查找性能而设计,它记录着文件名,上级目录等信息,所有的dentry用d_parent和d_child连接起来,就形成了我们熟悉的树状结构,正是它形成了我们所看到的树状结构;VFS在查找的时候,根据一层一层的目录项找到对应的每个目录项的inode,那么沿着目录项进行操作就可以找到最终的文件。

而有关该文件的组织和管理的信息主要存放inode里面,它记录着文件在存储介质上的位置与分布,例如可以通过inode可以得到一个数组,这个数组记录了文件内容在磁盘中的位置。

同时dentry->d_inode指向相应的inode结构。dentry与inode是多对一的关系,因为有可能一个文件有好几个文件名(由于硬链接, hard link);

文件对象与dentry和inode和task_struct

task_struct中的fs成员中有三个指向目录项对象的指针, root、 pwd 及 altroot 三个指针都指向这个结构。 其中, root 所指向的 dentry 结构代表着本进程所在的根目录, 也就是在用户登录进入系统时所看到的根目录; pwd 指向进程当前所在的目录; 而 altroot 则是为用户设置的替换根目录。实际运行时, 这三个目录不一定都在同一个文件系统中。

task_struct中的files成员中有一个文件对象的指针数组。这个数组中存放着该进程打开的文件(也就是使用的文件描述符)。

进程通过上述两个成员和文件系统联系起来。

文件对象file中有一个指向相关目录项对象的指针,然后目录项对象中有一个指向相关inode对象的指针。

因为一个文件可以被多个进程打开,所以一个文件可以对应着多个文件对象。但是由于文件是唯一的,那么inode就是唯一的,目录项也是定的!

额外的一些Tips

1.文件对象中的成员:引用计数f_count,当我们关闭一个进程的某一个文件描述符时候,其实并不是真正的关闭文件,仅仅是将f_count减一,当f_count=0时候,才会真的去关闭它。对于dup,fork这些操作来说,都会使得f_count增加。

二.文件缓冲区

所谓文件缓冲区,就是一块内核内存区域。由于该区域是进程与磁盘之间起缓冲作用的中介,缓冲区在与磁盘交换信息时必须以块为访问单位,即从磁盘的角度看,这个缓冲区是磁盘数据块缓冲区(buffer cache),然而缓冲区在与进程交换信息时通常以页为访问单位,而从进程的角度看,则是页缓冲区(page cache)。

换句话说,所谓的buffer cache和page cache,在linux2.4.10版本之后,实际就是指向同一块内核内存区域,只是站的角度不同,缓冲区在与磁盘交换信息时必须以块为访问单位,即从磁盘的角度看,这个缓冲区是磁盘数据块缓冲区(buffer cache),主要是来自VFS的访问,然而缓冲区在与进程交换信息时通常以页为访问单位,从进程的角度看,则是页缓冲区(page cache),主要是来自进程的访问。

buffer page就是带数据的page加上buffer head以定义该page中每个block的信息。

因此,内核中设置了两套用来管理缓冲区的数据结构。
在这里插入图片描述

磁盘数据块缓冲区

在Linux中,每一个磁盘数据块缓冲区用buffer_head结构来描述.
其中,域b_data是指向内存中磁盘块缓冲区的指针;域b_size表示缓冲区的大小。由于进程以页面为单位来访问缓冲区,所以结构中用域b_this_page把同一页面缓冲块组成了一个环形链表。

另外,系统根据磁盘数据块缓冲区的使用状态将它们分别组成了多个队列。

内存中的一个磁盘块缓冲区的队列示意图如下所示:
在这里插入图片描述

页缓冲区

为了方便进程对文件的使用,并在需要时能把以块为单位的磁盘块缓冲区(块的大小一般为512字节)映射到以页为单位(页的大小一般4k)的用户空间,VFS还建立了页缓冲区。由于进程是通过VFS的i节点来访问文件的,因此,文件的页缓冲区也就被设置在inode结构中。

inode结构中有一个指向自身的i_data域的指针i_mapping,这个i_data域是一个address_space的结构。而每一个页面的所有信息由struct page来描述,它有一个名称为mapping的域,这是一个指针,它指向一个struct address_space类型结构。

在这里插入图片描述

Storing Blocks in the Page Cache

In old versions of the Linux kernel, there were two different main disk caches: the page cache, which stored whole pages of disk data resulting from accesses to the contents of the disk files, and the buffer cache, which was used to keep in memory the contents of the blocks accessed by the VFS to manage the disk-based filesystems. Starting from stable version 2.4.10, the buffer cache does not really exist anymore. In fact, for reasons of efficiency, block buffers are no longer allocated individually; instead, they are stored in dedicated pages called “buffer pages,” which are kept in the page cache.Formally, abuffer pageis a page of data associated with additional descriptors called “buffer heads,” whose main purpose is to quickly locate the disk address of each individual block in the page. In fact, the chunks of data stored in a page belonging to the page cache are not necessarily adjacent on disk.

最后,大图奉上~

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值