当前位置: 首页 > news >正文

Linux I/O 访问架构深入分析

Linux I/O 访问架构深入分析

目录

  • 概述
  • I/O 架构层次
  • 核心数据结构
  • I/O 处理流程
  • VFS 虚拟文件系统
  • 块设备I/O
  • 字符设备I/O
  • 内存映射I/O
  • 异步I/O机制
  • I/O调度器
  • 调试工具与方法
  • 性能优化策略

概述

Linux I/O 系统是一个多层次、高度抽象的架构,旨在为应用程序提供统一的文件访问接口,同时支持各种不同类型的存储设备和文件系统。

用户空间应用程序
系统调用接口
虚拟文件系统 VFS
具体文件系统
页缓存层
块设备层
设备驱动层
硬件设备
字符设备
设备驱动
硬件设备

I/O 架构层次

架构分层表

层次组件主要功能关键数据结构
用户空间应用程序文件操作API调用FILE*, fd
系统调用内核入口参数验证、权限检查system_call table
VFS层虚拟文件系统统一文件接口抽象inode, dentry, file
文件系统层ext4/xfs/btrfs等具体文件系统实现super_block, inode_operations
页缓存层Page CacheI/O缓存和优化address_space, page
块设备层Block Layer块设备I/O管理bio, request, request_queue
设备驱动层驱动程序硬件抽象接口block_device_operations
硬件层存储设备物理存储介质硬件寄存器、DMA

核心数据结构

文件系统核心结构

/* 文件结构体 - 表示一个打开的文件 */
struct file {struct path             f_path;         /* 文件路径 */struct inode           *f_inode;        /* 关联的inode */const struct file_operations *f_op;     /* 文件操作函数表 */spinlock_t              f_lock;         /* 文件锁 */atomic_long_t           f_count;        /* 引用计数 */unsigned int            f_flags;        /* 文件标志 */fmode_t                 f_mode;         /* 文件模式 */struct mutex            f_pos_lock;     /* 位置锁 */loff_t                  f_pos;          /* 文件位置 */struct fown_struct      f_owner;        /* 文件所有者 */const struct cred      *f_cred;         /* 文件凭证 */struct file_ra_state    f_ra;           /* 预读状态 */u64                     f_version;      /* 版本号 */void                   *private_data;   /* 私有数据 */struct address_space   *f_mapping;      /* 地址空间映射 */
};/* inode结构体 - 文件系统中的文件节点 */
struct inode {umode_t                 i_mode;         /* 文件类型和权限 */unsigned short          i_opflags;     /* 操作标志 */kuid_t                  i_uid;          /* 用户ID */kgid_t                  i_gid;          /* 组ID */unsigned int            i_flags;       /* 文件系统标志 */const struct inode_operations *i_op;   /* inode操作 */struct super_block     *i_sb;          /* 超级块 */struct address_space   *i_mapping;     /* 地址空间 */void                   *i_security;    /* 安全模块 */unsigned long           i_ino;         /* inode号 */dev_t                   i_rdev;        /* 设备号 */loff_t                  i_size;        /* 文件大小 */struct timespec64       i_atime;       /* 访问时间 */struct timespec64       i_mtime;       /* 修改时间 */struct timespec64       i_ctime;       /* 创建时间 */spinlock_t              i_lock;        /* inode锁 */unsigned short          i_bytes;       /* 字节数 */u8                      i_blkbits;     /* 块大小位数 */blkcnt_t                i_blocks;      /* 块数 */const struct file_operations *i_fop;   /* 文件操作 */struct hlist_head       i_dentry;      /* dentry链表 */struct rw_semaphore     i_rwsem;       /* 读写信号量 */union {struct pipe_inode_info  *i_pipe;   /* 管道信息 */struct cdev             *i_cdev;   /* 字符设备 */char                    *i_link;   /* 符号链接 */unsigned                i_dir_seq; /* 目录序列号 */};
};/* 文件操作函数表 */
struct file_operations {struct module *owner;loff_t (*llseek)(struct file *, loff_t, int);ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);ssize_t (*read_iter)(struct kiocb *, struct iov_iter *);ssize_t (*write_iter)(struct kiocb *, struct iov_iter *);int (*iopoll)(struct kiocb *kiocb, bool spin);int (*iterate)(struct file *, struct dir_context *);int (*iterate_shared)(struct file *, struct dir_context *);__poll_t (*poll)(struct file *, struct poll_table_struct *);long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long);long (*compat_ioctl)(struct file *, unsigned int, unsigned long);int (*mmap)(struct file *, struct vm_area_struct *);unsigned long mmap_supported_flags;int (*open)(struct inode *, struct file *);int (*flush)(struct file *, fl_owner_t id);int (*release)(struct inode *, struct file *);int (*fsync)(struct file *, loff_t, loff_t, int datasync);int (*fasync)(int, struct file *, int);int (*lock)(struct file *, int, struct file_lock *);ssize_t (*sendpage)(struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock)(struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **, void **);long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);void (*show_fdinfo)(struct seq_file *m, struct file *f);ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int);loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,struct file *file_out, loff_t pos_out,loff_t len, unsigned int remap_flags);int (*fadvise)(struct file *, loff_t, loff_t, int);
};

