Linux Basic Concepts

VFS 文件系统

VFS 是一个软件层,用来处理与 Unix/Linux 标准文件系统相关的所有系统调用。是用户应用程序与文件系统实现之间的抽象层,VFS 能为各种文件系统提供一个通用的、统一的接口。(作用)

VFS 中描述各对象的数据结构:

  • 超级块对象 super_block;
  • 索引节点对象 inode;
  • 文件对象 file;
  • 目录项对象 dentry。

超级块对象(super block)

超级块对象描述一个文件系统的信息;对于每个具体的文件系统来说,都有各自的超级块,如 Ext2 超级块,并被存放在磁盘特定扇区上。当内核对一个具体文件系统进行 mount 安装时,调用文件系统提供的函数为其分配一个 VFS 超级块,并从此判读取具体文件系统超级块中的信息填充进来。

VFS 超级块是各个具体文件系统安装时才建立的,并在这些具体文件系统卸载时被自动删除,故 VFS 超级块仅存于主存中

具体文件系统的 VFS 超级块对象何时被创建?如何被创建?

在挂载的时候被创建,创建的方式是 get_sb 和 kill_sb 分别是在挂载(mount)和卸载(unmount)文件系统实例时会被调用的方法。VFS 通过 get_sb() 函数读取超级块,通过 kill_sb() 函数删除超级块。

文件系统被挂载时该文件系统必须是注册过的原因?

在挂载的时候会检查该文件系统类型是不是已经注册过的文件系统的类型,如果是,则在系统中找到对应的文件系统的相关数据结构,用来填充 VFS 的超级块对象。

每个文件系统都有一个初始化函数,他用于向 VFS 注册,即填写有 file_systems 指向的文件系统注册表数据结构 file_system_type。每一个文件系统类型在注册表中有一个登记项,记录了该文件系统的类型名,文件系统特性,指向对应的 VFS 数据块读取函数的地址及已注册项的链指针等。当装入一个文件系统时,应首先向内核注册该文件及其类型,当卸载一个文件系统时,应向内核申请注销该系 统及类型。文件系统类型的注册反映在以 file_systems 为链表头,以 file_system_type 为节点的链表中。链表的每一个 file_system_type 节点描述了一个已注册的文件系统类型。

索引结点对象(inode)

Inode 对象内包含了内核在操作文件或目录时需要的全部信息,文件名可以更改,但 inode 对文件是唯一的, 且随文件的存在而存在。一个 Inode 代表文件系统中的一个文件,它可以是设备或管道这类特殊文件,故 Inode 中会包含特殊的项。VFS 把每个目录看作一个文件,如在路径/tmp/test 中,tmp 和 test 都是文件, tmp 是目录文件,而 test 是普通文件; tmp 和 test 都有一个 inode 对象表示。每一个文件除了有一个 inode 数据结构外,还有一个 dentry 数据结构与之关联,该结构中的 d_inode 指针指向相应的 inode 结构。

文件对象(file)

文件对象在磁盘上没有映像,在文件被打开时创建由一个 file 结构组成。文件对象中的信息主要是文件指针,即文件中当前的位置,下一个操作将在该位置发生。file 结构除保存文件当前位置外,还把指向该文件 inode 的指针放在其中,并形成一个双项链表,称系统打开文件表.

目录项对象(dentry)

Dentry 数据结构可以加快对文件的快速定位,改进文件系统的效率。Dentry 描述文件的逻辑属性,它在磁盘上没有对应的映像; inode 结构记录文件的物理属性,在磁盘上有对应的映像.


与进程有关的文件系统的数据结构及作用(Files_struct, fs_struct)

用户打开文件相关信息 files_struct

系统打开表信息

进程的当前工作目录与根目录相关信息 fs_struct

Open 的执行过程

读写文件之前必须先打开文件。在文件被打开的过程中,要根据给定的文件路径名搜索目录结构。在内存,常常缓存部分目录结构以便加速目录操作。一旦文件被找到,文件的 FCB 被复制到内存里的系统打开文件表里。该表不仅存储 FCB,还记录打开该文件的进程数。接着,在进程打开文件表里创建一个指针字段,指向系统打开文件表里相应的表项。

打开文件系统调用返回指向进程打开文件表相应项的指针,以后文件的操作都通过这个指针进行。在 UNIX 系统,打开文件系统调用返回的是文件描述符.

注意:在 linux 中文件控制块为 inode 项

当进程关闭文件时,相应的进程打开文件表项被删除,相应的系统打开文件表项里的文件打开次数减一。当所有打开该文件的进程都关闭该文件时,已修改的文件信息被写回磁盘,相应的系统打开文件表项被删除。

实际上,open 系统调用首先搜索系统打开文件表,看该文件是否已被其它进程打开了。如果已经打开了,在进程打开文件表里增加一个指针,指向该文件在系统打开文件表里所占用的表项即可。 VFS 系统调用的实现过程:

文件的打开与关闭

  • 用户进程在读/写一个文件之前必须先打开这个文件。所谓打开文件实质上是在进程与文件之间建立连接,而打开文件描述符唯一地标识着这个连接。
  • 应用程序对 open ( )的调用将引起内核调用服务例程 sys_open ( )函数,该函数接收的参数为: 要打开文件的路径名和访问模式等。该系统调用成功后将返回一个文件描述符,也就是文件对象指 针数组的一个索引;系统调用不成功时返回-1。
  • 用户程序通过 close ( )系统调用关闭打开的文件,该函数接收的参数为要关闭文件的文件描述符。内核服务例程为 sys_close ( )函数。

文件的读与写

  • 文件的读/写主要是通过系统调用 read ( )和 write ( )完成的,对于读/写文件的进程,目标文件是由一个打开文件描述符代表的。
  • read ( )和 write ( )的服务例程分别是 sys_read ( )和 sys_write ( )函数。它们都需要三个参数:一个文件描述符 fd;一个包含要传送数据的内存缓冲区地址 buf;一个指定应该传送多少字节数的 count。read ( )把数据从文件传送到缓冲区,而 write ( )执行相反的操作。
  • 两个系统调用都返回所成功传送的字节数,或者发一个错误信号并返回-1。读或写操作总是发生在由当前文件指针所指定的文件偏移量处(文件对象的 f_pos 域)。两个系统调用都通过把所传送的字节数加到文件指针来更新文件指针
Terry Tang
Terry Tang
Software Development Engineer

My research interests include distributed robotics, mobile computing and programmable matter.

comments powered by Disqus

Related