文件描写符的操纵(如: open)返回的是一个文件描写符,内核会在每个历程空间中维护一个文件描写符表,
所有打开的文件都将通过此表中的文件描写符来引用;
而流(如: fopen)返回的是一个FILE布局指针,
FILE布局是包括有文件描写符的,FILE布局函数可以看作是对fd直接操纵的系统挪用的封装, 它的利益是带有I/O缓存
Linux支持各类百般的文件系统名目,如ext2、ext3、reiserfs、FAT、NTFS、iso9660等等,差异的磁盘分区、光盘或其它存储设备都有差异的文件系统名目,然而这些文件系统都可以mount到某个目次下,使我们看到一个统一的目次树,各类文件系统上的目次和文件我们用ls呼吁看起来是一样的,读写操纵用起来也都是一样的,这是怎么做到的呢?Linux内核在各类差异的文件系统名目之上做了一个抽象层,使得文件、目次、读写会见等观念成为抽象层的观念,因此各类文件系统看起来用起来都一样,这个抽象层称为虚拟文件系统(VFS,Virtual Filesystem)。上一节我们先容了一种典范的文件系统在磁盘上的存储机关,这一节我们先容运行时文件系统在内核中的暗示。
3.1. 内核数据布局Linux内核的VFS子系统可以图示如下:
每个历程在PCB(Process Control Block)即历程节制块中都生存着一份文件描写符表,文件描写符就是这个表的索引,文件描写表中每个表项都有一个指向已打开文件的指针,此刻我们明晰一下:已打开的文件在内核顶用file布局体暗示,文件描写符表中的指针指向file布局体。
在file布局体中维护File Status Flag(file布局体的成员f_flags)和当前读写位置(file布局体的成员f_pos)。在上图中,历程1和历程2都打开同一文件,可是对应差异的file布局体,因此可以有差异的File Status Flag和读写位置。file布局体中较量重要的成员尚有f_count,暗示引用计数(Reference Count),后头我们会讲到,dup、fork等系统挪用会导致多个文件描写符指向同一个file布局体,譬喻有fd1和fd2都引用同一个file布局体,那么它的引用计数就是2,当close(fd1)时并不会释放file布局体,而只是把引用计数减到1,假如再close(fd2),引用计数就会减到0同时释放file布局体,这才真的封锁了文件。
每个file布局体都指向一个file_operations布局体,这个布局体的成员都是函数指针,指向实现各类文件操纵的内核函数。好比在用户措施中read一个文件描写符,read通过系统挪用进入内核,然后找到这个文件描写符所指向的file布局体,找到file布局体所指向的file_operations布局体,挪用它的read成员所指向的内核函数以完成用户请求。在用户措施中挪用lseek、read、write、ioctl、open等函数,最终都由内核挪用file_operations的各成员所指向的内核函数完成用户请求。file_operations布局体中的release成员用于完成用户措施的close请求,之所以叫release而不叫close是因为它不必然真的封锁文件,而是淘汰引用计数,只有引用计数减到0才封锁文件。对付同一个文件系统上打开的通例文件来说,read、write等文件操纵的步和谐要领应该是一样的,挪用的函数应该是沟通的,所以图中的三个打开文件的file布局体指向同一个file_operations布局体。假如打开一个字符设备文件,那么它的read、write操纵必定和通例文件纷歧样,不是读写磁盘的数据块而是读写硬件设备,所以file布局体应该指向差异的file_operations布局体,个中的各类文件操纵函数由该设备的驱动措施实现。
每个file布局体都有一个指向dentry布局体的指针,“dentry”是directory entry(目次项)的缩写。我们传给open、stat等函数的参数的是一个路径,譬喻/home/akaedu/a,需要按照路径找到文件的inode。为了淘汰读盘次数,内核缓存了目次的树状布局,称为dentry cache,个中每个节点是一个dentry布局体,只要沿着路径各部门的dentry搜索即可,从根目次/找到home目次,然后找到akaedu目次,然后找到文件a。dentry cache只生存最近会见过的目次项,假如要找的目次项在cache中没有,就要从磁盘读到内存中。
每个dentry布局体都有一个指针指向inode布局体。inode布局体生存着从磁盘inode读上来的信息。在上图的例子中,有两个dentry,别离暗示/home/akaedu/a和/home/akaedu/b,它们都指向同一个inode,说明这两个文件互为硬链接。inode布局体中生存着从磁盘分区的inode读上来信息,譬喻所有者、文件巨细、文件范例和权限位等。每个inode布局体都有一个指向inode_operations布局体的指针,后者也是一组函数指针指向一些完成文件目次操纵的内核函数。和file_operations差异,inode_operations所指向的不是针对某一个文件举办操纵的函数,而是影响文件和目次机关的函数,譬喻添加删除文件和目次、跟踪标记链接等等,属于同一文件系统的各inode布局体可以指向同一个inode_operations布局体。