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 Cache I/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; 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;
} ;
struct inode { umode_t i_mode; unsigned short i_opflags; kuid_t i_uid; kgid_t i_gid; unsigned int i_flags; const struct inode_operations * i_op; struct super_block * i_sb; struct address_space * i_mapping; void * i_security; unsigned long i_ino; dev_t i_rdev; loff_t i_size; struct timespec64 i_atime; struct timespec64 i_mtime; struct timespec64 i_ctime; spinlock_t i_lock; unsigned short i_bytes; u8 i_blkbits; blkcnt_t i_blocks; const struct file_operations * i_fop; struct hlist_head i_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核心結構
struct bio { struct bio * bi_next; struct gendisk * bi_disk; unsigned int bi_opf; unsigned short bi_flags; unsigned short bi_ioprio; unsigned short bi_write_hint; blk_status_t bi_status; u8 bi_partno; atomic_t __bi_remaining; 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; unsigned short bi_max_vecs; atomic_t __bi_cnt; struct bio_vec * bi_io_vec; struct bio_set * bi_pool; struct bio_vec bi_inline_vecs[ ] ;
} ;
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; struct bio * biotail; 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_operations read, write, open, release 文件I/O操作 inode操作 inode_operations create, lookup, mkdir, rmdir 文件系統對象操作 地址空間操作 address_space_operations readpage, writepage, direct_IO 頁緩存操作 超級塊操作 super_operations alloc_inode, destroy_inode, sync_fs 文件系統級操作 目錄項操作 dentry_operations d_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系統調用流程
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 簡單FIFO SSD、虛擬化環境 O(1) deadline 截止時間保證 實時系統 O(log n) cfq 完全公平隊列 多用戶環境 O(log n) bfq 預算公平隊列 交互式應用 O(log n) kyber 多隊列優化 高性能SSD O(1)
CFQ調度器算法
CFQ調度器
RT
BE
IDLE
請求類別
請求
實時隊列
最優努力隊列
空閑隊列
優先級
優先級0隊列
優先級1隊列
優先級7隊列
調度器
調試工具與方法
系統I/O監控工具工具名稱 功能描述 使用場景 輸出信息 iostat I/O統計信息 性能監控 IOPS、吞吐量、延遲 iotop 進程I/O排序 問題定位 每進程I/O使用率 blktrace 塊設備跟蹤 深度分析 I/O請求路徑 strace 系統調用跟蹤 調試 系統調用序列 perf 性能分析 優化 CPU、I/O熱點 ftrace 內核函數跟蹤 內核調試 函數調用鏈
常用調試命令
iostat -x 1
iotop -o
vmstat 1
blktrace -d /dev/sda -o trace
blkparse trace.blktrace.0
cat /proc/PID/io
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
性能分析腳本
#!/bin/bash
echo "=== I/O Performance Analysis ==="
echo "1. Basic I/O Statistics:"
iostat -x 1 5
echo "2. Top I/O Processes:"
iotop -a -o -d 1 -n 5
echo "3. Disk Usage:"
df -h
echo "4. Memory and Cache Status:"
free -h
cat /proc/meminfo | grep -E "(Cached|Buffers|Dirty|Writeback)"
echo "5. File Descriptor Usage:"
cat /proc/sys/fs/file-nr
echo "6. I/O Scheduler:"
for dev in /sys/block/*/queue/scheduler; do echo "$dev : $( cat $dev) "
done
內核調試技術
# 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
# 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)
) ;
# 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/O 2-5x I/O調度優化 減少磁盤尋道 機械硬盤 20-100%
優化配置示例
echo mq-deadline > /sys/block/sda/queue/scheduler
echo 4096 > /sys/block/sda/queue/read_ahead_kb
echo 128 > /sys/block/sda/queue/nr_requests
echo 10 > /proc/sys/vm/swappiness
echo 1 > /proc/sys/vm/zone_reclaim_mode
mount -o remount,noatime,nodiratime /
應用層優化建議
int fd = open ( "largefile.dat" , O_RDONLY | O_DIRECT) ;
posix_fadvise ( fd, 0 , 0 , POSIX_FADV_SEQUENTIAL) ;
madvise ( addr, length, MADV_WILLNEED) ;
struct iovec iov[ MAX_IOV] ;
writev ( fd, iov, iovcnt) ;
struct aiocb cb;
aio_read ( & cb) ;
aio_suspend ( & cb, 1 , NULL ) ;
總結
Linux I/O架構是一個復雜而精密的系統,通過多層抽象和優化技術,為應用程序提供了高效、統一的存儲訪問接口。理解其工作原理和掌握相關的調試技術,對于系統性能優化和問題診斷具有重要意義。
關鍵要點
分層架構 :VFS提供統一接口,底層支持多種文件系統和設備類型緩存機制 :頁緩存顯著提升I/O性能,但需要合理管理異步處理 :現代I/O棧大量使用異步機制減少延遲調度優化 :不同的I/O調度器適用于不同的應用場景性能監控 :豐富的工具鏈支持深度性能分析和問題診斷
通過深入理解這些機制并合理應用優化技術,可以顯著提升系統的I/O性能和響應能力。