块设备I/O核心结构

/* BIO结构体 - 块I/O描述符 */
struct bio {struct bio              *bi_next;       /* 链表中下一个bio */struct gendisk          *bi_disk;       /* 目标磁盘 */unsigned int            bi_opf;         /* 操作标志 */unsigned short          bi_flags;       /* 状态标志 */unsigned short          bi_ioprio;      /* I/O优先级 */unsigned short          bi_write_hint;  /* 写提示 */blk_status_t            bi_status;      /* I/O状态 */u8                      bi_partno;      /* 分区号 */atomic_t                __bi_remaining; /* 剩余I/O计数 */struct bvec_iter        bi_iter;        /* 迭代器 */bio_end_io_t            *bi_end_io;     /* 完成回调 */void                    *bi_private;    /* 私有数据 */struct bio_crypt_ctx    *bi_crypt_context; /* 加密上下文 */struct bio_integrity_payload *bi_integrity; /* 完整性载荷 */unsigned short          bi_vcnt;        /* bio_vec数量 */unsigned short          bi_max_vecs;    /* 最大bio_vec数量 */atomic_t                __bi_cnt;       /* 引用计数 */struct bio_vec          *bi_io_vec;     /* bio_vec数组 */struct bio_set          *bi_pool;       /* 内存池 */struct bio_vec          bi_inline_vecs[]; /* 内联bio_vec */
};/* 请求结构体 - I/O请求 */
struct request {struct request_queue    *q;             /* 请求队列 */struct blk_mq_ctx       *mq_ctx;        /* 多队列上下文 */struct blk_mq_hw_ctx    *mq_hctx;       /* 硬件队列上下文 */unsigned int            cmd_flags;      /* 命令标志 */req_flags_t             rq_flags;       /* 请求标志 */int                     tag;            /* 请求标签 */int                     internal_tag;   /* 内部标签 */sector_t                __sector;       /* 起始扇区 */unsigned int            __data_len;     /* 数据长度 */struct bio              *bio;           /* 关联的bio */struct bio              *biotail;       /* bio链表尾 */struct hlist_node       hash;           /* 哈希链表节点 */union {struct rb_node      rb_node;        /* 红黑树节点 */struct bio_vec      special_vec;    /* 特殊向量 */};union {struct hd_struct    *part;          /* 分区信息 */int                 margin_lvl;     /* 边界级别 */};unsigned long           deadline;       /* 截止时间 */struct list_head        timeout_list;  /* 超时链表 */unsigned int            timeout;        /* 超时值 */int                     retries;        /* 重试次数 */rq_end_io_fn            *end_io;        /* 完成回调 */void                    *end_io_data;   /* 完成回调数据 */
};

I/O 处理流程

系统调用到设备驱动的数据流

应用程序系统调用VFS层文件系统页缓存块设备层设备驱动硬件read(fd, buf, len)sys_read()file_operations->>read()检查页缓存返回缓存数据提交bio请求调用驱动函数发送硬件命令完成中断调用完成回调更新页缓存alt[缓存命中][缓存未命中]返回数据返回读取结果返回用户空间应用程序系统调用VFS层文件系统页缓存块设备层设备驱动硬件

read系统调用详细流程

普通文件
字符设备
块设备
用户调用read
进入内核sys_read
获取file结构
检查文件权限
调用vfs_read
file->f_op->read_iter
文件类型?
generic_file_read_iter
字符设备read
块设备read
查找页缓存
缓存命中?
复制到用户缓存
分配新页面
构造bio请求
提交到块设备层
I/O调度器处理
设备驱动执行
DMA传输
完成中断
更新页缓存
返回用户空间

VFS 虚拟文件系统

VFS 架构关系图

