文件系统与文件读取全过程:从磁盘到内存
文件系统概述
文件系统是操作系统用于组织、存储和管理计算机数据的一种机制,它定义了文件和目录的命名、存储和检索方式。常见的文件系统包括Ext4(Linux)、NTFS(Windows)和APFS(macOS)等。
文件系统核心组件
- 超级块(Superblock):
• 存储文件系统的元信息(如大小、块大小、空闲块数等)• 通常位于磁盘开头 - inode结构:
• 每个文件/目录对应一个inode• 包含文件元数据(权限、大小、时间戳等)和数据块指针 - 目录项(Dentry):
• 将文件名映射到inode• 形成目录树结构 - 数据块(Data Blocks):
• 实际存储文件内容的磁盘区域
文件读取全过程(含inode和中断)
让我们以一个进程读取文件/home/user/test.txt为例,详细说明从磁盘到内存的全过程:
1. 用户空间发起读取请求
// 用户程序调用read系统调用
int fd = open("/home/user/test.txt", O_RDONLY);
char buf[1024];
read(fd, buf, 1024);
• 触发read()系统调用,CPU从用户态切换到内核态
2. 路径解析(路径名→inode)
- VFS层处理:
• 内核通过虚拟文件系统(VFS)接口接收请求• 解析路径"/home/user/test.txt"为inode - 目录项缓存查找:
• 首先检查dentry缓存(dcache)是否缓存了该路径• 如果命中,直接获取对应的inode - 逐级目录查找:
• 未命中则从根目录开始逐级查找: ◦ 查找"/“目录的inode(通常inode号为2) ◦ 在”/"的数据块中查找"home"对应的inode ◦ 在"home"目录中查找"user"对应的inode ◦ 最后在"user"目录中查找"test.txt"的inode
3. 获取文件inode
- inode缓存查找:
• 检查inode缓存是否已缓存该文件的inode• 如果未缓存,从磁盘读取inode信息 - 磁盘读取inode:
• 根据文件系统布局计算inode位置: ◦ 超级块中包含inode表起始位置 ◦ inode号用于索引inode表• 触发磁盘I/O操作读取inode:
磁盘操作流程:
1. 磁头移动到正确磁道(寻道时间)
2. 等待扇区旋转到磁头下(旋转延迟)
3. 读取inode数据(传输时间)
• 读取过程中,进程可能被阻塞,CPU调度其他进程运行
4. 权限检查
• 检查进程是否有该文件的读权限
• 检查文件是否被锁定
5. 确定数据块位置
• 从inode中提取数据块指针:
• 直接指针:指向前12个数据块(Ext4)
• 间接指针:指向包含更多块指针的块
• 双重间接指针:两级间接寻址
• 三重间接指针:三级间接寻址
6. 读取文件数据
- 页缓存检查:
• 首先检查页缓存(page cache)中是否已缓存所需数据• 如果命中(缓存命中),直接返回数据 - 触发磁盘I/O(缓存未命中):
• 准备I/O请求: ◦ 根据文件块号计算磁盘物理位置(柱面/磁头/扇区) ◦ 构造bio结构(块I/O请求)• 通过块设备层提交请求:
中断处理流程:
1. 磁盘控制器收到请求,DMA引擎将数据直接传输到内存
2. 传输完成后,磁盘控制器触发硬件中断
3. CPU保存当前上下文,跳转到中断处理程序
4. 内核的中断处理程序确认I/O完成
5. 唤醒等待该I/O的进程
6. 恢复被中断的上下文
- 数据拷贝到用户空间:
• 将页缓存中的数据拷贝到用户提供的缓冲区buf• 如果实现了零拷贝技术(如sendfile),可能避免这次拷贝
7. 系统调用返回
• 返回实际读取的字节数
• CPU从内核态切换回用户态
• 用户程序继续执行
关键数据结构交互
性能优化技术
- 预读(Read-ahead):
• 基于访问模式预测并提前读取后续数据块• 减少后续读取的延迟 - 延迟分配:
• 写入时延迟分配实际磁盘块• 提高写入性能并减少碎片 - 日志(Journaling):
• 记录元数据变更,确保崩溃后快速恢复• Ext4使用更高效的写时复制(COW)技术 - 异步I/O:
• 允许进程在I/O进行时继续执行• 提高并发性能
文件系统通过精心设计的层次结构和缓存机制,将缓慢的磁盘I/O操作对用户体验的影响降到最低,同时保证了数据的完整性和安全性。从inode查找、权限检查到实际的磁盘读取和中断处理,每个步骤都体现了操作系统设计的精妙之处。
本文来自博客园,作者:NeoLshu,转载请注明原文链接:https://www.cnblogs.com/neolshu/p/19120444

浙公网安备 33010602011771号