I/O
子系统概貌VFS
:内核提供不同实现文件系统的抽象,应用端一般请求到vfs
,vfs
在调用实际文件系统的posix
语义函数,可以理解为vfs
作为用户态和实际文件系统的之间的转换桥梁,为用户态提供对于底层磁盘文件系统无感知的文件系统服务层。Page Cache
: 缓存文件系统的数据,这里包括文件系统元数据和文件系统数据,在块缓存之上构建页缓存(常说的Buffer/Cache
).Mapping Layer
:如果内核需要从块设备上读取数据,就必须知道数据在物理设备上的位置,这个是由映射层Mapping Layer
来完成。Generic Block Layer
:通用块设备层目标是为不同的块设备建立统一的模型,它负责接受上层的IO请求,最后在发出IO请求(在块设备上执行操作,启动I/O操作,传输请求数据)I/O Scheduler
:IO调度层
根据调度策略对IO请求进行排序,缓存请求而且合并相邻的请求,根据设置号的调度策略,回调驱动提供的回调函数,用来处理具体的IO请求。Block Device Driver
:负责向磁盘控制器发送IO指令执行实际的数据传输。I/O
子系统中对象struct gendisk
: 内核通过gendisk
把磁盘类设备中通用的部分抽象出来。struct hd_struct
:对于分区的请求可以线性的映射到物理磁盘,这种分区的体现在内核中使用hd_struct
表示。struct block_device
:在内核中磁盘和分区对应一个块设备,每个块设备有自己唯一的块设备编号和名称,根据块设备可以找到磁盘,这个通用的块设备抽象层是通过block_device
呈现。I/O
处理流程I/O
调度层的调度队列中,在根据调度策略进行合并和排序,最后把转换后的I/O
请求派发给具体的块设备的队列,最后由设备驱动层来进行处理。I/O
请求,一种是通用块设备层的I/O
请求,这个在内核中是以struct bio
呈现;另外一种设备驱动层的I/O
请求,在内核中是以struct request
呈现。 // 驱动层的IO请求
struct request {
// 指向包含请求的请求队列的指针
struct request_queue *q;
struct blk_mq_ctx *mq_ctx;
int cpu;
// 请求标志
unsigned int cmd_flags; /* op and common flags */
req_flags_t rq_flags;
int internal_tag;
// 请求的数据长度
unsigned int __data_len; /* total data len */
int tag;
// 请求的起始扇区的编号
sector_t __sector;
// 没完成传输的第一个bio
struct bio *bio;
// 租后一个bio
struct bio *biotail;
// request请求放入的I/O调度队列
struct list_head queuelist;
union {
// 链入电梯算法哈希表,按照最后一个扇区的编号进行哈希,方便查找和合并对象
struct hlist_node hash; /* merge hash */
struct list_head ipi_list;
};
union {
struct rb_node rb_node; /* sort/lookup */
struct bio_vec special_vec;
void *completion_data;
int error_count; /* for legacy drivers, don't use */
};
union {
struct {
struct io_cq *icq;
void *priv[2];
} elv;
struct {
unsigned int seq;
struct list_head list;
rq_end_io_fn *saved_end_io;
} flush;
};
// IO请求所对应的磁盘结构指针
struct gendisk *rq_disk;
// IO请求所在的磁盘对应的分区
struct hd_struct *part;
// IO提交到内核的时间
u64 start_time_ns;
// IO提交到驱动层的时间
u64 io_start_time_ns;
#ifdef CONFIG_BLK_WBT
unsigned short wbt_flags;
#endif
#ifdef CONFIG_BLK_DEV_THROTTLING_LOW
unsigned short throtl_size;
#endif
/*
* Number of scatter-gather DMA addr+len pairs after
* physical address coalescing is performed.
*/
unsigned short nr_phys_segments;
#if defined(CONFIG_BLK_DEV_INTEGRITY)
unsigned short nr_integrity_segments;
#endif
unsigned short write_hint;
unsigned short ioprio;
void *special;
// 额外的树长度
unsigned int extra_len; /* length of alignment and padding */
enum mq_rq_state state;
refcount_t ref;
// 请求的超时时间
unsigned int timeout;
/* access through blk_rq_set_deadline, blk_rq_deadline */
unsigned long __deadline;
struct list_head timeout_list;
union {
struct __call_single_data csd;
u64 fifo_time;
};
// 请求完成的回调函数
rq_end_io_fn *end_io;
// 完成回调函数的参数
void *end_io_data;
// next_rq关联两个request实现SCSI双向指令
struct request *next_rq;
#ifdef CONFIG_BLK_CGROUP
struct request_list *rl; /* rl this rq is alloced from */
#endif
};
// 来自用户态的IO请求在内核的表现形式bio
struct bio {
// 指向属于同一个request的后一个bio
struct bio *bi_next;
// bio请求的磁盘
struct gendisk *bi_disk;
unsigned int bi_opf;
// bio的状态
unsigned short bi_flags; /* status, etc and bvec pool number */
unsigned short bi_ioprio;
unsigned short bi_write_hint;
blk_status_t bi_status;
// 磁盘对应的那个分区标识
u8 bi_partno;
// bio中的Segment的个数
unsigned int bi_phys_segments;
// 缓存bio的第一个segment的长度,根据这个最大段长度快速判断是否能合并
unsigned int bi_seg_front_size;
// 缓存bio的最后一个segment的长度
unsigned int bi_seg_back_size;
struct bvec_iter bi_iter;
atomic_t __bi_remaining;
// bio的IO操作完成后回调函数
bio_end_io_t *bi_end_io;
// 私有数据指针,在通用块设备层和驱动IO结束使用
void *bi_private;
#ifdef CONFIG_BLK_CGROUP
/*
* Optional ioc and css associated with this bio. Put on bio
* release. Read comment on top of bio_associate_current().
*/
struct io_context *bi_ioc;
struct cgroup_subsys_state *bi_css;
struct blkcg_gq *bi_blkg;
struct bio_issue bi_issue;
#endif
union {
#if defined(CONFIG_BLK_DEV_INTEGRITY)
struct bio_integrity_payload *bi_integrity; /* data integrity */
#endif
};
// bio的bio_vec数组中包含segmnet的个数
unsigned short bi_vcnt; /* how many bio_vec's */
unsigned short bi_max_vecs; /* max bvl_vecs we can hold */
atomic_t __bi_cnt; /* pin count */
// 存储bio的数组
struct bio_vec *bi_io_vec;
struct bio_set *bi_pool;
// 内嵌的bio数组
struct bio_vec bi_inline_vecs[0];
};
存储
栈