VFS
+inode: struct inode
+dentry: struct dentry
+file: struct file
+super_block: struct super_block
inode
+i_mode: umode_t
+i_size: loff_t
+i_op: inode_operations*
+i_fop: file_operations*
+i_mapping: address_space*
dentry
+d_name: qstr
+d_inode: inode*
+d_parent: dentry*
+d_subdirs: list_head
+d_op: dentry_operations*
file
+f_path: path
+f_inode: inode*
+f_op: file_operations*
+f_pos: loff_t
+f_mapping: address_space*
address_space
+host: inode*
+i_pages: xarray
+a_ops: address_space_operations*
+nrpages: unsigned_long

VFS核心操作表

操作类型结构体主要函数功能描述
文件操作file_operationsread, write, open, release文件I/O操作
inode操作inode_operationscreate, lookup, mkdir, rmdir文件系统对象操作
地址空间操作address_space_operationsreadpage, writepage, direct_IO页缓存操作
超级块操作super_operationsalloc_inode, destroy_inode, sync_fs文件系统级操作
目录项操作dentry_operationsd_revalidate, d_hash, d_compare目录缓存操作

块设备I/O

块设备I/O架构

I/O调度器类型
块设备I/O栈
noop
deadline
cfq
bfq
kyber
文件系统层
VFS层
页缓存层
BIO层
请求层
I/O调度器
多队列层
驱动层
硬件层

BIO生命周期

bio_alloc()
bio_set_dev()
bio_add_page()
继续添加
submit_bio()
I/O调度器处理
设备驱动处理
bio_endio()
bio_put()
发生错误
可重试错误
不可重试错误
创建
初始化
添加页面
提交
调度
执行
完成
释放
错误
重试

字符设备I/O

字符设备架构

/* 字符设备结构体 */
struct cdev {struct kobject kobj;                /* 内核对象 */struct module *owner;               /* 所属模块 */const struct file_operations *ops;  /* 操作函数表 */struct list_head list;              /* 链表节点 */dev_t dev;                          /* 设备号 */unsigned int count;                 /* 设备数量 */
};/* 字符设备注册流程 */
static struct file_operations globalmem_fops = {.owner = THIS_MODULE,.llseek = globalmem_llseek,.read = globalmem_read,.write = globalmem_write,.unlocked_ioctl = globalmem_ioctl,.open = globalmem_open,.release = globalmem_release,
};

字符设备I/O流程

用户空间VFS字符设备设备驱动硬件open("/dev/mydev")查找字符设备cdev->>ops->>open()初始化硬件硬件就绪返回成功返回文件描述符write(fd, data, len)fops->>write()写入硬件寄存器完成写入返回写入字节数返回结果用户空间VFS字符设备设备驱动硬件

内存映射I/O

mmap机制

物理内存
页表映射
虚拟内存区域
物理页面
页缓存
页全局目录
页上级目录
页中间目录
页表项
vm_area_struct
vm_start
vm_end
vm_flags
vm_operations_struct

mmap系统调用流程

/* mmap实现示例 */
static int globalmem_mmap(struct file *filp, struct vm_area_struct *vma)
{unsigned long size = vma->vm_end - vma->vm_start;/* 检查映射大小 */if (size > GLOBALMEM_SIZE)return -EINVAL;/* 设置页面不可交换 */vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;/* 建立页表映射 */if (remap_pfn_range(vma, vma->vm_start,virt_to_phys(globalmem_devp->mem) >> PAGE_SHIFT,size, vma->vm_page_prot))return -EAGAIN;return 0;
}

异步I/O机制

AIO架构

完成处理
异步I/O栈
工作队列
中断处理
完成处理
完成环
libaio库
应用程序
io_submit系统调用
AIO核心
内核I/O控制块
BIO层
块设备层

io_uring新机制

零拷贝机制
io_uring架构
共享内存
内存映射
提交队列
应用程序
SQ Ring
内核处理
完成队列
CQ Ring

I/O调度器

调度器对比表

调度器特点适用场景算法复杂度
noop简单FIFOSSD、虚拟化环境O(1)
deadline截止时间保证实时系统O(log n)
cfq完全公平队列多用户环境O(log n)
bfq预算公平队列交互式应用O(log n)
kyber多队列优化高性能SSDO(1)

CFQ调度器算法

CFQ调度器
RT
BE
IDLE
请求类别
请求
实时队列
最优努力队列
空闲队列
优先级
优先级0队列
优先级1队列
优先级7队列
调度器

调试工具与方法

系统I/O监控工具

