/*
* 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 */
};
/*
* blk_size contains the size of all block-devices:
*
* blk_size[MAJOR][MINOR]
*
* if (!blk_size[MAJOR]) then no minor size checking is done.
*/
int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
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.
*
* Note that swapping requests always go before other requests,
* and are done in the order they appear.
*/
static void add_request(struct blk_dev_struct * dev, struct request * req)
{ //--向链表中加入请求项
struct request * tmp;
req->next = NULL;
cli();
if (req->bh)
req->bh->b_dirt = 0;
if (!(tmp = dev->current_request)) { //--检查设备是否正忙
dev->current_request = req; //--若目前该设备没有请求项,本次是唯一一个请求
sti(); //--则将块设备当前请求指针直接指向该请求项
(dev->request_fn)();
return;
}
for ( ; tmp->next ; tmp=tmp->next) { //--设备已经有当前请求项在处理
if (!req->bh)
if (tmp->next->bh)
break;
else
continue;
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)
{ //--创建请求项,并插入请求队列中
struct request * req; //--major主设备号/rw指定命令/bh数据的缓冲区头指针
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)) {
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);
/* 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);
goto repeat;
}
/* fill up the request-info, and add it to the queue */
req->dev = bh->b_dev; //--填写信息,并加入队列
req->cmd = rw;
req->errors=0;
req->sector = bh->b_blocknr<<1;
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_page(int rw, int dev, int page, char * buffer)
{ //--低级页面读写操作,与make_request类似
struct request * req; //--以页面(4K)为单位访问块设备数据,即每次读/写8个扇区
unsigned int major = MAJOR(dev);
if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
printk("Trying to read nonexistent block-device/n/r");
return;
}
if (rw!=READ && rw!=WRITE)
panic("Bad block dev command, must be R/W");
repeat:
req = request+NR_REQUEST;
while (--req >= request)
if (req->dev<0)
break;
if (req < request) {
sleep_on(&wait_for_request);
goto repeat;
}
/* fill up the request-info, and add it to the queue */
req->dev = dev;
req->cmd = rw;
req->errors = 0;
req->sector = page<<3;
req->nr_sectors = 8;
req->buffer = buffer;
req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
add_request(major+blk_dev,req);
schedule();
}
void ll_rw_block(int rw, struct buffer_head * bh) //--低级数据块读写操作
{ //--块设备驱动程序与系统其它部分的接口函数
unsigned int major;
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
!(blk_dev[major].request_fn)) { //--操作函数:do_hd_request,do_fd_request,do_rd_requset.
printk("Trying to read nonexistent block-device/n/r");
return;
}
make_request(major,rw,bh);
}
void blk_dev_init(void) //--块设备初始化程序,main.c中调用
{
int i;
for (i=0 ; i<NR_REQUEST ; i++) {
request[i].dev = -1;
request[i].next = NULL;
}
}
|xGv00|fcc8d4de8197f69fde70263fb4d52380