第十章 文件系统
10.1 文件概念
操作系统对存储设备的物理属性加以抽象,从而定义逻辑存储单位,即文件(file)。文本文件(text file) 为按行(可能还有页)组织的字符序列,源文件(source file)为函数序列,而每个函数包括声明和可执行语句。可执行文件(executable file)为一系列代码段,以供加载程序调入内存并执行。
10.1.1 文件属性
文件的属性因操作系统而异,但通常包括:
- 名称:符号文件名是以人类可读形式来保存的唯一信息。
- 标识符:这种唯一标记(通常为数字)标识文件系统的文件;它是文件的非人类可读的名称。
- 类型:支持不同类型文件的系统需要这种信息。
- 尺寸:包括文件当前大小(以字节、字或字块为单位)以及可能允许的最大尺寸。
- 保护:访问控制信息确定谁能读写,执行等。
- 时间、日期和用户标识:文件创建、最后修改和最后使用的相关信息可以保存。这些数据用于保护、安全和使用监控。
10.1.2 文件操作
操作系统可以提供系统调用,来创建、写入、读取、重新定位、删除以及截断文件。下面讨论操作系统如何执行这6个基本文件操作。
- 创建文件:创建文件需要两个步骤。首先必须在文件系统中为文件找到空间,然后必须在目录中创建新文件的条目。
- 写文件:使用一个系统调用指定文件名称和要写入文件的信息。根据给定的文件名称,系统搜索目录以查找文件位置,系统应保留写指针(write pointer),用于指向需要进行下次写操作的文件位置。每当发生写操作时,写指针必须被更新。
- 读文件:使用一个系统调用,指明文件名称和需要文件的下一个块应放在哪里(在内存中)。
- 重新定位文件:搜索目录以寻找适当的条目,并且将当前文件位置指针重新定位到给定值。这个文件操作不涉及任何实际 I/O ,这个操作也称为文件定位(file seek)。
- 删除文件:在目录中搜索给定名称的文件,找到关联的目录条目后,释放所有文件空间,并删除目录条目。
- 截断文件:删除文件内容,但保留它的属性。这个功能允许所有属性不变(除了文件长度),但让文件重置为零,并释放它的文件空间。
以上提及的大多数文件操作涉及搜索目录,以得到命名文件的相关条目。为避免这种不断的搜索,许多系统要求,在首次使用文件之前进行系统调用 open() 。操作系统有一个打开文件表(open-file table)用于维护所有打开文件的信息。当请求文件操作时,可以通过该表的索引指定文件,而不需要搜索。当文件最近不再使用时,进程关闭它。操作 open() 根据文件名搜索目录,将目录条目复制到打开文件表,调用 open() 也会接受访问模式信息,如创建、只读、读写、只附加等。根据文件权限,检查这种模式。如果允许请求模式,则会为进程打开文件。系统调用 open() 通常返回一个指向打开文件表的对应条目的指针。这个指针会用于所有的 I/O 操作,以避免任何进一步搜索,并简化系统调用接口。
对于多个进程可以同时打开文件的环境,通常操作系统采用两级的内部表:每个进程表和整个系统表。每个进程表跟踪它打开的所有文件,该表存的是进程对文件的使用信息。单个进程表的每个条目相应地指向整个系统的打开文件表。系统表包含与进程无关的信息。一旦有进程打开一个文件,系统表就包含该文件的条目。当一个进程执行 open() ,只要简单地在器进程打开表中增加一个条目,并指向系统表的相应条目。通常,系统打开文件表为每个文件关联一个打开计数(open count),用于表示有多少个进程打开了这个文件。每次 close() 递减打开计数;当打开计数为0时,可从系统打开文件表中删除这个文件条目。
每个打开文件具有如下关联信息:
- 文件指针
- 文件打开计数
- 文件的磁盘位置
- 访问权限:每个进程采用访问模式打开文件。这种信息保存在进程的打开文件表中,因此操作系统可以允许或拒绝后续的 I/O 请求。
10.1.3 文件类型
如果操作系统识别文件的类型,它就能按合理的方式来操作文件。实现文件类型的常见技术是将类型作为文件名的一部分。文件名分为两部分,即名称和扩展,通常由句点分开。操作系统使用扩展名来指示文件类型和可用于文件的操作类型。
10.1.4 文件结构
文件类型也可用于指示文件的内部结构。文件需具有一定的结构,以便匹配读取它们的程序的期望。让操作系统支持多个文件结构带来一个缺点:操作系统会变得太复杂。如果操作系统定义了5个不同的文件结构,则它需要包含代码,以便支持这些文件结构。有些操作系统强加(并支持)最小数量的文件结构。UNIX、Windows 都采用这种方案。UNIX 认为每个文件为8位字节序列;而操作系统并不对这些位做出解释。这种方案提供了最大的灵活性,但是支持的也很少。每个应用程序必须包含自己的代码,以便按适当的结构来解释输入文件。但是,所有操作系统必须支持至少一种结构,即可执行文件的结构,以便系统能够加载和运行程序。
10.1.5 内部文件结构
???
10.2 访问方法
文件储存信息,当使用时,必须访问这种信息。
10.2.1 顺序访问(sequential access)
文件信息按顺序(一个记录接着一个记录地)加以处理。(这种访问模式最常见,例如编辑器和编译器)
10.2.2 直接访问
直接访问(direct access)也称相对访问(relative access)。这里,文件由固定长度的逻辑记录(logical records)组成,以允许程序按任意顺序进行快速读取和写入记录。直接访问方法基于文件的磁盘模型。用户通常提供给操作系统文件的相对块号(relative block number)(相对文件开头的索引),以访问文件对应位置的信息。使用相对块号允许操作系统决定文件放置在哪里(称为分配问题(allocation problem))。
还有其他通过建立索引等方式进行访问。
10.3 目录与磁盘的结构
一个存储设备可以按整来用于文件系统,也可细分以提供更细粒度的控制,如一个磁盘可以划分为4个分区(partition)。包含文件系统的分区称为卷(volume)。包含文件系统的每个卷也应包含有关系统内的文件信息,这些信息保存在设备目录(device directory)或卷目录表(volume table of content)中。
10.3.1 目录概述
目录可视为符号表,可将文件名称转成目录条目。采用这种观点,可按许多方式来组织目录。这种租着允许我们插入条目、删除条目、搜索命名条目以及列出所有目录条目等。
10.3.2 单级目录
所有文件都包含在一个目录中。这样的目录虽然组织简单,但具有很大的局限性。
10.3 4 两级目录
单级目录常常导致混乱的文件名。标准的解决方案是为每个用户创建一个单独的目录。对于两级目录结构,每个用户都有自己的用户文件目录(User File Directory,UFD)。当用户作业开始或用户登录时,搜索系统的主文件目录(Master File Directory,MFD)。通过用户名或账户可索引MFD,每个条目指向该用户的 UFD。当用户引用特定文件时,只搜索他自己的 UFD。系统管理员可运行一个特别的程序创建或删除 UFD。虽然两级目录结构解决了名称碰撞问题(不同 UFD 下可有同名程序也不会引起混淆),有效的将一个用户与另一个用户隔离。但当用户需要在某个任务上进行合作并且访问彼此文件时,隔离却是个缺点。如果允许一个用户访问另一个用户的目录中的文件,那么它必须能够命名该文件。我们使用用户名和文件名定义路径名(path name)。为了唯一地命名文件,用户必须知道所需文件的路径名。
还有一个特例是关于系统文件(作为系统一部分的程序)。一种方案是给每个用户都复制一份,但这样太浪费空间。还有一种方案是创建一个特殊的用户目录定义成包含系统文件。每当需要加载给定名称的文件时,操作系统首先搜索本地 UFD。如果找到则使用,否则,系统自动搜索包含系统文件的特殊用户目录。用于搜索给定名称的文件所用的目录序列称为搜索路径(search path)。
10.3.5 树形目录
可将两级目录视为两级树,那么自然推广就是将目录结构扩展到任意高度的树。这种推广允许用户创建自己的子目录并相应的组织文件。常规使用时,每个进程都有一个当前目录(current directory)(包括进程当前感兴趣的大多数文件)。用户可指定路径名来引用不在当前目录下的文件。路径名有两种形式:绝对路径名(absolute path name)从根开始遵循一个路径到指定文件,并给出路径上的目录名。相对路径名(relative path name)从当前目录开始,定义一个路径。
10.3.6 无环图目录
树结构禁止共享文件或目录。无环图(acyclic graph),允许目录共享子目录和文件。同一文件或子目录可以出现在两个不同目录中。实现时,一种常见的方式是采用链接(link)。无环图目录结构比简单的树结构更灵活但也更复杂。需要考虑文件都的查找(一个文件可能有多个绝对路径名)、删除(删除可能留下悬挂指针)等。
10.4 文件系统安装
正如文件在使用前必须要打开一样,文件系统在用于系统的进程之前必须先安装(mount)。安装过程很简单,操作系统只需知道设备的名称和安装点(mount point)(附加文件系统在原来文件结构中的位置)。
10.5 文件共享
10.5.1 多用户
为了实现共享与保护,多用户系统必须比单用户系统维护更多的文件和目录属性。现在大多数系统都采用了文件(或目录)所有者(owner)(或用户(user))和组(group)的概念。文件所有者可以拥有最高控制,组属性定义用户子集,文件组的成员和其他用户可以对文件进程哪些具体操作由文件所有者来定义。当用户请求操作文件时,将用户 ID 与所有者属性、组 ID 比较以确定该用户拥有怎样的操作权限。
10.5.2 远程文件系统
远程文件共享方法:第一种实现方法是通过如ftp程序在机器之间手动传送文件;第二种方法是,通过分布式文件系统(Distributed File System,DFS),远程目录从本机上可直接访问;第三种方法是,万维网(World Wide Web,WWW)。
10.5.2.1 客户机 - 服务器模型
远程文件系统允许一台计算机安装一台或多台远程机器上的一个或多个文件系统。在这种情况下,包含文件的机器是服务器(server),需要访问文件的机器是客户机(client)。
10.5.2.2 分布式信息系统
为了更易管理客户机-服务器系统,分布式信息系统(distributed information system)也称为分布式命名服务(distributed naming service),对远程计算所需信息提供统一访问。域名系统(Domain Name System,DNS)为整个互联网提供主机名到网络地址(host-to-name-to-network address)的转换。
10.5.2.3 故障模式
考虑一个客户机正在使用远程文件系统,突然远程文件系统不再可用,客户系统不应按照本地文件系统的丢失一样来处理。系统可以终止对丢失服务器的所有操作或延迟操作,直到服务器再次可用为止。为了实现这种故障恢复,可能要在客户机和服务器上维护一定的状态信息(state information)。
10.5.3 一致性语义
一致性语义(consistency semantic)是个重要准则,用于评估支持文件共享的文件系统。这些语义规定系统的多个用户如何访问共享文件。特别的,它们规定了一个用户的数据修改何时为另一用户可见。这些语义通常由文件系统代码来实现。在下面的讨论中,假设用户尝试的一系列文件访问总是包含在操作 open() 和 close() 之间的,这样的一系列访问称为文件会话(file session)。
10.5.3.1 UNIX 语义
- 一个用户对已打开文件的写入,对于打开同一文件的其他用户立即可见。
- 一种共享模式允许用户共享文件的当前位置指针。因此一个用户前移指针就会影响所有共享用户。
10.5.3.2 会话语义
Andrew 文件系统(Open AFS)采用以下一致性语义:
- 一个用户对已打开文件的写入,对于打开同一文件的其他用户,不是立即可见的。
- 一旦文件关闭,对其所做的更改只能被后来打开的会话可见
10.5.3.3 不可变共享文件语义
一个不可变文件有两个关键属性:它的名称不可以重用,它的内容不可以改变。
10.6 保护
当信息存储在计算机系统时,需要保护它的安全,以避免物理损坏(可靠性的问题)和非法访问(保护问题)。可靠性通常通过文件的重复副本来提供。
10.6.1 访问类型
通过限制可进行的文件访问类型,保护机制提供受控访问。
- 读。
- 写。
- 执行:加载文件到内存并执行它。
- 附加:在文件末尾写入新的信息。
- 删除。
- 列表:列出文件的名称和属性。
其他操作,如文件的重命名、复制、编辑等也可以控制。
10.6.2 访问控制
保护问题的最常见方法是,根据用户身份控制访问。为每个文件和目录关联一个访问控制列表(Access-Control List,ACL),以指定每个用户的名称及其允许访问类型。这样能够进行复杂的访问方法,但有一个主要的问题就是访问列表的长度。目录条目以前是固定大小,现在必须是可变大小,导致了更为复杂的空间管理。通过采用精简的访问列表,可以解决。许多系统为每个文件采用了三种用户类型:所有者、组、其他。为每种类型设置特定的访问权限。
10.6.3 其他保护方式
为每个文件加上一个密码,如计算机系统的访问通常通过密码控制一样。但是用密码具有如下缺点:用户需要记住的密码数量太多;如果所有文件只使用一个密码,一旦发现则所有文件都可被访问。