ll_re_block()函數:核心塊裝置讀寫都是通過該函數申請請求項來完成的。該函數首先建立請求項,並插入到指定塊裝置的請求隊列中,實際的讀寫操作則是用請求項函數request_fn()來完成的--對與硬碟來說是do_hd_request().該函數建立的請求項後,首先會檢查對應的請求項隊列是否為空白,如果為空白則設定該請求項為當前請求項,否則利用電梯演算法將該請求項加入請求項隊列。由於每個do_hd_request()在結束每個請求項處理後,都會通過終端回呼函數(read_intr和write_intr)來再次調用do_hd_request()來處理請求項隊列中的其他請求項。直到請求項隊列為空白為止,當請求項為空白時停止發送請求(通過INIT_REQUEST宏來實現)。
這裡將ll_re_block(),read_intr和write_intr三者的實現與調用關係分析如下:
void do_hd_request(void)
{
//定義硬碟用到的一些參數
int i,r;
unsigned int block,dev;
unsigned int sec,head,cyl;
unsigned int nsect;
//goto語句定義的宏,用來檢查請求項隊列是否為空白
INIT_REQUEST;
//初始化硬碟參數,並做相應檢查
dev = MINOR(CURRENT->dev);
block = CURRENT->sector;
if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
end_request(0);
goto repeat;
}
block += hd[dev].start_sect;
dev /= 5;
__asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
"r" (hd_info[dev].sect));
__asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
"r" (hd_info[dev].head));
sec++;
nsect = CURRENT->nr_sectors;
//檢查之前是否設定了一些複位參數
if (reset) {
reset = 0;
recalibrate = 1;
reset_hd(CURRENT_DEV);
return;
}
if (recalibrate) {
recalibrate = 0;
hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
WIN_RESTORE,&recal_intr);
return;
}
//這裡開始處理請求項,是讀還是寫發送相應命令,並設定相應的回呼函數
if (CURRENT->cmd == WRITE) {
//如果是讀則發送讀命令,並設定中斷回呼函數為write_intr
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
//迴圈檢查硬碟狀態,如果就緒則發送資料,這裡發送出資料以後,do_hd_request()函數就已經推出了,至於資料用沒有發送玩是在回呼函數write_intr中判斷執行的,在write_intr函數中如果將所有資料都發送晚,則會調用end_request(1)和do_hd_request()。其中end_request(1)完成該請求項的善後工作,do_hd_request()用來處理請求項中的下一個請求項,這樣迴圈起來知道隊列為空白為止。
for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
/* nothing */ ;
if (!r) {
bad_rw_intr();
goto repeat;
}
port_write(HD_DATA,CURRENT->buffer,256);
} else if (CURRENT->cmd == READ) {
//這裡對寫操作進行處理,處理過程類似於寫。
hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
} else
panic("unknown hd-command");
}
request_fn()是請求項處理的發起者,但其在發送命令和設定好回呼函數以後就退出了,後續工作都是通過回呼函數進行的。
static void write_intr(void)
{
if (win_result()) {
bad_rw_intr();
//檢測操作結果,如果失敗則再次調用do_hd_request()來對當前請求項進行處理
do_hd_request();
return;
}
//這裡表示do_hd_request()發送命令成功,並且硬碟控制器已經準備後發出了中斷,開始傳輸資料(沒有發送晚繼續發)。
if (--CURRENT->nr_sectors) {
CURRENT->sector++;
CURRENT->buffer += 512;
do_hd = &write_intr;
port_write(HD_DATA,CURRENT->buffer,256);
return;
}
//這裡表示當前請求項的操作完畢,資料轉送完畢,則結束當前請求項處理,調用do_hd_request()開始請求項隊列的下一個請求。
end_request(1);
do_hd_request();
}
static void read_intr(void)
{
if (win_result()) {
bad_rw_intr();
do_hd_request();
return;
}
port_read(HD_DATA,CURRENT->buffer,256);
CURRENT->errors = 0;
CURRENT->buffer += 512;
CURRENT->sector++;
if (--CURRENT->nr_sectors) {
do_hd = &read_intr;
return;
}
end_request(1);
do_hd_request();
}讀的過程類似