
这张图详细展示了Linux内核4.10版本的完整存储栈架构,从用户空间到物理设备的完整I/O路径。
整体架构概览
Linux存储栈采用分层架构,每层都有明确的职责:
用户空间应用 → VFS → 文件系统 → 页面缓存 → 块层 → I/O调度 → 设备驱动 → 物理设备
1. 用户空间 (Userspace)
系统调用接口
- vfs_writev, vfs_read, ...:虚拟文件系统提供的系统调用
- 用户空间文件系统:如sshfs,通过FUSE实现
关键知识点:
- 应用程序通过系统调用进入内核态
- 所有文件操作首先经过VFS层
- FUSE允许在用户空间实现文件系统
2. 虚拟文件系统 (VFS - Virtual File System)
作用
- 提供统一的文件操作接口,抽象不同文件系统的差异
- 实现通用的文件系统功能(目录缓存、inode缓存等)
支持的文件系统类型
块设备文件系统
- ext2/ext3/ext4:Linux传统文件系统
- XFS:高性能日志文件系统
- Btrfs:带快照和校验的现代文件系统
网络文件系统
- NFS:网络文件系统
- CIFS:Common Internet File System
- Ceph:分布式文件系统
伪文件系统
- proc:进程信息文件系统
- sysfs:系统设备信息
- tmpfs:临时文件系统
特殊用途文件系统
- FUSE:用户空间文件系统
- 其他专用文件系统
3. 页面缓存 (Page Cache)
功能
- 缓存文件数据,减少磁盘访问
- 使用LRU等算法管理缓存页面
- 处理匿名页(anonymous pages)和文件页
工作机制
c
// 页面缓存核心数据结构
struct address_space {
struct inode *host; // 所属inode
struct radix_tree_root page_tree; // 页面树
// ...
};
4. 块I/O层 (Block I/O Layer)
BIO结构体 (Block I/O)
c
struct bio {
sector_t bi_sector; // 磁盘扇区
unsigned int bi_size; // 数据大小
struct bio_vec *bi_io_vec; // bio向量
unsigned int bi_idx; // 当前向量索引
// ...
};
struct bio_vec {
struct page *bv_page; // 物理页面
unsigned int bv_len; // 长度
unsigned int bv_offset; // 偏移
};
BIO处理流程
- 文件系统将I/O请求转换为BIO
- BIO包含要读写的磁盘位置和内存位置
- 支持分散/聚集I/O(scatter-gather)
5. I/O调度层 (I/O Scheduler)
调度器类型
CFQ (Completely Fair Queuing)
- 为每个进程维护独立的I/O队列
- 公平分配I/O带宽
- 适合桌面系统
Deadline
- 每个请求有截止时间
- 防止请求饥饿
- 适合数据库应用
NOOP
- 简单的FIFO队列
- 不进行重新排序
- 适合SSD和智能存储设备
多队列调度器 (blk-mq)
- 为多核系统设计
- 减少锁竞争
- 软件队列 + 硬件分发队列
6. 设备映射层 (Device Mapper)
功能
- 提供逻辑卷管理
- 支持快照、条带化、镜像等
目标设备
- dm-multipath:多路径I/O
- dm-thin:精简配置
- dm-crypt:设备加密
7. SCSI子系统
SCSI中间层 (SCSI Mid Layer)
- 提供统一的SCSI设备抽象
- 处理SCSI命令和响应
SCSI上层驱动
- sd :SCSI磁盘驱动 (
/dev/sda,/dev/sdb) - sr :SCSI光盘驱动 (
/dev/sr0) - st:SCSI磁带驱动
- sg:通用SCSI设备
其他块设备驱动
- virtio_blk:虚拟化块设备
- nbd:网络块设备
- loop:回环设备
- mmcblk:MMC/SD卡设备
- ubd:用户模式Linux块设备
8. 传输类和sysfs
传输类
- scsi_transport_fc:光纤通道
- scsi_transport_sas:SAS接口
- 其他传输协议
sysfs集成
- 通过
/sys/class/scsi_host/等路径暴露设备属性 - 提供统一的管理接口
9. 底层设备驱动
SCSI低层驱动 (LLDs)
- libata:SATA/AHCI驱动
- mpt3sas:LSI SAS 12Gbps驱动
- qla2xxx:QLogic光纤通道
- virtio_scsi:虚拟化SCSI
其他存储接口
- NVMe:非易失性内存快速
- UFS:通用闪存存储(移动设备)
- 各种HBA卡驱动
10. 物理设备层
存储介质类型
- HDD:机械硬盘
- SSD:固态硬盘
- DVD/CD:光盘
- SD/MMC:闪存卡
接口技术
- SAS:串行SCSI
- SATA:串行ATA
- PCIe:高速外围组件互联
- FC:光纤通道
完整I/O路径示例
读取文件的数据流
应用程序read() → VFS → 文件系统 → 页面缓存检查 →
↓ (缓存未命中)
创建BIO → I/O调度器 → 设备驱动 → SCSI命令 → 物理设备
↑
数据返回 → DMA到内存 → 完成中断 → 唤醒进程
写入文件的数据流
应用程序write() → VFS → 文件系统 → 页面缓存 →
↓ (延迟写入)
标记页面为脏 → 定期刷回或显式sync
↓ (立即写入)
创建BIO → I/O调度 → 设备驱动 → 物理设备
关键技术和优化
1. 多队列块层 (blk-mq)
- 解决多核系统的锁竞争问题
- 软件队列处理I/O准备
- 硬件队列直接映射到CPU核心
2. 直接I/O (Direct I/O)
- 绕过页面缓存
- 适合数据库等自缓存应用
- 使用O_DIRECT标志
3. 异步I/O
- 非阻塞I/O操作
- 提高并发性能
- 使用libaio或内核AIO
4. 内存映射 (mmap)
- 将文件直接映射到进程地址空间
- 减少数据拷贝
- 按需分页
性能调优要点
I/O调度器选择
- HDD:CFQ或Deadline
- SSD:NOOP或Deadline
- NVMe:使用多队列(none调度器)
队列深度优化
- 调整
/sys/block/sdX/queue/nr_requests - 增加队列深度提高并行性
预读优化
- 调整
/sys/block/sdX/queue/read_ahead_kb - 适合顺序读场景
现代发展趋势
1. NVMe over Fabrics
- 远程直接访问NVMe设备
- 支持RDMA、TCP等传输
2. computational Storage
- 在存储设备上执行计算
- 减少数据传输
3. 持久内存
- 字节寻址的持久存储
- 新的编程模型要求
这个存储栈架构体现了Linux内核设计的模块化、可扩展性思想,每层都可以独立发展和优化,同时保持清晰的接口和职责分离。理解这个架构对于系统性能调优、存储问题排查和存储系统开发都至关重要。