文件系统
文件系统是操作系统中管理持久性数据的子系统,提供数据存储和访问功能,可以提供组织、检索、读写访问数据功能。在没有文件系统时,我们在计算机上操作的数据无法有效保存,在计算机关机再重启时数据就丢失了。大多数计算机系统都有文件系统,我们常用的谷歌也是一个文件系统,支持分布式应用的数据管理,可以支持系统监控、故障检测、故障容忍和自动恢复,提供很高的可靠性。
文件系统的概念
文件系统的主要目的是实现对文件的按名存取(从用户的角度来看),而文件管理实际上是对辅助存储空间的管理。
文件是具有符号名,由字节序列构成的数据项集合。
- 文件是文件系统的基本数据单位
- 文件名是文件的标识符号
文件系统的功能
分配文件磁盘空间
- 管理文件块(位置和顺序)
- 管理空闲空间(位置)
- 分配算法(策略)
管理文件集合
- 定位 文件及其内容
- 命名 通过名字找到文件
- 文件系统结构 文件组织方式
确保数据可靠和安全
- 安全 多层次保护数据安全
- 可靠 持久保存文件,避免系统崩溃、攻击
文件属性
名称、类型、位置、大小、保护、创建者、创建时间、最近修改时间等
文件都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方;而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块。
文件头 文件系统元数据中的文件信息
- 文件属性
- 文件存储位置和顺序
文件描述符
进程访问文件数据前必须先打开文件,内核跟踪所有打开的文件。
操作系统在打开文件表中维护的打开文件状态和信息。文件描述符是打开文件的标识,由于打开文件表中文件数目和文件系统中文件有数量级差别,所以另外维护文件描述符而不是直接引用文件标识。
文件指针
- 最近一次读写位置
- 每个进程分别维护自己的打开文件指针
文件打开计数
- 当前打开文件的次数
- 最后一个进程关闭文件时,将其从打开文件表中移除
文件的磁盘位置
缓存数据访问信息
访问权限
- 每个进程的文件访问模式信息(以什么方式访问)
文件的用户视图和系统视图
- 文件的用户视图
- 持久的数据结构
- 系统访问接口
- 字节序列的集合(Unix)
- 系统不关心存储在磁盘上的数据结构
- 操作系统的文件视图
- 数据块的集合
- 数据块是逻辑存储单元,而扇区是物理存储单元
- 块大小和扇区大小通常是不同的,通常是几个扇区构成一个数据块
用户视图到系统视图的转换
文件系统中最小基本单位为数据块,磁盘最小访问单位为扇区。
- 进程读文件
- 获取字节所在的数据块(数据块是逻辑存储单位)
- 返回数据块内对应部分
- 进程写文件
- 获取数据块
- 修改数据块中对应部分
- 写回数据块
访问模式
进程如何访问文件
顺序访问
- 按字节依次读取
- 大多数文件访问都是顺序访问
随机访问
- 从中间读写
- 不常用,但很重要
- 虚拟内存中把内存页存储在文件
索引访问
- 依据数据特征索引
- 通常操作系统不完整提供索引访问
- 数据库是建立在索引内容的磁盘访问之上
文件内部结构
- 无结构
- 单词、字节序列
- 简单记录结构
- 分列
- 固定长度
- 可变长度
- 复杂结构
- 格式化的文档(PDF Word),应用程序可根据文档格式对文件进行识别
- 可执行文件
文件共享和访问控制
多用户系统中的文件共享是很有必要的
- 访问控制
- 每个用户能够获得哪些文件的哪些访问权限
- 访问模式:读、写、执行、删除、列表
- 文件访问控制列表(ACL)
- <文件实体, 权限>
- Unix模式
- <用户|组|所有人, 读|写|可执行>
- 用户标识ID 识别用户,表明每个用户所允许的权限及保护模式
- 组标识ID 允许用户组成组,并指定了组访问权限
语义一致性
规定多进程如何同时访问共享文件
- 与同步算法相似
- 因磁盘I/O和网络延迟而设计简单
Unix文件系统(UFS)语义
- 对打开文件的写入内容立即对其他打开同一文件的其他用户可见
- 共享文件指针允许多用户同时读取和写入文件
会话语义
- 写入内容只有当文件关闭时可见( 效率低)
读写锁
- 一些操作系统和文件系统提供该功能
目录
分层文件系统
目录操作
操作系统应该只允许内核修改目录,以确保映射的完整性。应用程序通过系统调用访问目录。
- 搜索文件
- 创建文件
- 删除文件
- 列目录
- 重命名文件
- 遍历路径
目录实现
文件名的线性列表 包含了指向数据块的指针
- 编程简单
- 执行搜索耗时
哈希表
- 减少目录搜索时间
- 冲突 两个文件名的哈希值相同
- 固定大小
文件别名
硬链接中文件的删除操作在删除最后一个文件项时才删除。
名字解析(路径遍历)
名字解析是指将逻辑名字转换成物理资源(文件)
有以下两种名字解析的方式
- 遍历文件目录直到找到目标文件
- 根据路径名在文件系统中找到实际文件位置
比如:当解析 "/bin/ls"
时
- 读取根目录的文件头(在磁盘固定位置)
- 读取根目录的数据块,搜索 bin 项
- 读取 bin 的文件头
- 读取 bin的数据块,搜索 ls项
- 读取 ls 的文件头
当前工作目录(PWD)
- 每个进程都会指向一个文件目录用于解析文件名(可以提高效率)
- 允许用户指定相对路径来代替绝对路径 如
PWD="/bin”
能够解析“ls”
文件系统挂载
文件系统种类
- 磁盘文件系统
- 文件存储在数据存储设备上 如磁盘
- FAT,NTFS,ext2/3, ISO9660
- 数据库文件系统
- 文件特征是可被寻址辨识的
- WinFS
- 日志文件系统
- 记录文件系统的修改/事件
- 以原子形式记录访问
- 网络/分布式文件系统(通过网络访问)
- NFS、SMB、AFS、GFS
- 特殊/虚拟文件系统
- 管道
网络/分布式文件系统
文件可以通过网络被共享
- 文件处于远程服务器
- 客户端远程挂载服务器文件系统
- 标准系统文件访问被转换成远程访问
- 标准文件共享协议
- NFS for Unix
- CIFS for Windows
分布式文件系统的挑战
- 客户端和客户端上的用户辨别起来很复杂
- NFS 不安全
- 一致性问题
- 错误处理
虚拟文件系统
文件系统的实现
目的
- 对所有不同文件系统的抽象,多种文件系统,对上提供一致的访问接口
功能
- 提供相同的文件和文件系统接口
- 管理所有文件和文件系统关联的数据结构
- 高效查询例程,遍历文件系统
- 与特定文件系统模块的交互
文件系统基本数据结构
- 文件卷控制块(Unix superblock)
- 每个文件系统一个
- 文件系统详细信息
- 块、块大小、空余块、计数/指针
- 文件控制块(Unix vnode or inode)
- 每个文件一个
- 文件详细信息
- 访问权限、拥有者、大小、数据块位置
- 目录项(Linux dentry)
- 每个目录项一个(目录和文件)
- 将目录项数据结构及树型布局编码成树型数据结构
- 指向文件控制块、父目录、子目录
文件系统的组织视图
文件系统的存储结构
- 文件系统数据结构
- 卷控制块(superblock 每个文件系统一个)
- 文件控制块(inode 每个文件一个)
- 目录节点(dentry 每个目录项一个)
- 以上都持久存储在外存中
- 存储设备的数据块中
- 当需要时加载进内存
- 卷控制模块 当文件系统挂载时进入内存
- 文件控制块 当文件被访问时候进入内存
- 目录节点 在遍历一个文件路径时进入内存
文件系统的存储视图
文件缓存
多种磁盘缓存位置
文件缓存有数据块缓存和页缓存两种方式。
数据块缓存
- 数据块按需进入内存
- 提供read()操作
- 预读 预先读取后面的数据块
- 数据块使用后被缓存
- 假设数据将会再次用到
- 写操作可能被缓存和延迟写入
页缓存
- 虚拟页式存储
- 在虚拟地址空间中虚拟页面可映射到本地外存文件中
- 文件数据块的页缓存
- 在虚拟内存中文件数据块被映射成页
- 文件的读/写操作被转换成对内存的访问
- 可能导致缺页或被设置为脏页
- 会带来问题 页面置换算法需要协调虚拟存储和页缓存间的页面数
文件系统中打开文件的数据结构
- 文件描述符
- 每个被打开的文件都有一个文件描述符
- 文件状态信息 目录项、当前文件指针、文件操作设置
- 打开文件表
- 每个进程都有一个打开文件表
- 一个系统级的打开文件表
- 有文件被打开, 文件卷就不能被卸载
打开文件锁
一些文件系统提供文件锁 用于协调多进程的文件访问
- 强制 根据锁保持情况和访问需求确定是否拒绝访问
- 劝告 进程可以查找锁的状态来决定怎么做
文件分配
文件大小
- 大多数文件都很小
- 需要对小文件提供很好的支持
- 数据块空间不能太大
- 一些文件非常大
- 必须支持大文件(64位文件偏移)
- 大文件访问需要高效
分配方式
- 连续分配
- 链式分配
- 索引分配
指标
- 存储效率 外部碎片(连续分配),忽略内碎片
- 读写性能 访问速度
连续分配
链式分配
索引分配
大文件的索引分配
UFS多级索引分配
(UFS Unix File System)
- 文件头包含13个指针
- 10个指针指向数据块
- 第1个指针指向索引块
- 第12个指针指向二级索引块
- 第13个指针指向三级索引块
- 效果
- 提高了文件大小限制阈值
- 动态分配数据块 文件扩展很容易
- 小文件开销小
- 只为大文件分配间接索引块 大文件在访问数据块时需要大量查询