[关闭]
@harpsword 2015-11-04T12:44:22.000000Z 字数 2603 阅读 1955

linux0.11内核之块设备驱动程序

操作系统 块设备


源代码目录

表1: linux/kernel/blk_drv 目录

文件名 大小 最后修改时间
Makefile 1951 bytes 1991-12-05 19:59:42
blk.h 3464 bytes 1991-12-05 19:58:01
floppy.c 11429 bytes 1991-12-07 00:00:38
hd.c 7807 bytes 1991-12-05 19:58:17
ll_rw_blw.c 3539 bytes 1991-12-04 13:41:42
ramdisk.c 2740 bytes 1991-12-06 03:08:06

总体功能描述

细节

1. 对硬盘和软盘块设备上数据的读写操作是通过中断处理程序进行的
2. 每次读写的数据量以一个逻辑块(1 block = 1 KB = 1024 B)为单位。
3. 在处理过程中,使用了读写请求等待队列来顺序缓冲一次读写多个逻辑块的操作。

读取硬盘上一个逻辑快的流程图

Created with Raphaël 2.1.2当程序要读取硬盘上的一个逻辑块时向缓冲管理程序提出申请,并自身进入睡眠等待状态缓存区中是(yes)否(no)存在这块数据返回对应的缓冲区块头指针唤醒该程序缓冲管理程序会调用ll_wr_block()函数,发出一个读块数据的操作请求当块数据读入到指定的缓冲块中后,会发出中断请求信号,并调用结束请求过程,对相应块设备进行关闭操作和设置该缓冲块数据已经更新标志yesno

块设备请求项和请求队列

  1. 块设备表 blk_dev[] : 这是内核用来管理块设备的。每种块设备都在该表中占有一项。

    • 块设备表中每个块设备表项的结构 和 块设备表的定义
    1. struct blk_dev_struct {
    2. void ( * request_fn) (void); // 某种块设备的请求项操作函数指针
    3. struct request * current_request; // 当前请求项指针
    4. }
    5. extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; // 块设备表(数组)(NR_BLK_DEV = 7)
    • linux0.11内核中的主设备号 表
    主设备号 类型 说明 请求项操作
    0 NULL
    1 块/字符 ram,内存设备(虚拟盘等) do_rd_request()
    2 fd,软驱设备 do_fd_request()
    3 hd,硬盘设备 do_hd_request()
    4 字符 ttyx 设备 NULL
    5 字符 tty设备 NULL
    6 字符 lp打印机设备 NULl
  2. ll_rw_block()函数简介:当内核发出一个块设备读写或者其他操作请求时,ll_rw_block()函数即会根据其参数中指明的操作命令和数据缓冲块头中的设备号,利用对应的 请求项操作函数do_XX_request() 建立一个 块设备请求项 ,并利用 电梯算法 插入到请求队列中去。 请求项队列 由请求项数组中的项构成, 共有 32 项。 如下是每个请求项的数据结构

    1. struct request{
    2. int dev; // 使用的设备号 (若为 -1 ,表示该项空闲)
    3. int cmd; // 命令(READ 或者 WRITE)
    4. int errrors; // 操作时产生的错误次数
    5. unsigned long sector; // 起始扇区 (1块 = 2 扇区)
    6. unsigned long nr_sectors; // 读/写扇区数
    7. char * buffer;; // 数据缓冲区
    8. struct task_struct * waiting; // 任务等待操作执行完成的地方
    9. struct buffer_head *bh; // 缓冲区头指针(include/linux/fs.h,68)
    10. struct request * next; // 指向下一项请求项
    11. };
    12. extern struct request request[NR_REQUEST]; // 请求队列数组(NR_REQUEST = 32)
    • 请求项采用数组加链表结构的主要原因是

      1. 利用请求项的数组结构在搜索空闲请求块的时候可以进行循环操作,使代码更简洁
      2. 满足电梯算法插入请求项操作
    • 另外:为了满足读操作的优先权,在建立新的请求项而搜索请求项数组时,把建立写操作时的空闲项搜索范围限制在整个请求项数组的前 2/3 范围内, 而剩下的 1/3 请求项专门给读操作建立请求项使用。

    • ll_rw_block() 具体实现 : 对于一个当前空闲的块设备,当ll_rw_block()函数为其建立第一个请求项时,会让该设备的当前请求项指针current_request直接指向刚建立的请求项,并且理科调用对应设备的请求项操作函数开始执行块设备读写操作。当一个块设备已经有几个请求项组成的链表存在,ll_rw_block()就会利用电梯算法,根据磁头移动距离最小原则,把新建的请求项插入到链表中适当的位置。

块设备操作方式

总的过程

总过程时序图

Created with Raphaël 2.1.2开始读/写过程中断过程,是否还有数据未读或未写结束处理过程是否存在下一个读/写请求项Endyesnoyesno

结束处理过程

  1. 唤醒等待该请求项有关数据的相关进程
  2. 唤醒等待该请求项的进程
  3. 释放当前请求项并从链表中删除该请求项以及释放锁定的相关缓冲区

读写过程序列图

Created with Raphaël 2.1.2系统(cpu)系统(cpu)设备控制器设备控制器驱动器驱动器命令数据传输中断请求

写过程序列图

Created with Raphaël 2.1.2系统、块设备控制器和驱动器(写操作)系统(cpu)系统(cpu)控制器控制器驱动器驱动器写命令(使用 hd_out())允许项控制器写数据一个扇区的数据(同样使用 hd_out()函数)一个扇区的数据(数据传输)中断请求信号中断处理

读过程时序图

Created with Raphaël 2.1.2读过程时序图系统(cpu)系统(cpu)控制器控制器驱动器驱动器包括扇区开始位置、扇区数量等信息的命令数据传输(大小:1扇区)中断信号

虚拟盘设备

由于它的读写操作不牵涉到与外部设备之间的同步操作,因此没有上述的中断处理过程。当前请求项对虚拟设备的读写操作完全在do_rd_requst()中实现。

代码分析

blk.h 文件

代码分析

hd.c 文件

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注