工具名称功能描述使用场景输出信息
iostatI/O统计信息性能监控IOPS、吞吐量、延迟
iotop进程I/O排序问题定位每进程I/O使用率
blktrace块设备跟踪深度分析I/O请求路径
strace系统调用跟踪调试系统调用序列
perf性能分析优化CPU、I/O热点
ftrace内核函数跟踪内核调试函数调用链

常用调试命令

# I/O性能监控
iostat -x 1        # 每秒显示扩展I/O统计
iotop -o           # 显示有I/O活动的进程
vmstat 1           # 系统整体统计# 块设备跟踪
blktrace -d /dev/sda -o trace
blkparse trace.blktrace.0# 进程I/O分析
cat /proc/PID/io   # 进程I/O统计
lsof +D /path      # 文件描述符分析# 内核调试
echo 1 > /sys/kernel/debug/tracing/events/block/enable
cat /sys/kernel/debug/tracing/trace# 页缓存分析
cat /proc/meminfo | grep -E "(Cached|Buffers|Dirty)"
echo 3 > /proc/sys/vm/drop_caches  # 清理页缓存# 文件系统分析
df -h              # 磁盘使用情况
mount | column -t  # 挂载信息
tune2fs -l /dev/sda1  # ext文件系统信息

性能分析脚本

#!/bin/bash
# I/O性能分析脚本echo "=== I/O Performance Analysis ==="# 1. 基本I/O统计
echo "1. Basic I/O Statistics:"
iostat -x 1 5# 2. 进程I/O排序
echo "2. Top I/O Processes:"
iotop -a -o -d 1 -n 5# 3. 磁盘使用情况
echo "3. Disk Usage:"
df -h# 4. 内存和缓存状态
echo "4. Memory and Cache Status:"
free -h
cat /proc/meminfo | grep -E "(Cached|Buffers|Dirty|Writeback)"# 5. 文件描述符使用
echo "5. File Descriptor Usage:"
cat /proc/sys/fs/file-nr# 6. I/O调度器信息
echo "6. I/O Scheduler:"
for dev in /sys/block/*/queue/scheduler; doecho "$dev: $(cat $dev)"
done

内核调试技术

/* 内核调试宏和技术 *//* 1. printk调试 */
#define DEBUG_IO 1
#if DEBUG_IO
#define io_debug(fmt, ...) \printk(KERN_DEBUG "IO_DEBUG: " fmt, ##__VA_ARGS__)
#else
#define io_debug(fmt, ...)
#endif/* 2. 跟踪点 */
#include <linux/tracepoint.h>TRACE_EVENT(my_io_event,TP_PROTO(struct file *file, size_t count, loff_t pos),TP_ARGS(file, count, pos),TP_STRUCT__entry(__field(unsigned long, inode)__field(size_t, count)__field(loff_t, pos)),TP_fast_assign(__entry->inode = file->f_inode->i_ino;__entry->count = count;__entry->pos = pos;),TP_printk("inode=%lu count=%zu pos=%lld",__entry->inode, __entry->count, __entry->pos)
);/* 3. 动态调试 */
#define pr_debug_io(fmt, ...) \pr_debug("IO: " fmt, ##__VA_ARGS__)/* 使用方法 */
static ssize_t my_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{io_debug("Read request: count=%zu, pos=%lld\n", count, *ppos);trace_my_io_event(filp, count, *ppos);pr_debug_io("Processing read for inode %lu\n", filp->f_inode->i_ino);/* 实际读取逻辑 */return count;
}

性能优化策略

I/O优化技术对比

优化技术原理适用场景性能提升
页缓存预读预先加载后续页面顺序访问2-10x
异步I/O非阻塞I/O操作高并发应用5-50x
直接I/O绕过页缓存大文件传输20-30%
内存映射避免数据拷贝随机访问10-50%
批量I/O合并多个请求小块I/O2-5x
I/O调度优化减少磁盘寻道机械硬盘20-100%

优化配置示例

# 1. I/O调度器优化
echo mq-deadline > /sys/block/sda/queue/scheduler# 2. 预读优化
echo 4096 > /sys/block/sda/queue/read_ahead_kb# 3. 队列深度优化
echo 128 > /sys/block/sda/queue/nr_requests# 4. 内存管理优化
echo 10 > /proc/sys/vm/swappiness
echo 1 > /proc/sys/vm/zone_reclaim_mode# 5. 文件系统优化
mount -o remount,noatime,nodiratime /

应用层优化建议

