ll_wr_blk.c

656阅读 0评论2009-08-09 jhluroom
分类:LINUX

/*
 * linux/kernel/blk_dev/ll_rw.c
 *
 * (C) 1991 Linus Torvalds
 */


/*
 * This handles all read/write requests to block devices
 */

#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>

#include "blk.h"

/*
 * The request-struct contains all necessary data
 * to load a nr of sectors into memory
 */

struct request request[NR_REQUEST];//全局变量同,请求项数组链表,NR_REQUEST=32


/*
 * used to wait on when there are no free requests
 */

struct task_struct * wait_for_request = NULL;//用于在请求项数组没有空闲项时 的进程的临时等待处,请求项数组满时又来了一个请求


/* blk_dev_struct is:
 *    do_request-address
 *    next-request
 */

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 */
    { NULL, NULL },        /* dev ttyx */
    { NULL, NULL },        /* dev tty */
    { NULL, NULL }        /* dev lp */
};//块设备数组,一共7个,每个设备一个


static inline void lock_buffer(struct buffer_head * bh)//锁定指定 缓冲区

{
    cli();//关中断

    while (bh->b_lock)//如果上锁

        sleep_on(&bh->b_wait);//睡眼等待该缓冲区解 锁的进程

    bh->b_lock=1;//上锁

    sti();//开中断

}

static inline void unlock_buffer(struct buffer_head * bh)//解锁指定缓冲区

{
    if (!bh->b_lock)//没上锁

        printk("ll_rw_block.c: buffer not locked\n\r");
    bh->b_lock = 0;//解锁

    wake_up(&bh->b_wait);//唤醒等待该缓冲区解 锁的进程

}

/*
 * add-request adds a request to the linked list.
 * It disables interrupts so that it can muck with the
 * request-lists in peace.
 */

static void add_request(struct blk_dev_struct * dev, struct request * req)//向请求项链表中加入一请求项,dev指定块设备结构指针,req请求项

{
    struct request * tmp;

    req->next = NULL;//下一项置空

    cli();//关中断

    if (req->bh)
        req->bh->b_dirt = 0;//修改标志0为未修改,1为修改

    if (!(tmp = dev->current_request)) {//当前设备所指向的当前请求项为空时,也就是当前设备暂时还没有请求项

        dev->current_request = req;//当前请求项指向于req

        sti();//开中断

        (dev->request_fn)();//执行请请求函数,如do_hd_request

        return;
    }
    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;
    sti();//开中断

}

static void make_request(int major,int rw, struct buffer_head * bh)//将请求项插入到请求链表中,major主设备号,rw指定命令,bh存放数据的缓冲区的头指针

{
    struct request * req;//新建请求项

    int rw_ahead;//是否是为提前读或提前写


/* WRITEA/READA is special case - it is not really needed, so if the */
/* buffer is locked, we just forget about it, else it's a normal read */
    if (rw_ahead = (rw == READA || rw == WRITEA)) {//如果是提前读或提前写

        if (bh->b_lock)//指定缓冲区上锁,则返回

            return;
        if (rw == READA)//指定缓冲区没有上锁,则提前读提前写置为普通的读写

            rw = READ;
        else
            rw = WRITE;
    }
    if (rw!=READ && rw!=WRITE)//不为读或写

        panic("Bad block dev command, must be R/W/RA/WA");
    lock_buffer(bh);//锁定指定 缓冲区,以便为缓冲区进行检查

    if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {//体现高速缓冲区的用意,在数据 可靠的情况下(要读取硬盘上的的数据与缓冲区上的数据相同,要写入的数据与缓冲区上的相同 )这一次操作可以返顺回,没有必要增加新 求项,bh->b_dirt修改标志0为未修改,1为修改,, bh->b_uptodate更新标志,缓冲区上的数据是否为块上的数据同步,1为缓冲区上的数据与硬盘上的数据同步一样

        unlock_buffer(bh);//解锁

        return;
    }
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;//请求链表中可以全为读项

    else
        req = request+((NR_REQUEST*2)/3);//但写项只可占用请求链表中的2/3

/* find an empty request */
    while (--req >= request)
        if (req->dev<0)
            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);//否则,由于请求链表满,没有空闲的,所以让本次请求操作先睡眠,将当前任务置为不可中断的等待状态,放入wait_for_request队列中来,进行进程调度,当又轮到本程序执行时执行下面的语句goto repeat;

        goto repeat;
    }
/* fill up the request-info, and add it to the queue *///t向空闲链表填写相关停息

    req->dev = bh->b_dev;//设备号

    req->cmd = rw;//命令

    req->errors=0;//操作的数据次数

    req->sector = bh->b_blocknr<<1;//块号转为扇区(1块=2扇区),起始扇区

    req->nr_sectors = 2;//要读写的扇区数

    req->buffer = bh->b_data;//请求项缓冲区指针,指向需读写的数据缓冲区

    req->waiting = NULL;//等待该请求项的进程,(任务等待操作执行完成的地方)

    req->bh = bh//缓冲区头指针

    req->next = NULL;//指向下一个请求项

    add_request(major+blk_dev,req);
}

void ll_rw_block(int rw, struct buffer_head * bh)//底层读写数据块函数,由fs/buffer.c函数调用 ,主要创建读写设备的请示谋项,并插入到请求链表中去

{
    unsigned int major;

    if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
    !(blk_dev[major].request_fn)) {//如主设备号为非法的,或块设备数组中请求项函数指针为空时,

        printk("Trying to read nonexistent block-device\n\r");
        return;
    }
    make_request(major,rw,bh);//将请求项插入到请求链表中

}

void blk_dev_init(void)//块设备初始化函数main.c line 128 行调用,

{
    int i;

    for (i=0 ; i<NR_REQUEST ; i++) {//初始化请求数组

        request[i].dev = -1;
        request[i].next = NULL;
    }
}

上一篇:blk.h
下一篇:ramdisk.c