现在的位置: 首页 > 综合 > 正文

Linux内核具体体系结构之虚拟文件系统

2017年12月22日 ⁄ 综合 ⁄ 共 5333字 ⁄ 字号 评论关闭
文章目录

Linux内核具体体系结构之虚拟文件系统

作者: Waterloo, Ontario N2L 3G1 
CS 746G, Winter 1998
刘建文略译(http://blog.csdn.net/keminlau )

3.3 Virtual File System

3.3.1 Goals

Linux被设计成支持驱动多种不同物理设备的现代操作系统。注意,即便是同一种的硬件设备也可能存在多种不同的接口,比如硬盘有PATA、SATA、SCSI、 USB等不同接口(KEMIN:注意接口与总线的区别)。除了支持不同的物理设备接口外,Linux还支持各种不同的逻辑文件系统( logical file systems),这个功能有助于Linux与其它的操作系统共存和互操作。[虚拟文件系统]泛化和囊括了[外设输入输出]和[逻辑文件系统]功能,实现以下一些“伟大”目标:

  • * Multiple hardware devices - provide access to many different hardware devices
  • * Multiple logical file systems - support many different logical file systems
  • * Multiple executable formats - support several different executable file formats (like a.out, ELF, java)
  • * Homogeneity - present a common interface to all of the logical file systems and all hardware devices
  • * Performance - provide high-speed access to files
  • * Safety - do not lose or corrupt data
  • * Security - restrict user access to access files; restrict user total file size with quotas

3.3.2 External Interface

[虚拟文件系统]为系统边界提供了两层的接口:对外的是给用户进程调用的系统调用(system-call);对内是给内核其它子系统调用的底层函数。

对外系统调用函数是符合POSIX标准的,包括文件操作open/close/read/write/seek/tell,和目录操作readdir/creat/unlink/chmod/stat。

对内的接口则更丰富一些,除了公开文件系统的功能函数,还会对内核其它子系统公开一些实现的数据结构。比如, inode 和 file。以下两个接口定义可在文件系统C头文件(/include/linux/fs.h)中找到:

Inode Interface:

  • * create(): create a file in a directory
  • * lookup(): find a file by name within a directory
  • * link() / symlink() / unlink() / readlink() / follow_link(): manage file system links
  • * mkdir() / rmdir(): create or remove sub-directories
  • * mknod(): create a directory, special file, or regular file
  • * readpage() / writepage(): read or write a page of physical memory to a backing store
  • * truncate(): set the length of a file to zero
  • * permission(): check to see if a user process has permission to execute an operation
  • * smap(): map a logical file block to a physical device sector
  • * bmap(): map a logical file block to a physical device block
  • * rename(): rename a file or directory

注:除了以上inode的接口,其它内核子系统还可以调用namei() 函数查出与inode相关联的文件或目录。

File Interface:

  • * open() / release(): open or close the file
  • * read() / write(): read or write to the file
  • * select(): wait until the file is in a particular state (readable or writeable)
  • * lseek(): if supported, move to a particular offset in the file
  • * mmap(): map a region of the file into the virtual memory of a user process
  • * fsync() / fasync(): synchronize any memory buffers with the physical device
  • * readdir: read the files that are pointed to by a directory file
  • * ioctl: set file attributes
  • * check_media_change: check to see if a removable media has been removed (such as a floppy)
  • * revalidate: verify that all cached information is valid

3.3.3 Subsystem Description

[虚拟文件系统]为了支持驱动多种[逻辑文件系统]和多种[I/O设备],实现了两个概念逻辑层——[设备驱动层]和[逻辑文件系统层],并且是以一种易于扩展的方法实现的。所谓[概念逻辑层]指是对多种实现细节进行统一抽象,比如[设备驱动层]对各种[I/O设备]进行抽象,提供一致的访问接口;[逻辑文件系统层]亦如是。

KEMIN:我对这幅构图有一点不解的,就是用户进程访问非磁盘设备(比如网卡)要不要通过逻辑文件系统层?
答案是[设备文件系统 ] 。

Device Drivers

[设备驱动层]负责对所有硬件设备进行包装抽象。Linux内核支持三种设备驱动:字符设备、块设备和网络设备。前两者是与[虚拟文件系统]直接相关的。字符设备必须按顺序访问,而块设备则可随机访问,但必须以块为单位。

所有设备驱动 必须实现前面提到的文件接口(file interface)函数。从而,每个设备都可以看成文件,通过文件系统访问到它(这个文件被专称为[设备文件])。当内核(或用户进程)都统一通过这个 [文件接口]访问设备的时候,为系统添加新设备变得很容易;因为这个[文件接口]是抽象的(虚的),只要编写设备的硬件相关的代码 实现这个接口即可。

块设备驱动如果引入缓冲(buffer)机构可大大提高I/O性能。因为缓冲区可最少化读写硬件设备的次数。内核会为每一个设备指定一个请求队列(request queue),当[缓冲机构]发现设备的缓冲区的数据不足以满足一个请求时,[缓冲机构]会把该请求添加到设备请求队列 ,然后眠掉该请求,直到缓冲区数据足够。[缓冲机构]由一个独立的内核线程——kflushd实现。kflushd也负责将缓冲数据写入外部设备,并清理缓冲区。

主机和外设通信一般使用三种方式:轮询、DMA和中断。中断相对前两者要复杂一些。

中断机制可以使外设独立于主机,有自己的状态,与主机并发工作。当外设需要向主机报告一个状态的改变时(比如鼠标单击、键盘被按下或一项请求的操作完成),它给主机发出一个中断信号。主机CPU在处理中断的条件满足后执行相应的中断处理代码。这些代码就是设备驱动程序(KEMIN:CPU是怎么找到这些中断处理代码吗?中断向量表是固定的吗?设备驱动程序在安装时又是如何注册中断向量的?多个设备驱动是怎么实现共享一个中断向量的(像USB驱动)?)。 CPU在处理中断请求时运行在一个特定的上下文,同一时刻可能有多个中断请求,而且缓急不一,中断处理必须非常高效,以免丢失重要的中断请求。

有时候中断处理任务太重而未能在限定的时间内完成,在这种情形下,中断处理被分为上下两半部分,上半部分在限定的时间内完成,下半部分由于不是十分紧急而指派到调度队列,等待被调度完成。这种做法能够降低设备驱动的中断延迟并提高系统并发性。

Logical File Systems

虽然我们可以通过[设备文件]访问所有物理设备,但我常常只通过[逻辑文件系统 ]访问[块设备]。

当一块[块设备]的文件系统被挂接(mounted)入[虚拟文件系统]目录树后,该设备上的所有文件和目录可从挂点访问(KEMIN:注意用词表达,文件系统是设备的属性,是块设备的一部分,被格式化后的设备有了质的变化)。目录树各分支的具体实现对用户是透明的,用户不必知道文件所在文件系统是什么,也不必知道文件在哪个物理设备上。这种灵活性是Linux成功的原因之一。那么Linux是如何实现这种灵活性的呢?

为了实现[虚拟文件系统],Linux引入节点[inodes]的概念。Linux用一个inode数据结构表征块设备上的一个文件。和前面提到的[文件接口]类似,[节点接口]也是抽象的,只包括节点操作函数的定义。特定的文件系统 具体实现它们的节点接口。包括文件系统的逻辑部分(目录组织策略)和物理部分(可访问的物理单元)。
Modules

虚拟文件系统的各部分功能可以以[动态加载模块 ]的形式实现。这个动态配置内核模块的方式可以让用户能尽可能小地编译内核,并且还能够在会话过程中按需加载设备驱动或文件系统。

3.3.4 Data Structures

以下三个数据结构是[虚拟文件系统]相关的:

* super_block:每个逻辑文件系统都有一个超级块( superblock )数据结构相关联,用于表征其存在于内核中。超级块包括了关于已挂接入目录树的逻辑文件系统元信息,比如哪些数据块被使用、块大小等。

* inode:inode是常驻内存的数据结构,用于保存单个磁盘上文件的所有元信息。内核需要这些信息对文件进行管理,包括跟踪进程使用、数据缓冲和内存映射。

* file:这个数据结构则表征被特定进程打开的文件。所有被打开的文件都保存到一个双向链表中(其首地是由first_file指向);All open files are stored in a doubly-linked list (pointed to by first_file); the file descriptor that is used in POSIX style routines (open, read, write) is the index of a particular open file in this linked list.

3.3.5 Subsystem Structure

Figure 6: File Subsystem Structure

3.3.6 Subsystem Dependencies

Figure 7: File Subsystem Dependencies

Figure 7 shows how the file system is dependent on other kernel subsystems. Again, the file system depends on all other kernel subsystems, and all other kernel subsystems depend on the file subsystem. In particular, the network subsystem depends on the file system because network sockets are presented to user processes as file descriptors. The memory manager depends on the file system to support swapping. The IPC subsystem depends on the file system for implementing pipes and FIFO’s. The process scheduler depends on the file system to load loadable modules.

The file system uses the network interface to support NFS; it uses the memory manager to implement the buffer cache and for a ramdisk device; it uses the IPC subsystem to help support loadable modules, and it uses the process scheduler to put user processes to sleep while hardware requests are completed. For more details, see [PBS:fs.html].

抱歉!评论已关闭.