文件系统¶
文件系统目标和要求¶
-
目标:方便用户管理自己的数据资源
-
基本要求
-
文件按名存储
-
文件有序组织,文件名分层次管理
-
如支持树形目录结构
-
操作简单,存取效率高。
-
-
其它要求:
-
支持多用户系统,多用户能够共享同一个磁介质。
-
有一定的安全性保证,最好能进行数据恢复。
-
存储空间的利用率高
-
文件系统概念¶
-
文件:
- 由文件名字标识的一组相关信息的集合。文件名是字母或数字组成的字母数字串
-
文件系统:
-
软件观点:操作系统中,为用户和应用程序管理文件的系统软件集合。
-
存储格式观点:文件系统是文件在存储介质上保存和管理相关的约定。在操作系统中,这种约定的实现也被称为文件系统。一种相关约定就对应一种文件系统,所以目前存在多种文件系统:FAT,FAT32,NTFS,EXT2 等。
-
-
操作系统和文件系统
-
早期:一个操作系统一般都支持一种文件系统。在设计操作系统时,常常会专门为此设计一种文件系统。
-
目前:为实现文件和文件系统共享,一个操作系统除支持为它设计的文件系统外,还可能支持其他文件系统。如 Linux 支持 Ext2,FAT 等。
-
-
文件类型
-
普通文件:即前面所讨论的存储在外存设备上的数据文件。
-
目录文件:文件在管理普通数据文件时,需要保存其相应的文件和属性,这些属性以目录文件的形式存储在磁盘中。
-
块设备文件:在 unix/Linux 等操作系统中,对应于磁盘、光盘或磁带等块设备的文件。
-
字符设备文件:在 unix/Linux 等操作系统中,对应于终端、打印机等字符设备的文件。
-
-
文件属性
-
文件的类型属性:如普通文件、目录文件、系统文件、隐式文件、设备文件等。
-
文件的保护属性:如可读、可写、可执行、可创建、可删除等。
-
创建者属性
-
创建和访问时间属性
-
文件大小
-
-
文件的逻辑组织方式
-
堆文件
-
顺序文件
-
索引顺序文件
-
索引文件
-
散列文件
-
文件存储资源分配和磁盘空闲空间管理策略¶
分配策略¶
-
静态分配(预分配)
-
在文件创建时就分配好所需的连续的存储空间。
-
优点:访问速度快,文件存储连续。
-
缺点:无法预知文件的未来大小,可能会出现分区浪费和预留分区的大小不够,难以动态调整。
-
-
动态分配
-
在使用时,按文件大小分配磁盘空间。
-
一般占有不连续的磁盘块。
-
分区大小¶
-
可变长、连续大分区
-
文件访问性能高。无内部碎片
-
难于重复使用存储空间。有外部碎片
-
分配方法:
-
首次适应
-
最佳适应
-
循环首次适应
-
-
-
块(固定大小)
-
灵活性强、不一定相邻
-
管理较复杂
-
文件存储方式¶
-
连续分配
-
一个文件占用磁盘上的一系列连续数据块
-
初始块号以及占用的块数量放在目录项中(例如,FCB)
-
优点
-
速度快 – 可以实现最小寻道时间和磁头移动
-
方便地访问文件中的任何块
-
-
缺点
-
类似于动态存储分配策略
- 外部碎片 – 可以压缩
-
文件增长困难
- 可以找一个大的连续块,并搬迁文件的位置
-

-
-
链接分配
-
每一个数据块包含一个指向下一个数据块的指针
-
查找时间复杂度为 \(O(n)\) , \(n\) 是文件的大小
-
指针的损坏能造成整个文件的丢失

-
-
索引分配
-
一个索引块包含一些指向数据块的指针
-
优点
-
支持随机读写
-
可靠性提高
-
-
缺点:
-
二次访问,性能不高
-
需要额外空间来保存索引节点
-
-
索引节点大小如何确定?
-
大索引节点:小文件时浪费空间
-
小索引节点:无法支持大文件
-

-
空闲空间管理¶
-
位图法
-
使用位图来表示磁盘块的使用情况
-
每个磁盘块对应一个位,0 表示空闲,1 表示已分配
-
优点:简单、易于实现
-
缺点:需要额外的存储空间来保存位图
-
-
链接表法
-
使用链表来管理空闲块
-
每个空闲块包含指向下一个空闲块的指针
-
优点:节省空间,动态分配
-
缺点:查找时间较长,指针损坏可能导致内存泄漏
-
-
索引法
-
使用索引块来管理空闲块
-
索引块包含指向空闲块的指针
-
优点:支持随机访问,查找时间较短
-
缺点:需要额外的存储空间来保存索引块
-