/* 1. 使用O_DIRECT避免双重缓存 */
int fd = open("largefile.dat", O_RDONLY | O_DIRECT);/* 2. 使用posix_fadvise提供访问模式提示 */
posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);/* 3. 使用madvise优化内存映射 */
madvise(addr, length, MADV_WILLNEED);/* 4. 批量I/O操作 */
struct iovec iov[MAX_IOV];
/* 填充iov数组 */
writev(fd, iov, iovcnt);/* 5. 异步I/O */
struct aiocb cb;
aio_read(&cb);
aio_suspend(&cb, 1, NULL);

总结

Linux I/O架构是一个复杂而精密的系统,通过多层抽象和优化技术,为应用程序提供了高效、统一的存储访问接口。理解其工作原理和掌握相关的调试技术,对于系统性能优化和问题诊断具有重要意义。

关键要点

  1. 分层架构:VFS提供统一接口,底层支持多种文件系统和设备类型
  2. 缓存机制:页缓存显著提升I/O性能,但需要合理管理
  3. 异步处理:现代I/O栈大量使用异步机制减少延迟
  4. 调度优化:不同的I/O调度器适用于不同的应用场景
  5. 性能监控:丰富的工具链支持深度性能分析和问题诊断

通过深入理解这些机制并合理应用优化技术,可以显著提升系统的I/O性能和响应能力。


文章转载自:

http://3lX8LEWC.zbtfz.cn
http://BBmR1E8N.zbtfz.cn
http://aORfHxhd.zbtfz.cn
http://mN9DxUxy.zbtfz.cn
http://jf6t9FfN.zbtfz.cn
http://tPtRjdUF.zbtfz.cn
http://oWYkvPig.zbtfz.cn
http://DwrBQPwF.zbtfz.cn
http://70B8kfde.zbtfz.cn
http://8O3AXKbY.zbtfz.cn
http://UKr5FfCi.zbtfz.cn
http://i8h9pbAw.zbtfz.cn
http://4Ydu9XOd.zbtfz.cn
http://I5V9dTf3.zbtfz.cn
http://qoHSfZfK.zbtfz.cn
http://5wJKNhLl.zbtfz.cn
http://36dLQZGs.zbtfz.cn
http://9ghUkQgI.zbtfz.cn
http://rWbyWutf.zbtfz.cn
http://cSFUOC0m.zbtfz.cn
http://1RsJtU6P.zbtfz.cn
http://ZqcgV8to.zbtfz.cn
http://gvLAD68H.zbtfz.cn
http://eAUVsYo2.zbtfz.cn
http://iInuS0od.zbtfz.cn
http://sdgBoIwH.zbtfz.cn
http://numQCVmo.zbtfz.cn
http://xyMbZMJZ.zbtfz.cn
http://Iv2p5AwX.zbtfz.cn
http://0cMe1vAb.zbtfz.cn
http://www.dtcms.com/a/374286.html

相关文章:

  • 实现一个可中断线程的线程类
  • Java全栈学习笔记31
  • 算法之双指针
  • js定义变量时let和cons的使用场景
  • DataLens:一款现代化的开源数据分析和可视化工具
  • 人工智能-python-深度学习-神经网络-MobileNet V1V2
  • TDengine 选择函数 Last() 用户手册
  • MySQL的数据模型
  • vulnhub:Kioptrix level 2
  • C++ Int128 —— 128位有符号整数类实现剖析
  • 前端部署,又有新花样?
  • Neural Jacobian Field学习笔记 - omegaconf
  • C++(day8)
  • 设计模式:模板方法模式
  • 英发睿能闯关上市:业绩波动明显,毅达创投退出,临场“移民”
  • 华清远见25072班网络编程day1
  • 深入理解 AbstractQueuedSynchronizer (AQS):Java 并发的排队管家
  • 32位CPU架构是如何完成两数(32位)相加的指令的?
  • 深度学习中的损失函数都有哪些,大模型时代主要用的损失函数有哪些,中间有什么区别?
  • java:io流相关类的继承关系梳理
  • PAT 1004 Counting Leaves
  • Linux操作系统shell脚本语言-第六章
  • 基于Springboot + vue3实现的小区物业管理系统
  • 自动化测试DroidRun
  • 把一段 JSON 字符串还原成一个实体对象
  • YOLO系列论文梳理(AI版)
  • ARM内核知识概念
  • 图论相关经典题目练习及详解
  • 深圳比斯特|多维度分选:圆柱电池品质管控的自动化解决方案
  • MySQL 日志全解析:Binlog/Redo/Undo 等 5 类关键日志的配置、作用与最佳实践