當核心想快裝置發出一個讀寫請求或其他請求時,ll_rw_block就會根據其參數指明的操作命令和資料緩衝塊頭中的裝置號,利用對應請求項的操作函數do_xx_request建立一個塊裝置請求項,並利用電梯演算法將新產生的請求項插入請求項隊列中。
1.
struct request {
int dev; /* -1 if no request */
int cmd; /* READ or WRITE */
int errors;
unsigned long sector;
unsigned long nr_sectors;
char * buffer;
struct task_struct * waiting;
struct buffer_head * bh;
struct request * next;
};
struct request request[NR_REQUEST];
2.
struct blk_dev_struct{
(void *)(request_fn)();
struct request *current_request;
}
struct blk_dev_struct blk_dev[NR_BLK];
每個塊裝置中當前請求項與請求項數組中該裝置的請求項鏈表共同構成了當前塊裝置的請求隊列。
對於一個當前閒置塊裝置,當ll_rw_block為其建立第一個請求項時,會讓當前請求項指標指向剛剛建立的請求項,並立刻調用當前塊裝置的請求項操作函數進行讀寫操作。
3.
在end_request()中有:
#define CURRENT(blk_dev[MAJOR_NR]->currnt_request)
#define CURRENT_DEV DEVICE_NR(CURRENT->DEV)
wake_up(&CURRENT->waiting);
wake_up(&wait_for_request);
第1句是把等待該項裝置的進程喚醒,第2句中的wait_for_request是指什麼呢?
趙博在extern struct task_struct * wait_for_request; 說是等待請求的任務結構。在進行塊裝置的I/O操作時,需要使用請求項
struct request request[NR_REAUEST];
因此請求項本身就是一種資源,所以第二句的意識是喚醒那些等待有空閑請求可用的進程等待隊列。
CURRENT->waiting是當前請求項的進程隊列,wait_for_rquest是等待可用請求項的進程等待隊列
對於寫請求,請求項指標會指向請求項數組中的2/3處。
1.讀寫硬碟出錯時的處理
首先會調用bad_wr_intr函數,該函數會判斷失敗次數是否大於規定的錯誤最大值,如果是則結束當前請求向並喚醒等待該請求向的進程,並且置位對應緩衝區的標誌位,表示緩衝區沒有得到更新。如果出錯的次數大於最大出錯值的一半時,則要求置位硬碟控制器。
static void bad_wr_intr(void)
{
if(++CURRENT->error >= MAX_ERRORS)
end_request(0);
if(CURRENT->error > MAX_ERRORS/2)
reset = 1;
}
//reset時複位標誌,當讀寫硬碟發生錯誤時會設定這個標誌,並調用相關的複位函數來複位硬碟控制器和硬碟
static int reset = 1;
複位硬碟控制器函數
static int reset_controller(void)
{
unsigned int i;
oub_p(4,HD_CMD); //向控制器發送複位位元組
for(i = 0;i<100;i++) {}; //等待一會
oub_p((hd_info[0].ctl&0x0f), HD_CMD): //發送正常的控制位元組,其中hd_info[0]的資訊是通過BIOS傳進來的在初始化硬碟資訊的時候對各個硬碟資訊數組進行初始化
if(device_busy) //等待硬碟就緒,否則提示錯誤資訊
printk(" hd controller still busy/n");
if((i = inb_p(HD_ERR))!=1)
printk("hd controller reset failed!/n");
}
複位硬碟
static void reset_hd(int nr)
{
reset_controller();
hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1,
hd_info[nr].cyl,WIN_SPECIFY,&recal_intr);
}
WIN_SPECIFY表示建立硬碟驅動參數,recal_intr是在硬碟中斷處理函數中調用的重新校正處理函數