现在的位置: 首页 > 综合 > 正文

linux 0.11 源码学习(十二)

2012年10月09日 ⁄ 综合 ⁄ 共 1714字 ⁄ 字号 评论关闭

块设备驱动管理

linux的设备驱动管理遵循Unix的机制,向上以文件的形式暴露接口,见Read_write.c中的sys_read函数,在该系统调用函数中根据文件的类型以此调用块设备类驱动、字符设备驱动、管道和普通文件接口。

对于块设备类这个分类主要针对如硬盘、软盘等以数据块为单位进行读写的设备,linux 0.11这部分的代码主要有4个.c文件,ll_rw_blk.c(块设备读写封装)、hd.c(提供硬盘读写的具体功能)、Floopy.c(提供软盘读写的具体功能)、Ramdisk.c(内存虚拟盘读写的具体功能)。

ll_rw_blk.c

linux为各个设备维护了请求缓冲区,ll_rw_blk通过向不同的设备发送请求项完成读写触发,如下:

struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
    { NULL, NULL },        /* no_dev */
    { NULL, NULL },        /* dev mem */
    { NULL, NULL },        /* dev fd */
    { NULL, NULL },        /* dev hd */ //数组的初始化会在各类设备的初始化中完成,如硬盘的hd_init。
    { NULL, NULL },        /* dev ttyx */
    { NULL, NULL },        /* dev tty */
    { NULL, NULL }         /* dev lp */
};

struct blk_dev_struct {
    void (*request_fn)(void); //请求项的处理回调函数
    struct request * current_request;//请求项队列
};

向上提供的核心函数式ll_rw_block,该函数非常简单判断设备接口体是否被正确初始化,OK的话调用make_request。在make_request中完成如下工作:

  • 首先判断缓冲区,若命令是写且缓冲区数据为修改,或命令是读缓冲区数据已更新,则解锁缓冲区,直接返回;
  • 查找一个读或者写的请求项
repeat:
/* we don't allow the write-requests to fill up the queue completely:
 * we want some room for reads: they take precedence. The last third
 * of the requests are only for reads.
 */
    if (rw == READ)
        req = request+NR_REQUEST; //读请求项在队列的前2/3,因为优先保证读
    else
        req = request+((NR_REQUEST*2)/3);//写请求项在队列的后1/3
/* find an empty request */
    while (--req >= request)
        if (req->dev<0)//req->dev = -1表示未使用,见ll_rw_blk的初始化函数blk_dev_init
            break;
/* if none found, sleep on new requests: check for rw_ahead */
    if (req < request) {
        if (rw_ahead) {//预读指令,则直接解锁
            unlock_buffer(bh);
            return;
        }
        sleep_on(&wait_for_request);
        goto repeat;
    }
  • 之后构造一个request消息,调用add_request(major+blk_dev,req)

add_request函数的实现功能很简单,就是以电梯算法插入请求项队列。

    for ( ; tmp->next ; tmp=tmp->next)
        if ((IN_ORDER(tmp,req) || 
            !IN_ORDER(tmp,tmp->next)) &&
            IN_ORDER(req,tmp->next))
            break;
    req->next=tmp->next;
    tmp->next=req;
#define IN_ORDER(s1,s2) \ //以此根据读写命令(优先读)、设备、扇区进行排序;
((s1)->cmd<(s2)->cmd || ((s1)->cmd==(s2)->cmd && \
((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \
(s1)->sector < (s2)->sector))))

抱歉!评论已关闭.