FAT 文件系统¶
-
采用链接分配方式
-
每个文件的目录项中包含一个指向 FAT 表的指针
-
FAT 表内容:
-
位图法记录空闲块
-
链表法记录文件数据地址
-
-
-
FAT12
-
FAT entry size: 12bits:可支持 4K 个表项
-
如果 cluster 大小为 32K,则可支持最大磁盘容量:128M
-
-
FAT16
-
FAT entry size: 16bits:可支持表项数:64K
-
如果 cluster 大小为 32K,则可支持最大磁盘容量 2G
-
-
FAT32
-
结构和 FAT12/16 完全不同
-
FAT 表项大小 32bits,28bit 用于保存 cluster 号
-
可支持最大磁盘容量: \((2^{28})* 32 \text{K}=8\text{T}\)
-
目录结构¶
-
目录文件的内容
-
目录下所有文件(含子目录)的属性信息:文件名,文件属性,文件内容存储的位置。
-
每个文件对应的信息成为一个目录项。也就是说目录文件的内容是目录项的集合。
-
-
目录项的内容
-
基本信息
-
文件名:在一个特定的目录中具有唯一性。
-
文件类型:例如文本文件,二进制文件,目标模块等。
-
文件组织:系统所支持的不同组织形式。
-
-
存储信息
-
地址信息:文件存放在磁盘的物理地址(例如:柱面号、磁道号或在磁盘上的块号)。两种方式:
-
起始地址
-
扇区地址数组
-
-
文件的大小,以字节、字或块计。
-
分配大小:文件的最大尺寸
-
-
存取控制信息
-
文件主:拥有文件的控制权。文件主能授予和取消其他用户对文件的存取权和改变这些权限。
-
访问控制:权限用户的口令和用户名等
-
允许的操作:控制读、写、执行和在网上的传输等。
-
-
使用信息
-
创建日期:文件首次存放在目录中的时间。
-
读时间:最后一次读文件的时间。
-
修改时间:最后一次更新、插入或删除的时间。
-
备份时间:文件最后一次备份到其他介质的时间。
-
-
-
间接式访问:如果对目录文件的属性进行修改,那么与该目录中文件的内容没有关系,实际上是:修改上级目录文件的内容。
-
目录结构
-
线性结构
-
Hash 表
-
树
-
流文件操作与系统调用间的关系¶

UNIX 文件系统¶
UNIX 文件索引结构¶
UNIX 索引节点如下
struct dinode {
ushort di_mode; // 文件控制模式
short di_nlink; // 文件的链接数
ushort di_uid; // 文件主用户标识数
ushort di_gid; // 文件主同组用户组标识数
off_t di_size; // 文件长度,以字节为单位
char di_addr[40]; // 地址索引表,存放文件的盘块号
time_t di_atime; // 文件最近一次访问时间
time_t di_mtime; // 文件最近一次修改时间
time_t di_ctime; // 文件创建时间
} dinode;
其中的 di_addr 字段是一个数组,存放文件的盘块号。每三个字节表示一个磁盘号;相当于能够表示 13 个磁盘号的数组
-
前 10 个表项是直接寻址。
-
直接存放文件前 10 磁盘块地址。
-
假定一个磁盘块 1K,那么可以表示 10K 以内的文件
-
如果文件大小可用 10 以内磁盘块保存,后面间接寻址不使用。
-
-
第 11 个表项是一级间接寻址。
-
表示的磁盘块不是直接存放文件的内容,而是存放直接寻址表项。即表明 \(1024/3\) 个磁盘块号,用于存放文件内容。
-
该级地址最多可表示文件大小 \(1024/3 \times 1024\)。
-
-
第 12 个表项是二级间接寻址。
-
表示的磁盘块不是直接存放文件,而是存放一级间接寻址表项。即表明 \(1024/3\) 个磁盘块号,用于存放一级寻址表项。
-
该级地址最多可表示文件大小 \(1024/3 \times 1024/3 \times 1024\)。
-
-
第 13 个表项是三级间接寻址。
-
表示的磁盘块不是直接存放文件,而是存放二级间接寻址表项。即表明 \(1024/3\) 个磁盘块号,用于存放二级寻址表项。
-
该级地址最多可表示文件大小 \(1024/3 \times 1024/3 \times 1024/3 \times 1024\)。
-

UNIX 目录系统结构¶
目录项如下
struct direct {
ino_t d_ino; // 文件的inode号
char d_name[NAME_MAX + 1]; // 文件名
};

UNIX 文件系统在磁盘的存储布局¶
-
分布概述:
-
一个物理磁盘能够被划分成多个逻辑分区,相当于一个逻辑盘。对每一个逻辑盘,盘块的物理地址是连续的。
-
可以把一个逻辑盘的存储地址空间看成一个一维的线性空间。
-
一个文件系统对应一个逻辑盘。一个物理磁盘上可以同时存在多个文件系统。
-

