土法炼钢兴趣小组的算法知识备份

【操作系统百科】VFS I/O 路径全景

文章导航

分类入口
os
标签入口
#vfs#read-write#io-path#page-cache#direct-io

目录

read(fd, buf, 4096) 看似简单,内核旅程却穿过 VFS → 文件系统 → 页缓存 → 块层 → 设备驱动至少五层。理解全路径是性能调优的前提。

一、先看图

flowchart TD
    SYSCALL[read / write 系统调用] --> FD[file 查找<br/>fdget]
    FD --> FOP[f_op->read_iter<br/>/ write_iter]
    FOP --> CACHE{页缓存<br/>命中?}
    CACHE -- 命中 --> COPY[copy_to_user]
    CACHE -- miss --> FS[文件系统<br/>iomap / readpage]
    FS --> BIO[bio 提交<br/>块层]
    BIO --> DISK[设备驱动<br/>NVMe / SCSI]
    DISK --> IRQ[完成中断]
    IRQ --> WAKEUP[唤醒进程]

    FOP -->|O_DIRECT| DIO[直接 I/O<br/>跳过页缓存]
    DIO --> BIO

    classDef hot fill:#f0883e22,stroke:#f0883e,color:#adbac7;
    classDef cache fill:#3fb95022,stroke:#3fb950,color:#adbac7;
    classDef hw fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    class SYSCALL,FD,FOP hot
    class CACHE,COPY,FS cache
    class BIO,DISK,IRQ,WAKEUP,DIO hw

二、系统调用入口

// fs/read_write.c
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    // fdget → file → vfs_read → f_op->read_iter
}

核心路径:ksys_read()vfs_read()new_sync_read()call_read_iter()

read_iter / write_iter 是现代 VFS 接口,使用 struct iov_iter 描述用户缓冲区。

三、iov_iter 与向量化 I/O

struct iov_iter {
    u8 iter_type;     // ITER_IOVEC, ITER_BVEC, ITER_PIPE, ITER_UBUF
    size_t count;
    // ...
};

统一了 readv/writev、splice、sendfile、io_uring 等不同缓冲区类型。

四、页缓存命中路径

4.1 generic_file_read_iter

// mm/filemap.c
ssize_t generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
    if (iocb->ki_flags & IOCB_DIRECT)
        return mapping->a_ops->direct_IO(iocb, iter);
    return filemap_read(iocb, iter, 0);
}

4.2 filemap_read

查找页缓存(filemap_get_pages)→ 命中则 copy_page_to_iter() → 零 I/O。

miss → 调用 readaheadreadpage → 向块层提交 bio。

五、直接 I/O(O_DIRECT)

跳过页缓存,直接构造 bio → 块层 → 设备。

条件:

iomap 框架(fs/iomap/direct-io.c)统一了 ext4/XFS/btrfs 的直接 I/O 路径。

六、iomap 框架

取代了旧的 buffer_head 路径:

// include/linux/iomap.h
struct iomap_ops {
    int (*iomap_begin)(struct inode *, loff_t, loff_t, unsigned, struct iomap *, struct iomap *);
    int (*iomap_end)(struct inode *, loff_t, loff_t, ssize_t, unsigned, struct iomap *);
};

文件系统只需实现 iomap_begin/iomap_end → iomap 框架处理页缓存、直接 I/O、DAX。

七、写路径

7.1 缓冲写

generic_file_write_iter()generic_perform_write() → 写到页缓存 → 标记 dirty → 后台 writeback。

7.2 fsync

vfs_fsync()file->f_op->fsync() → 文件系统 flush dirty pages + journal → 返回。

7.3 writeback

内核 flusher 线程定期把 dirty page 写回:

八、块层提交

页缓存 miss 或 writeback → 构造 struct biosubmit_bio() → I/O 调度器 → 设备驱动。

flowchart LR
    BIO[bio] --> SCHED[I/O 调度器<br/>mq-deadline / bfq / none]
    SCHED --> DISPATCH[dispatch queue]
    DISPATCH --> DRIVER[NVMe / SCSI<br/>设备驱动]
    classDef blk fill:#a371f722,stroke:#a371f7,color:#adbac7;
    class BIO,SCHED,DISPATCH,DRIVER blk

九、fsnotify 插桩

VFS 在关键操作点插入 fsnotify hook:

// 写完成后
fsnotify_modify(file);
// 打开时
fsnotify_open(file);

inotify / fanotify 通过这些 hook 收到通知。

十、小结


参考文献

工具


上一篇FUSE 下一篇POSIX AIO 与 libaio

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-08 · os

【操作系统百科】VFS 四层抽象

Linux 的一切皆文件靠 VFS 实现——superblock、inode、dentry、file 四层抽象加 ops 表。本文讲 VFS 核心数据结构、dcache、inode cache、RCU lookup,以及文件系统如何插入 VFS。

2026-04-26 · os

【操作系统百科】页缓存深入(VM 视角)

页缓存是 Linux I/O 的灵魂缓冲层。本文从 VM 视角讲 address_space、radix 到 XArray 改造、folio 抽象、readahead 策略、writeback 与 dirty throttling、memcg 对页缓存的约束。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。


By .