操作系统所有设备可分为两类:块设备和字符设备。
块设备是一种可以以固定大小的数据块为单位进行寻址和访问的设备,例如硬盘、软盘。
字符设备是一种以字符流作为操作对象的设备,不能进行寻址操作,例如打印机、网卡、终端设备。
为便于管理,操作系统将这些设备统一的以设备号进行分类。linux0.11内核将设备分成7类
主设备号 | 类型 | 说明 |
0 | 无 | 无 |
1 | 块/字符 | ram,内存设备 |
2 | 块 | fd,软盘 |
3 | 块 | hd,硬盘 |
4 | 字符 | ttyx,虚拟或串行终端 |
5 | 字符 | tty设备 |
6 | 字符 | lp打印机设备 |
代码路径:kernel/blk_drv
1 总体介绍
对hd和fd块设备上的数据的读写操作是通过中断处理程序进行的。内核每次读写的数据量以一个逻辑块(1024byte)为单位。
1.1 一次块设备读写流程
- 程序要读取硬盘上的某个块
- 向缓冲区管理程序提出申请
- 进程进入睡眠等待状态
- 首先在缓冲区中寻找这个数据块
- 找到则将对应缓冲区块头指针返回给程序
- 唤醒进程
- 如果缓冲区中未找到该区块
- 调用ll_rw_block()向硬盘驱动发送读请求
- ll_rw_block()会为此创建一个请求结构项,插入到请求队列里面
- 若对应块设备请求项队列为空,说明该设备空闲。内核向该块设备控制器发送读数据命令
- 块设备控制器将数据读入指定的缓冲块中
- 块设备控制器继续读取其他块或结束本次请求项
- 该请求项结束之后,关闭块设备,设置缓冲区数据已更新标志
- 唤醒等待该数据块的进程
1.2 块设备请求项
从上面的块设备读取数据的过程我们知道,ll_rw_block()是通过请求项来与各种块设备建立联系并发出读写请求的。
块设备请求结构
struct request { int dev; /* -1 if no request */ //设备号 int cmd; /* READ or WRITE */ //读或写 int errors; //读操作时产生的错误次数 unsigned long sector; //起始扇区 unsigned long nr_sectors; //扇区数 char * buffer; //数据缓冲区 struct task_struct * waiting; //等待该块设备的任务 struct buffer_head * bh; //缓冲区头指针 struct request * next; //指向下一请求项 };
块设备请求项
struct blk_dev_struct { void (*request_fn)(void); //处理对应块设备的函数指针,比如do_hd_request() struct request * current_request; //当前请求项 };
共有7种设备,使用一个数组blk_dev来存储各种块设备的请求项,数组大小为7
extern struct blk_dev_struct blk_dev[7];
1.3 请求队列
请求项除了在上述blk_dev[i]->current_request中有存放外,还专门设置了一个数组来存放所有设备的请求项,共可容纳32个请求项。这里的request[]就是请求队列
extern struct request request[32];
blk_dev[]数组和request[]队列之间的关系如下图所示
标签:二十二,kernel,请求,request,struct,dev,源码,blk,设备 From: https://www.cnblogs.com/zhenjingcool/p/17572816.html