-
引导块:
-
在块号为 0 的引导块中包含操作系统的自举程序
-
该块不属于文件系统一部分。
-
有些逻辑分区上没有这一块的内容
-
-
超级块
-
用于存放文件系统的核心数据
-
各部分的盘块分布
-
空闲节点数,空闲节点表
-
空闲盘块数,空闲盘块索引
-
文件系统的类型、版本号,文件系统的状态
-
超级块在文件系统启动时,为了快速更新,被复制到内存一份。
-
磁盘上超级块需要定时更新
-
为了保证超级块的安全性,超级块在磁盘上有备份,用于文件系统恢复。
struct filsys { ushort s_isize; /* 磁盘索引节点区所占用的盘块总数 */ daddr_t s_fsize; /* 整个文件系统的盘块总数 */ Short s_nfree; /* 直接管理的空闲块数目 */ daddr_t s_free[NICFREE]; /* 空闲块索引表 */ Short s_ninode; /*直接管理的空闲索引节点数 */ ino_t s_inode[NICINOD]; /* 空闲I节点索引表 */ Char s_flock; /* 处理空闲块表时的加锁标志位 */ Char s_ilock; /* 处理空闲I节点表时的加锁标志位 */ Char s_fmod; /* 文件系统超级块被修改标志 */ daddr_t s_tfree; /* 空闲数据块总数 */ ino_t s_tinode; /* 空闲索引节点总数 */ } -
-
进程对换区:
-
连续磁盘区域。用于是换入/换出,作为内存的扩充。
-
该块不属于文件系统的一部分。
-
有些系统,如 Linux,可以以单独的一个逻辑盘作为交换区
-
UNIX 文件系统对空闲磁盘块的管理¶
-
所有空闲磁盘块以多叉(50)树的方式组织。
-
树的每个叶子节点对应一个空闲磁盘块
-
树的每个中间节点存储在一个空闲磁盘块中,其内容表示下层的多(50)个磁盘块号。

UNIX 文件控制块(FCB)¶
-
内存中的目录结构树
-
必要性:
-
访问一个文件时,系统要从根目录或当前目录出发,循序读取和搜索各级目录文件磁盘 I 节点,索引结构等,找到文件物理块号后再存取文件数据。
-
涉及多次磁盘操作,速度慢。
-
-
技术思路:
-
在内存中,保存磁盘上的目录结构树的副本
-
内存中并不是完整的副本,而是一部分:
-
内存容量的限制
-
根据局部性原理,保存一部分就能起到很好的效果
-
-
-
-
文件控制块
-
文件被打开一次,就分配一个相应的文件控制块。
-
用于保存文件打开后产生一些动态信息。
-
存在的必要(为何动态信息不存放在内存索引节点中)
-
内存索引节点主要存放文件相关的静态信息
-
便于实现一个文件同时被多个进程打开。
-
struct file { char f_flag; /* 操作方式,如写、读、追加写等 */ cnt_t f_count; /* 共享该file结构的进程数 */ union { struct inode *f_uinode;/* 指向内存I节点 */ struct file *f_unext; /* 空闲file的链接指针 */ } f_up; union { off_t f_off; /* 读写位置指针 */ } f_un; }; -
打开文件表¶
-
进程的打开文件表
-
每个进程都有一个打开文件表,保存该进程打开的所有文件的文件控制块。
-
通过该表,进程可以访问其打开的文件。
-
子进程继承父进程打开的文件。
-
-
系统的打开文件表
-
系统中所有进程共享一个打开文件表,保存所有打开文件的文件控制块。
-
通过该表,系统可以管理所有进程打开的文件。
-
文件搜索¶
-
相对路径搜索
-
绝对路径搜索
虚拟文件系统¶
-
背景和目标
-
Linux 需要支持多种文件系统。
-
屏蔽下层的具体文件系统,向上提供统一的文件服务。
-
-
主要思路
-
在具体文件系统和操作系统的文件服务接口间实现虚拟层
-
对下层的具体文件系统进行统一封装和细节屏蔽
-
对上层提供统一的文件服务接口
-
-
核心实现:
-
对一些文件系统的具体实现,如果实现与具体文件系统无关,把这些实现统一到 VFS 层。如:一些结构的缓冲,索引节点
-
当一个进程调用文件系统例程时,内核调用 VFS 函数 (这个函数是和具体结构无关的),并将这个调用传递给物理文件系统中的相应函数,该函数和具体的物理结构有关。
-

可靠性问题¶
-
系统启动时的一致性检查
-
日志文件系统