Linux输入输出系统(笔记)
字符设备
不同的操作下调用链关系:
1、打开字符设备
2、写入字符设备
3、ioctl(特殊的io操作)
总结:
中断发生的调用过程:
中断是从外部设备发起的,会形成外部中断。
外部中断会到达中断控制器,中断控制器会发送中断向量 Interrupt Vector 给 CPU。
对于每一个 CPU,都要求有一个 idt_table,里面存放了不同的中断向量的处理函数。
中断向量表中已经填好了前 32 位,外加一位 32 位系统调用,其他的都是用于设备中断。
硬件中断的处理函数是 do_IRQ 进行统一处理,在这里会让中断向量,通过 vector_irq 映射为 irq_desc。
irq_desc 是一个用于描述用户注册的中断处理函数的结构,为了能够根据中断向量得到 irq_desc 结构,会把这些结构放在一个基数树里面,方便查找。
irq_desc 里面有一个成员是 irqaction,指向设备驱动程序里面注册的中断处理函数。
块设备(淋漓尽致地表现了一切皆文件的思想)
mount(挂载)的整个过程:
- 所有的块设备被一个 map 结构管理从 dev_t 到 gendisk 的映射;
- 所有的 block_device 表示的设备或者分区都在 bdev 文件系统的 inode 列表中;
- mknod 创建出来的块设备文件在 devtemfs 文件系统里面,特殊 inode 里面有块设备号;
- mount 一个块设备上的文件系统,调用这个文件系统的 mount 接口;
- 通过按照 /dev/xxx 在文件系统 devtmpfs 文件系统上搜索到特殊 inode,得到块设备号;
- 根据特殊 inode 里面的 dev_t 在 bdev 文件系统里面找到 inode;
- 根据 bdev 文件系统上的 inode 找到对应的 block_device,根据 dev_t 在 map 中找到 gendisk,将两者关联起来;
- 找到 block_device 后打开设备,调用和 block_device 关联的 gendisk 里面的 block_device_operations 打开设备;
- 创建被 mount 的文件系统的 super_block。
直接I/O与缓存I/O
对于块设备的 I/O 操作分为两种,一种是直接 I/O,另一种是缓存 I/O。无论是哪种 I/O,最终都会调用 submit_bio 提交块设备 I/O 请求。对于每一种块设备,都有一个 gendisk 表示这个设备,它有一个请求队列,这个队列是一系列的 request 对象。每个 request 对象里面包含多个 BIO 对象,指向 page cache。所谓的写入块设备,I/O 就是将 page cache 里面的数据写入硬盘。对于请求队列来讲,还有两个函数,一个函数叫 make_request_fn 函数,用于将请求放入队列。submit_bio 会调用 generic_make_request,然后调用这个函数。另一个函数往往在设备驱动程序里实现,我们叫 request_fn 函数,它用于从队列里面取出请求来,写入外部设备。
块设备I/O涉及到的文件系统分层结构: