当前位置: 首页 > Linux

vfs基础

时间:2023-04-06 02:33:59 Linux

转载1目录模型2VFS的概念VFS是Linux中的一个虚拟文件系统,也称为虚拟文件系统交换层(VirtualFilesystemSwitch)。它为应用程序员提供了一个抽象层,屏蔽了各种底层文件系统的差异。如下图所示:3VFS构建所谓VFS构建就是加载实际文件系统的过程,也就是调用mount的过程。如下图,以挂载一个ext2文件系统为例。这是一个简化的Ext2磁盘结构,只是为了说明用它构建VFS的基本过程。mount命令的一般形式为:mount/dev/sdb1/mnt/mysdb1/*/dev/sdb1为设备名,/mnt/mysdb1为挂载点*/VFS文件系统的基本结构为dentry结构和inode结构。Dentry代表文件目录中的一个点,可以是目录也可以是文件。inode代表磁盘上的一个文件,它和磁盘文件一一对应。inode和dentry不一定是一一对应的,一个inode可能对应多个dentry项。(hardlink)挂载时,Linux首先找到磁盘分区的superblock,然后通过分析磁盘的inode表和文件数据,建立自己的dentrylist和inodelist。需要注意的是,VFS其实是按照Ext的方式构建的,所以两者非常相似(毕竟Ext是Linux原生的文件系统)。比如inode节点,Ext和VFS都把文件管理结构称为inode,其实是不一样的。Ext的inode节点在磁盘上;VFS的inode节点在内存中。Ext-inode中有些成员变量其实是没有用的,比如引用计数。保留它们是为了与vfs-node保持一致。这样,在使用ext-inode节点构造vfs-inode节点时,不需要一个一个赋值,只需要一份内存拷贝。如果是非EXT的盘就没那么幸运了,所以mount非EXT的盘会比较慢。4VFS结构在构建了VFS文件系统之后,下一步就是将第一节提到的目录模型映射到VFS结构系统。上面说了,VFS主要由denty和inode组成。Dentry用于维护VFS的目录结构。每个dentry项代表我们在使用ls时看到的一个项(每个目录和每个文件对应一个dentry项)。inode是一个文件节点,它与一个文件一一对应。在Linux中,目录也是一种文件,所以dentry也对应一个inode节点。下图是上图目录模型在VFS中的结构。5dentrycache每个文件必须对应一个inode节点和至少一个dentry项。假设我们有一个100G的硬盘,里面装满了空文件,重建VFS需要多少内存?该文件必须至少占用1个块(通常为4K)。假设一个dentry和一个inode需要100字节,那么dentry和inode需要占用1/40的空间。1G硬盘需要2.5G空间。最近开始装1T硬盘。需要25G的内存来存放inode和dentry。我相信很少有电脑能负担得起。为了避免资源浪费,VFS采用了dentrycache的设计。当用户使用ls命令查看某个目录或使用open命令打开文件时,VFS会为这里使用的每个目录项和文件创建dentry项和inode,即“按需创建”。然后维护一个LRU(最近最少使用)列表。当Linux认为VFS占用过多资源时,VFS会释放长时间未使用的dentry项和inode项。需要注意的是,这里的建立和释放是从内存使用的角度来看的。从Linux的角度来看,dentry和inode是VFS中固有的东西。唯一的区别是VFS是否将dentry和inode读入内存。对于Ext2/3文件系统来说,构建dentry和inode的过程非常简单,但是对于其他文件系统,就会慢很多。6没有dentry时定位文件因为上面提到的DentryCache,VFS不能保证随时有dentry项和inode项。下面是没有dentry项和inode项时的定位方法。为了简化问题,假设已经找到了dir的dentry项(找dentry的过程会在后面说明)。首先通过dir对应的dentry0找到inode0节点。有了inode节点,就可以读取目录中的信息。它包含目录中包含的下一级目录和文件的列表,包括名称和索引节点号。其实ls命令就是用来查看这些信息的。“ls-i”将显示文件的索引节点号。>ls-i975248subdir0975247subdir1975251file0然后根据subdir0对应的inode号重建inode2,通过文件数据(目录也是文件)和inode2重建subdir0的dentry节点:dentry1。>ls-i975311file1975312file2接下来根据file1对应的inode编号重建inode4,通过文件数据和inode4重建file1的dentry节点。最后可以通过inode4节点访问文件。注意:文件对应的inode号是确定的,但是需要重构inode结构。7有dentry时定位文件8符号链接9硬链接10文件的进程管理与文件相关的进程控制块task_struct中有两个变量:fs和files。文件存储两个指向dentry项的指针,root和pwd。当用户指定路径时,绝对路径将由root定位;相对路径将由pwd定位。(进程的根不一定是文件系统的根目录,比如ftp进程的根目录就不是文件系统的根目录,这样才能保证用户只能访问文件系统的内容ftp目录)fs是一个文件对象列表,每个节点对应一个打开的文件。当进程定位到文件时,会构造一个文件对象,并通过f_inode关联到inode节点。当文件关闭(close)时,进程会释放相应的文件对象。file对象中的f_mode是打开时选择的权限,f_pos是读写位置。当同一个文件被多次打开时,每次都会构造一个新的文件对象。每个文件对象都有独立的f_mode和f_pos。11open进程首先建立一个文件管理结构,如下图,进程打开了两个文件,接下来我们再打开一个新的文件。第一步:找到文件;从上面我们可以定位到我们文件的inode节点,找到inode节点就找到文件了。第二步:创建文件对象;新建一个文件对象对象,放入文件对象对象列表,指向inode节点。第三步:创建文件描述符文件描述符是进程控制块task_struct中文件维护的fd_array。因为它是一个数组,所以文件描述符实际上已经预先分配了空间。这里,有必要将一个自由文件描述符与文件对象相关联。这个文件描述符在数组中的索引号就是文件打开时得到的文件fd。12openanddup同一个文件可以多次打开,结构如下图所示。每次打开都会创建一个新的文件描述符和文件对象。然后指向同一个文件的inode节点。下图中,假设打开的文件和fd1指向同一个文件,那么新创建的文件对象2和fd1的文件对象2会指向同一个inode2节点。Linux还提供了用于复制文件描述符的dup函数。使用dup不会创建新的非文件对象,所以新创建的文件描述符和原来的文件描述符会同时指向同一个文件对象。下图中,我们通过dup(fd1)得到了fd2,那么fd2和fd1指向同一个文件object2。13fork对打开文件的影响Dup的操作类似于fork子进程的操作。下图是现有父进程的文件结构:使用fork后的结构如下。同样没有创建新的文件对象,所以当父进程中的fd1移动文件指针时(比如读写),子进程中的fd1也会受到影响。也就是说,打开的文件列表不是进程的一部分,所以不会被复制。Openedfileslist应该是一个全局资源链表,进程维护了一个指针列表fd表,所以复制的只是指针列表fd表,而不是openedfileslist。14文件操作函数分析