?? ll_rw_blk.c
字號:
/* passed* linux/kernel/blk_dev/ll_rw.c** (C) 1991 Linus Torvalds*/#include <set_seg.h>
/** This handles all read/write requests to block devices*//** 該程序處理塊設(shè)備的所有讀/寫操作。*/#include <errno.h> // 錯誤號頭文件。包含系統(tǒng)中各種出錯號。(Linus 從minix 中引進(jìn)的)#include <linux/sched.h> // 調(diào)度程序頭文件,定義了任務(wù)結(jié)構(gòu)task_struct、初始任務(wù)0 的數(shù)據(jù),// 還有一些有關(guān)描述符參數(shù)設(shè)置和獲取的嵌入式匯編函數(shù)宏語句。#include <linux/kernel.h> // 內(nèi)核頭文件。含有一些內(nèi)核常用函數(shù)的原形定義。#include <asm/system.h> // 系統(tǒng)頭文件。定義了設(shè)置或修改描述符/中斷門等的嵌入式匯編宏。#include "blk.h" // 塊設(shè)備頭文件。定義請求數(shù)據(jù)結(jié)構(gòu)、塊設(shè)備數(shù)據(jù)結(jié)構(gòu)和宏函數(shù)等信息。/** The request-struct contains all necessary data* to load a nr of sectors into memory*//** 請求結(jié)構(gòu)中含有加載nr 扇區(qū)數(shù)據(jù)到內(nèi)存的所有必須的信息。*/struct request request[NR_REQUEST] = {0};/** used to wait on when there are no free requests*//* 是用于請求數(shù)組沒有空閑項(xiàng)時的臨時等待處 */struct task_struct *wait_for_request = NULL;/* blk_dev_struct is:* do_request-address* next-request*//* blk_dev_struct 塊設(shè)備結(jié)構(gòu)是:(kernel/blk_drv/blk.h,23)* do_request-address //對應(yīng)主設(shè)備號的請求處理程序指針。* current-request // 該設(shè)備的下一個請求。*/// 該數(shù)組使用主設(shè)備號作為索引(下標(biāo))。struct blk_dev_struct blk_dev[NR_BLK_DEV] = { {NULL, NULL}, /* no_dev */// 0 - 無設(shè)備。 {NULL, NULL}, /* dev mem */// 1 - 內(nèi)存。 {NULL, NULL}, /* dev fd */// 2 - 軟驅(qū)設(shè)備。 {NULL, NULL}, /* dev hd */// 3 - 硬盤設(shè)備。 {NULL, NULL}, /* dev ttyx */// 4 - ttyx 設(shè)備。 {NULL, NULL}, /* dev tty */// 5 - tty 設(shè)備。 {NULL, NULL} /* dev lp */// 6 - lp 打印機(jī)設(shè)備。};// 鎖定指定的緩沖區(qū)bh。如果指定的緩沖區(qū)已經(jīng)被其它任務(wù)鎖定,則使自己睡眠(不可中斷地等待),// 直到被執(zhí)行解鎖緩沖區(qū)的任務(wù)明確地喚醒。static _inline voidlock_buffer (struct buffer_head *bh){ cli (); // 清中斷許可。 while (bh->b_lock) // 如果緩沖區(qū)已被鎖定,則睡眠,直到緩沖區(qū)解鎖。 sleep_on (&bh->b_wait); bh->b_lock = 1; // 立刻鎖定該緩沖區(qū)。 sti (); // 開中斷。}// 釋放(解鎖)鎖定的緩沖區(qū)。static _inline voidunlock_buffer (struct buffer_head *bh){ if (!bh->b_lock) // 如果該緩沖區(qū)并沒有被鎖定,則打印出錯信息。 printk ("ll_rw_block.c: buffer not locked\n\r"); bh->b_lock = 0; // 清鎖定標(biāo)志。 wake_up (&bh->b_wait); // 喚醒等待該緩沖區(qū)的任務(wù)。}/** add-request adds a request to the linked list.* It disables interrupts so that it can muck with the* request-lists in peace.*//** add-request()向連表中加入一項(xiàng)請求。它關(guān)閉中斷,* 這樣就能安全地處理請求連表了 *///// 向鏈表中加入請求項(xiàng)。參數(shù)dev 指定塊設(shè)備,req 是請求的結(jié)構(gòu)信息。 static voidadd_request (struct blk_dev_struct *dev, struct request *req){ struct request *tmp; req->next = NULL; cli (); // 關(guān)中斷。 if (req->bh) req->bh->b_dirt = 0; // 清緩沖區(qū)“臟”標(biāo)志。// 如果dev 的當(dāng)前請求(current_request)子段為空,則表示目前該設(shè)備沒有請求項(xiàng),本次是第1 個// 請求項(xiàng),因此可將塊設(shè)備當(dāng)前請求指針直接指向請求項(xiàng),并立刻執(zhí)行相應(yīng)設(shè)備的請求函數(shù)。 if (!(tmp = dev->current_request)) { dev->current_request = req; sti (); // 開中斷。 (dev->request_fn) (); // 執(zhí)行設(shè)備請求函數(shù),對于硬盤(3)是do_hd_request()。 return; }// 如果目前該設(shè)備已經(jīng)有請求項(xiàng)在等待,則首先利用電梯算法搜索最佳位置,然后將當(dāng)前請求插入// 請求鏈表中。 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 ();}//// 創(chuàng)建請求項(xiàng)并插入請求隊(duì)列。參數(shù)是:主設(shè)備號major,命令rw,存放數(shù)據(jù)的緩沖區(qū)頭指針bh。static voidmake_request (int major, int rw, struct buffer_head *bh){ struct request *req; int rw_ahead;/* WRITEA/READA 是特殊的情況 - 它們并不是必要的,所以如果緩沖區(qū)已經(jīng)上鎖,*//* 我們就不管它而退出,否則的話就執(zhí)行一般的讀/寫操作。 */// 這里'READ'和'WRITE'后面的'A'字符代表英文單詞Ahead,表示提前預(yù)讀/寫數(shù)據(jù)塊的意思。// 當(dāng)指定的緩沖區(qū)正在使用,已被上鎖時,就放棄預(yù)讀/寫請求。 if (rw_ahead = (rw == READA || rw == WRITEA)) { if (bh->b_lock) return; if (rw == READA) rw = READ; else rw = WRITE; }// 如果命令不是READ 或WRITE 則表示內(nèi)核程序有錯,顯示出錯信息并死機(jī)。 if (rw != READ && rw != WRITE) panic ("Bad block dev command, must be R/W/RA/WA");// 鎖定緩沖區(qū),如果緩沖區(qū)已經(jīng)上鎖,則當(dāng)前任務(wù)(進(jìn)程)就會睡眠,直到被明確地喚醒。 lock_buffer (bh);// 如果命令是寫并且緩沖區(qū)數(shù)據(jù)不臟,或者命令是讀并且緩沖區(qū)數(shù)據(jù)是更新過的,則不用添加// 這個請求。將緩沖區(qū)解鎖并退出。 if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { unlock_buffer (bh); return; }repeat:/* 我們不能讓隊(duì)列中全都是寫請求項(xiàng):我們需要為讀請求保留一些空間:讀操作* 是優(yōu)先的。請求隊(duì)列的后三分之一空間是為讀準(zhǔn)備的。*/// 請求項(xiàng)是從請求數(shù)組末尾開始搜索空項(xiàng)填入的。根據(jù)上述要求,對于讀命令請求,可以直接// 從隊(duì)列末尾開始操作,而寫請求則只能從隊(duì)列的2/3 處向頭上搜索空項(xiàng)填入。 if (rw == READ) req = request + NR_REQUEST; // 對于讀請求,將隊(duì)列指針指向隊(duì)列尾部。 else req = request + ((NR_REQUEST * 2) / 3); // 對于寫請求,隊(duì)列指針指向隊(duì)列2/3 處。/* 搜索一個空請求項(xiàng) */// 從后向前搜索,當(dāng)請求結(jié)構(gòu)request 的dev 字段值=-1 時,表示該項(xiàng)未被占用。 while (--req >= request) if (req->dev < 0) break;/* 如果沒有找到空閑項(xiàng),則讓該次新請求睡眠:需檢查是否提前讀/寫 */// 如果沒有一項(xiàng)是空閑的(此時request 數(shù)組指針已經(jīng)搜索越過頭部),則查看此次請求是否是// 提前讀/寫(READA 或WRITEA),如果是則放棄此次請求。否則讓本次請求睡眠(等待請求隊(duì)列// 騰出空項(xiàng)),過一會再來搜索請求隊(duì)列。 if (req < request) { // 如果請求隊(duì)列中沒有空項(xiàng),則 if (rw_ahead) { // 如果是提前讀/寫請求,則解鎖緩沖區(qū),退出。 unlock_buffer (bh); return; } sleep_on (&wait_for_request); // 否則讓本次請求睡眠,過會再查看請求隊(duì)列。 goto repeat; }/* 向空閑請求項(xiàng)中填寫請求信息,并將其加入隊(duì)列中 */// 請求結(jié)構(gòu)參見(kernel/blk_drv/blk.h,23)。 req->dev = bh->b_dev; // 設(shè)備號。 req->cmd = rw; // 命令(READ/WRITE)。 req->errors = 0; // 操作時產(chǎn)生的錯誤次數(shù)。 req->sector = bh->b_blocknr << 1; // 起始扇區(qū)。(1 塊=2 扇區(qū)) req->nr_sectors = 2; // 讀寫扇區(qū)數(shù)。 req->buffer = bh->b_data; // 數(shù)據(jù)緩沖區(qū)。 req->waiting = NULL; // 任務(wù)等待操作執(zhí)行完成的地方。 req->bh = bh; // 緩沖區(qū)頭指針。 req->next = NULL; // 指向下一請求項(xiàng)。 add_request (major + blk_dev, req); // 將請求項(xiàng)加入隊(duì)列中(blk_dev[major],req)。}//// 低層讀寫數(shù)據(jù)塊函數(shù)。// 該函數(shù)主要是在fs/buffer.c 中被調(diào)用。實(shí)際的讀寫操作是由設(shè)備的request_fn()函數(shù)完成。// 對于硬盤操作,該函數(shù)是do_hd_request()。(kernel/blk_drv/hd.c,294)void ll_rw_block (int rw, struct buffer_head *bh){ unsigned int major; // 主設(shè)備號(對于硬盤是3)。// 如果設(shè)備的主設(shè)備號不存在或者該設(shè)備的讀寫操作函數(shù)不存在,則顯示出錯信息,并返回。 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); // 創(chuàng)建請求項(xiàng)并插入請求隊(duì)列。}//// 塊設(shè)備初始化函數(shù),由初始化程序main.c 調(diào)用(init/main.c,128)。// 初始化請求數(shù)組,將所有請求項(xiàng)置為空閑項(xiàng)(dev = -1)。有32 項(xiàng)(NR_REQUEST = 32)。void blk_dev_init (void){ int i; for (i = 0; i < NR_REQUEST; i++) { request[i].dev = -1; request[i].next = NULL; }}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -