技术编程|低调的 Linux 文件系统家族( 八 )



技术编程|低调的 Linux 文件系统家族
本文插图

我们使用 shell 、P1 和 P2 来描述一下父进程、子进程、子进程的关系 。 Shell 首先生成 P1 , P1 的数据结构就是 Shell 的一个副本 , 因此两者都指向相同的打开文件描述符的表项 。 当 P1 运行完成后 , Shell 的文件描述符仍会指向 P1 文件位置的打开文件描述 。 然后 Shell 生成了 P2 , 新的子进程自动继承文件的读写位置 , 甚至 P2 和 Shell 都不知道文件具体的读写位置 。
上面描述的是父进程和子进程这两个 相关 进程 , 如果是一个不相关进程打开文件时 , 它将得到自己的打开文件描述符表项 , 以及自己的文件读写位置 , 这是我们需要的 。
因此 , 打开文件描述符相当于是给相关进程提供同一个读写位置 , 而给不相关进程提供各自私有的位置 。
?
i - node 包含三个间接块的磁盘地址 , 它们每个指向磁盘块的地址所能够存储的大小不一样 。
Linux Ext4 文件系统
为了防止由于系统崩溃和电源故障造成的数据丢失 , ext2 系统必须在每个数据块创建之后立即将其写入到磁盘上 , 磁盘磁头寻道操作导致的延迟是无法让人忍受的 。 为了增强文件系统的健壮性 , Linux 依靠 日志文件系统, ext3 是一个日志文件系统 , 它在 ext2 文件系统的基础之上做了改进 , ext4 也是 ext3 的改进 , ext4 也是一个日志文件系统 。 ext4 改变了 ext3 的块寻址方案 , 从而支持更大的文件和更大的文件系统大小 。 下面我们就来描述一下 ext4 文件系统的特性 。
具有记录的文件系统最基本的功能就是 记录日志, 这个日志记录了按照顺序描述所有文件系统的操作 。 通过顺序写出文件系统数据或元数据的更改 , 操作不受磁盘访问期间磁盘头移动的开销 。 最终 , 这个变更会写入并提交到合适的磁盘位置上 。 如果这个变更在提交到磁盘前文件系统宕机了 , 那么在重启期间 , 系统会检测到文件系统未正确卸载 , 那么就会遍历日志并应用日志的记录来对文件系统进行更改 。
Ext4 文件系统被设计用来高度匹配 ext2 和 ext3 文件系统的 , 尽管 ext4 文件系统在内核数据结构和磁盘布局上都做了变更 。 尽管如此 , 一个文件系统能够从 ext2 文件系统上卸载后成功的挂载到 ext4 文件系统上 , 并提供合适的日志记录 。
日志是作为循环缓冲区管理的文件 。 日志可以存储在与主文件系统相同或者不同的设备上 。 日志记录的读写操作会由单独的 JBD(Journaling Block Device) 来扮演 。
JBD 中有三个主要的数据结构 , 分别是 「log record(日志记录)、原子操作和事务」 。 一个日志记录描述了一个低级别的文件系统操作 , 这个操作通常导致块内的变化 。 因为像是 write 这种系统调用会包含多个地方的改动 --- i - node 节点 , 现有的文件块 , 新的文件块和空闲列表等 。 相关的日志记录会以原子性的方式分组 。 ext4 会通知系统调用进程的开始和结束 , 以此使 JBD 能够确保原子操作的记录都能被应用 , 或者一个也不被应用 。 最后 , 主要从效率方面考虑 , JBD 会视原子操作的集合为事务 。 一个事务中的日志记录是连续存储的 。 只有在所有的变更一起应用到磁盘后 , 日志记录才能够被丢弃 。
由于为每个磁盘写出日志的开销会很大 , 所以 ext4 可以配置为保留所有磁盘更改的日志 , 或者仅仅保留与文件系统元数据相关的日志更改 。 仅仅记录元数据可以减少系统开销 , 提升性能 , 但不能保证不会损坏文件数据 。 其他的几个日志系统维护着一系列元数据操作的日志 , 例如 SGI 的 XFS 。
/proc 文件系统
另外一个 Linux 文件系统是 /proc (process) 文件系统
它的主要思想来源于贝尔实验室开发的第 8 版的 UNIX , 后来被 BSD 和 System V 采用 。


推荐阅读